diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/Parser.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/Parser.cpp | 328 |
1 files changed, 209 insertions, 119 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/Parser.cpp b/contrib/llvm-project/clang/lib/Parse/Parser.cpp index ffa1e0f027f1..6f63d01bc8ad 100644 --- a/contrib/llvm-project/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm-project/clang/lib/Parse/Parser.cpp @@ -581,15 +581,20 @@ void Parser::DestroyTemplateIds() { /// top-level-declaration-seq[opt] private-module-fragment[opt] /// /// Note that in C, it is an error if there is no first declaration. -bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { +bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result, + Sema::ModuleImportState &ImportState) { Actions.ActOnStartOfTranslationUnit(); + // For C++20 modules, a module decl must be the first in the TU. We also + // need to track module imports. + ImportState = Sema::ModuleImportState::FirstDecl; + bool NoTopLevelDecls = ParseTopLevelDecl(Result, ImportState); + // C11 6.9p1 says translation units must have at least one top-level // declaration. C++ doesn't have this restriction. We also don't want to // complain if we have a precompiled header, although technically if the PCH // is empty we should still emit the (pedantic) diagnostic. // If the main file is a header, we're only pretending it's a TU; don't warn. - bool NoTopLevelDecls = ParseTopLevelDecl(Result, true); if (NoTopLevelDecls && !Actions.getASTContext().getExternalSource() && !getLangOpts().CPlusPlus && !getLangOpts().IsHeaderFile) Diag(diag::ext_empty_translation_unit); @@ -603,7 +608,8 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { /// top-level-declaration: /// declaration /// [C++20] module-import-declaration -bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) { +bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, + Sema::ModuleImportState &ImportState) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this); // Skip over the EOF token, flagging end of previous input for incremental @@ -647,13 +653,12 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) { case tok::kw_module: module_decl: - Result = ParseModuleDecl(IsFirstDecl); + Result = ParseModuleDecl(ImportState); return false; - // tok::kw_import is handled by ParseExternalDeclaration. (Under the Modules - // TS, an import can occur within an export block.) + case tok::kw_import: import_decl: { - Decl *ImportDecl = ParseModuleImport(SourceLocation()); + Decl *ImportDecl = ParseModuleImport(SourceLocation(), ImportState); Result = Actions.ConvertDeclToDeclGroup(ImportDecl); return false; } @@ -669,12 +674,14 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) { Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>( Tok.getAnnotationValue())); ConsumeAnnotationToken(); + ImportState = Sema::ModuleImportState::NotACXX20Module; return false; case tok::annot_module_end: Actions.ActOnModuleEnd(Tok.getLocation(), reinterpret_cast<Module *>( Tok.getAnnotationValue())); ConsumeAnnotationToken(); + ImportState = Sema::ModuleImportState::NotACXX20Module; return false; case tok::eof: @@ -714,15 +721,28 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) { break; } - ParsedAttributesWithRange attrs(AttrFactory); + ParsedAttributes attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); Result = ParseExternalDeclaration(attrs); + // An empty Result might mean a line with ';' or some parsing error, ignore + // it. + if (Result) { + if (ImportState == Sema::ModuleImportState::FirstDecl) + // First decl was not modular. + ImportState = Sema::ModuleImportState::NotACXX20Module; + else if (ImportState == Sema::ModuleImportState::ImportAllowed) + // Non-imports disallow further imports. + ImportState = Sema::ModuleImportState::ImportFinished; + } return false; } /// ParseExternalDeclaration: /// +/// The `Attrs` that are passed in are C++11 attributes and appertain to the +/// declaration. +/// /// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl] /// function-definition /// declaration @@ -747,9 +767,8 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) { /// /// [Modules-TS] module-import-declaration /// -Parser::DeclGroupPtrTy -Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, - ParsingDeclSpec *DS) { +Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, + ParsingDeclSpec *DS) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -803,7 +822,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::annot_attr_openmp: case tok::annot_pragma_openmp: { AccessSpecifier AS = AS_none; - return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs); + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs); } case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); @@ -823,7 +842,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::semi: // Either a C++11 empty-declaration or attribute-declaration. SingleDecl = - Actions.ActOnEmptyDeclaration(getCurScope(), attrs, Tok.getLocation()); + Actions.ActOnEmptyDeclaration(getCurScope(), Attrs, Tok.getLocation()); ConsumeExtraSemi(OutsideFunction); break; case tok::r_brace: @@ -837,10 +856,10 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseExternalDeclaration(attrs); + return ParseExternalDeclaration(Attrs); } case tok::kw_asm: { - ProhibitAttributes(attrs); + ProhibitAttributes(Attrs); SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; @@ -865,7 +884,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, break; } case tok::at: - return ParseObjCAtDirectives(attrs); + return ParseObjCAtDirectives(Attrs); case tok::minus: case tok::plus: if (!getLangOpts().ObjC) { @@ -887,11 +906,17 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, getCurScope(), CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); return nullptr; - case tok::kw_import: - SingleDecl = ParseModuleImport(SourceLocation()); - break; + case tok::kw_import: { + Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module; + if (getLangOpts().CPlusPlusModules) { + llvm_unreachable("not expecting a c++20 import here"); + ProhibitAttributes(Attrs); + } + SingleDecl = ParseModuleImport(SourceLocation(), IS); + } break; case tok::kw_export: if (getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS) { + ProhibitAttributes(Attrs); SingleDecl = ParseExportDeclaration(); break; } @@ -907,7 +932,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, // A function definition cannot start with any of these keywords. { SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); } case tok::kw_static: @@ -917,7 +944,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 0; SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); } goto dont_know; @@ -928,7 +957,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, // Inline namespaces. Allowed as an extension even in C++03. if (NextKind == tok::kw_namespace) { SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); } // Parse (then ignore) 'inline' prior to a template instantiation. This is @@ -937,7 +968,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 1; SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); } } goto dont_know; @@ -952,7 +985,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc); SourceLocation DeclEnd; return Actions.ConvertDeclToDeclGroup(ParseExplicitInstantiation( - DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd, attrs)); + DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd, Attrs)); } goto dont_know; @@ -973,7 +1006,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, return nullptr; } // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(attrs, DS); + return ParseDeclarationOrFunctionDefinition(Attrs, DS); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -1037,10 +1070,8 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { /// [OMP] threadprivate-directive /// [OMP] allocate-directive [TODO] /// -Parser::DeclGroupPtrTy -Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, - ParsingDeclSpec &DS, - AccessSpecifier AS) { +Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal( + ParsedAttributes &Attrs, ParsingDeclSpec &DS, AccessSpecifier AS) { MaybeParseMicrosoftAttributes(DS.getAttributes()); // Parse the common declaration-specifiers piece. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, @@ -1079,11 +1110,11 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, ? DS.getTypeSpecTypeLoc().getLocWithOffset( LengthOfTSTToken(DS.getTypeSpecType())) : SourceLocation(); - ProhibitAttributes(attrs, CorrectLocationForAttributes); + ProhibitAttributes(Attrs, CorrectLocationForAttributes); ConsumeToken(); RecordDecl *AnonRecord = nullptr; - Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, - DS, AnonRecord); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( + getCurScope(), AS_none, DS, ParsedAttributesView::none(), AnonRecord); DS.complete(TheDecl); if (AnonRecord) { Decl* decls[] = {AnonRecord, TheDecl}; @@ -1092,8 +1123,6 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, return Actions.ConvertDeclToDeclGroup(TheDecl); } - DS.takeAttributesFrom(attrs); - // ObjC2 allows prefix attributes on class interfaces and protocols. // FIXME: This still needs better diagnostics. We should only accept // attributes here, no types, etc. @@ -1108,6 +1137,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, } DS.abort(); + DS.takeAttributesFrom(Attrs); const char *PrevSpec = nullptr; unsigned DiagID; @@ -1131,19 +1161,18 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, if (getLangOpts().CPlusPlus && isTokenStringLiteral() && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { + ProhibitAttributes(Attrs); Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File); return Actions.ConvertDeclToDeclGroup(TheDecl); } - return ParseDeclGroup(DS, DeclaratorContext::File); + return ParseDeclGroup(DS, DeclaratorContext::File, Attrs); } -Parser::DeclGroupPtrTy -Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs, - ParsingDeclSpec *DS, - AccessSpecifier AS) { +Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition( + ParsedAttributes &Attrs, ParsingDeclSpec *DS, AccessSpecifier AS) { if (DS) { - return ParseDeclOrFunctionDefInternal(attrs, *DS, AS); + return ParseDeclOrFunctionDefInternal(Attrs, *DS, AS); } else { ParsingDeclSpec PDS(*this); // Must temporarily exit the objective-c container scope for @@ -1151,7 +1180,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs, // afterwards. ObjCDeclContextSwitch ObjCDC(*this); - return ParseDeclOrFunctionDefInternal(attrs, PDS, AS); + return ParseDeclOrFunctionDefInternal(Attrs, PDS, AS); } } @@ -1177,10 +1206,12 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - // If this is C90 and the declspecs were completely missing, fudge in an + // If this is C89 and the declspecs were completely missing, fudge in an // implicit int. We do this here because this is the only place where // declaration-specifiers are completely optional in the grammar. - if (getLangOpts().ImplicitInt && D.getDeclSpec().isEmpty()) { + if (getLangOpts().isImplicitIntRequired() && D.getDeclSpec().isEmpty()) { + Diag(D.getIdentifierLoc(), diag::warn_missing_type_specifier) + << D.getDeclSpec().getSourceRange(); const char *PrevSpec; unsigned DiagID; const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); @@ -1281,6 +1312,41 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope); + // Parse function body eagerly if it is either '= delete;' or '= default;' as + // ActOnStartOfFunctionDef needs to know whether the function is deleted. + Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other; + SourceLocation KWLoc; + if (TryConsumeToken(tok::equal)) { + assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); + + if (TryConsumeToken(tok::kw_delete, KWLoc)) { + Diag(KWLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_defaulted_deleted_function + : diag::ext_defaulted_deleted_function) + << 1 /* deleted */; + BodyKind = Sema::FnBodyKind::Delete; + } else if (TryConsumeToken(tok::kw_default, KWLoc)) { + Diag(KWLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_defaulted_deleted_function + : diag::ext_defaulted_deleted_function) + << 0 /* defaulted */; + BodyKind = Sema::FnBodyKind::Default; + } else { + llvm_unreachable("function definition after = not 'delete' or 'default'"); + } + + if (Tok.is(tok::comma)) { + Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) + << (BodyKind == Sema::FnBodyKind::Delete); + SkipUntil(tok::semi); + } else if (ExpectAndConsume(tok::semi, diag::err_expected_after, + BodyKind == Sema::FnBodyKind::Delete + ? "delete" + : "default")) { + SkipUntil(tok::semi); + } + } + // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. Sema::SkipBodyInfo SkipBody; @@ -1288,10 +1354,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams : MultiTemplateParamsArg(), - &SkipBody); + &SkipBody, BodyKind); if (SkipBody.ShouldSkip) { - SkipFunctionBody(); + // Do NOT enter SkipFunctionBody if we already consumed the tokens. + if (BodyKind == Sema::FnBodyKind::Other) + SkipFunctionBody(); + return Res; } @@ -1302,6 +1371,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // safe because we're always the sole owner. D.getMutableDeclSpec().abort(); + if (BodyKind != Sema::FnBodyKind::Other) { + Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind); + Stmt *GeneratedBody = Res ? Res->getBody() : nullptr; + Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false); + return Res; + } + // With abbreviated function templates - we need to explicitly add depth to // account for the implicit template parameter list induced by the template. if (auto *Template = dyn_cast_or_null<FunctionTemplateDecl>(Res)) @@ -1311,42 +1387,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // parameter list was specified. CurTemplateDepthTracker.addDepth(1); - if (TryConsumeToken(tok::equal)) { - assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='"); - - bool Delete = false; - SourceLocation KWLoc; - if (TryConsumeToken(tok::kw_delete, KWLoc)) { - Diag(KWLoc, getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_defaulted_deleted_function - : diag::ext_defaulted_deleted_function) - << 1 /* deleted */; - Actions.SetDeclDeleted(Res, KWLoc); - Delete = true; - } else if (TryConsumeToken(tok::kw_default, KWLoc)) { - Diag(KWLoc, getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_defaulted_deleted_function - : diag::ext_defaulted_deleted_function) - << 0 /* defaulted */; - Actions.SetDeclDefaulted(Res, KWLoc); - } else { - llvm_unreachable("function definition after = not 'delete' or 'default'"); - } - - if (Tok.is(tok::comma)) { - Diag(KWLoc, diag::err_default_delete_in_multiple_declaration) - << Delete; - SkipUntil(tok::semi); - } else if (ExpectAndConsume(tok::semi, diag::err_expected_after, - Delete ? "delete" : "default")) { - SkipUntil(tok::semi); - } - - Stmt *GeneratedBody = Res ? Res->getBody() : nullptr; - Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false); - return Res; - } - if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) && trySkippingFunctionBody()) { BodyScope.Exit(); @@ -1444,7 +1484,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { } // Parse the first declarator attached to this declspec. - Declarator ParmDeclarator(DS, DeclaratorContext::KNRTypeList); + Declarator ParmDeclarator(DS, ParsedAttributesView::none(), + DeclaratorContext::KNRTypeList); ParseDeclarator(ParmDeclarator); // Handle the full declarator list. @@ -1533,7 +1574,7 @@ ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { ExprResult AsmString(ParseStringLiteralExpression()); if (!AsmString.isInvalid()) { const auto *SL = cast<StringLiteral>(AsmString.get()); - if (!SL->isAscii()) { + if (!SL->isOrdinary()) { Diag(Tok, diag::err_asm_operand_wide_string_literal) << SL->isWide() << SL->getSourceRange(); @@ -2127,14 +2168,14 @@ SourceLocation Parser::handleUnexpectedCodeCompletionToken() { PrevTokLocation = Tok.getLocation(); for (Scope *S = getCurScope(); S; S = S->getParent()) { - if (S->getFlags() & Scope::FnScope) { + if (S->isFunctionScope()) { cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_RecoveryInFunction); return PrevTokLocation; } - if (S->getFlags() & Scope::ClassScope) { + if (S->isClassScope()) { cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class); return PrevTokLocation; @@ -2269,9 +2310,9 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { // Parse the declarations. // FIXME: Support module import within __if_exists? while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); - DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); + ParsedAttributes Attrs(AttrFactory); + MaybeParseCXX11Attributes(Attrs); + DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs); if (Result && !getCurScope()->getParent()) Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); } @@ -2291,7 +2332,8 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { /// attribute-specifier-seq[opt] ';' /// private-module-fragment: [C++2a] /// 'module' ':' 'private' ';' top-level-declaration-seq[opt] -Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) { +Parser::DeclGroupPtrTy +Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { SourceLocation StartLoc = Tok.getLocation(); Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export) @@ -2311,7 +2353,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) { // Parse a global-module-fragment, if present. if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) { SourceLocation SemiLoc = ConsumeToken(); - if (!IsFirstDecl) { + if (ImportState != Sema::ModuleImportState::FirstDecl) { Diag(StartLoc, diag::err_global_module_introducer_not_at_start) << SourceRange(StartLoc, SemiLoc); return nullptr; @@ -2320,6 +2362,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) { Diag(StartLoc, diag::err_module_fragment_exported) << /*global*/0 << FixItHint::CreateRemoval(StartLoc); } + ImportState = Sema::ModuleImportState::GlobalFragment; return Actions.ActOnGlobalModuleFragmentDecl(ModuleLoc); } @@ -2334,52 +2377,56 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) { SourceLocation PrivateLoc = ConsumeToken(); DiagnoseAndSkipCXX11Attributes(); ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi); + ImportState = Sema::ModuleImportState::PrivateFragment; return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc); } SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; - if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false)) + if (ParseModuleName(ModuleLoc, Path, /*IsImport*/ false)) return nullptr; // Parse the optional module-partition. + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition; if (Tok.is(tok::colon)) { SourceLocation ColonLoc = ConsumeToken(); - SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition; - if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/false)) + if (!getLangOpts().CPlusPlusModules) + Diag(ColonLoc, diag::err_unsupported_module_partition) + << SourceRange(ColonLoc, Partition.back().second); + // Recover by ignoring the partition name. + else if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/ false)) return nullptr; - - // FIXME: Support module partition declarations. - Diag(ColonLoc, diag::err_unsupported_module_partition) - << SourceRange(ColonLoc, Partition.back().second); - // Recover by parsing as a non-partition. } // We don't support any module attributes yet; just parse them and diagnose. - ParsedAttributesWithRange Attrs(AttrFactory); + ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr); + ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr, + /*DiagnoseEmptyAttrs=*/false, + /*WarnOnUnknownAttrs=*/true); ExpectAndConsumeSemi(diag::err_module_expected_semi); - return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, IsFirstDecl); + return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, Partition, + ImportState); } /// Parse a module import declaration. This is essentially the same for -/// Objective-C and the C++ Modules TS, except for the leading '@' (in ObjC) -/// and the trailing optional attributes (in C++). +/// Objective-C and C++20 except for the leading '@' (in ObjC) and the +/// trailing optional attributes (in C++). /// /// [ObjC] @import declaration: /// '@' 'import' module-name ';' /// [ModTS] module-import-declaration: /// 'import' module-name attribute-specifier-seq[opt] ';' -/// [C++2a] module-import-declaration: +/// [C++20] module-import-declaration: /// 'export'[opt] 'import' module-name /// attribute-specifier-seq[opt] ';' /// 'export'[opt] 'import' module-partition /// attribute-specifier-seq[opt] ';' /// 'export'[opt] 'import' header-name /// attribute-specifier-seq[opt] ';' -Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { +Decl *Parser::ParseModuleImport(SourceLocation AtLoc, + Sema::ModuleImportState &ImportState) { SourceLocation StartLoc = AtLoc.isInvalid() ? Tok.getLocation() : AtLoc; SourceLocation ExportLoc; @@ -2391,9 +2438,10 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { bool IsObjCAtImport = Tok.isObjCAtKeyword(tok::objc_import); SourceLocation ImportLoc = ConsumeToken(); + // For C++20 modules, we can have "name" or ":Partition name" as valid input. SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; + bool IsPartition = false; Module *HeaderUnit = nullptr; - if (Tok.is(tok::header_name)) { // This is a header import that the preprocessor decided we should skip // because it was malformed in some way. Parse and ignore it; it's already @@ -2403,24 +2451,27 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { // This is a header import that the preprocessor mapped to a module import. HeaderUnit = reinterpret_cast<Module *>(Tok.getAnnotationValue()); ConsumeAnnotationToken(); - } else if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon)) { + } else if (Tok.is(tok::colon)) { SourceLocation ColonLoc = ConsumeToken(); - if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + if (!getLangOpts().CPlusPlusModules) + Diag(ColonLoc, diag::err_unsupported_module_partition) + << SourceRange(ColonLoc, Path.back().second); + // Recover by leaving partition empty. + else if (ParseModuleName(ColonLoc, Path, /*IsImport*/ true)) return nullptr; - - // FIXME: Support module partition import. - Diag(ColonLoc, diag::err_unsupported_module_partition) - << SourceRange(ColonLoc, Path.back().second); - return nullptr; + else + IsPartition = true; } else { - if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + if (ParseModuleName(ImportLoc, Path, /*IsImport*/ true)) return nullptr; } - ParsedAttributesWithRange Attrs(AttrFactory); + ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); // We don't support any module import attributes yet. - ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr); + ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr, + /*DiagnoseEmptyAttrs=*/false, + /*WarnOnUnknownAttrs=*/true); if (PP.hadModuleLoaderFatalFailure()) { // With a fatal failure in the module loader, we abort parsing. @@ -2428,12 +2479,51 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { return nullptr; } + // Diagnose mis-imports. + bool SeenError = true; + switch (ImportState) { + case Sema::ModuleImportState::ImportAllowed: + SeenError = false; + break; + case Sema::ModuleImportState::FirstDecl: + case Sema::ModuleImportState::NotACXX20Module: + // We can only import a partition within a module purview. + if (IsPartition) + Diag(ImportLoc, diag::err_partition_import_outside_module); + else + SeenError = false; + break; + case Sema::ModuleImportState::GlobalFragment: + // We can only have pre-processor directives in the global module + // fragment. We cannot import a named modules here, however we have a + // header unit import. + if (!HeaderUnit || HeaderUnit->Kind != Module::ModuleKind::ModuleHeaderUnit) + Diag(ImportLoc, diag::err_import_in_wrong_fragment) << IsPartition << 0; + else + SeenError = false; + break; + case Sema::ModuleImportState::ImportFinished: + if (getLangOpts().CPlusPlusModules) + Diag(ImportLoc, diag::err_import_not_allowed_here); + else + SeenError = false; + break; + case Sema::ModuleImportState::PrivateFragment: + Diag(ImportLoc, diag::err_import_in_wrong_fragment) << IsPartition << 1; + break; + } + if (SeenError) { + ExpectAndConsumeSemi(diag::err_module_expected_semi); + return nullptr; + } + DeclResult Import; if (HeaderUnit) Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, HeaderUnit); else if (!Path.empty()) - Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path); + Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path, + IsPartition); ExpectAndConsumeSemi(diag::err_module_expected_semi); if (Import.isInvalid()) return nullptr; @@ -2442,8 +2532,8 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { // the header is parseable. Emit a warning to make the user aware. if (IsObjCAtImport && AtLoc.isValid()) { auto &SrcMgr = PP.getSourceManager(); - auto *FE = SrcMgr.getFileEntryForID(SrcMgr.getFileID(AtLoc)); - if (FE && llvm::sys::path::parent_path(FE->getDir()->getName()) + auto FE = SrcMgr.getFileEntryRefForID(SrcMgr.getFileID(AtLoc)); + if (FE && llvm::sys::path::parent_path(FE->getDir().getName()) .endswith(".framework")) Diags.Report(AtLoc, diag::warn_atimport_in_framework_header); } |