Mercurial > hg > CbC > CbC_llvm
diff clang/lib/Parse/Parser.cpp @ 236:c4bab56944e8 llvm-original
LLVM 16
author | kono |
---|---|
date | Wed, 09 Nov 2022 17:45:10 +0900 |
parents | 5f17cb93ff66 |
children | 173fe712db74 1f2b6ac9f198 |
line wrap: on
line diff
--- a/clang/lib/Parse/Parser.cpp Wed Jul 21 10:27:27 2021 +0900 +++ b/clang/lib/Parse/Parser.cpp Wed Nov 09 17:45:10 2022 +0900 @@ -153,7 +153,7 @@ return true; } -bool Parser::ExpectAndConsumeSemi(unsigned DiagID) { +bool Parser::ExpectAndConsumeSemi(unsigned DiagID, StringRef TokenUsed) { if (TryConsumeToken(tok::semi)) return false; @@ -172,7 +172,7 @@ return false; } - return ExpectAndConsume(tok::semi, DiagID); + return ExpectAndConsume(tok::semi, DiagID , TokenUsed); } void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) { @@ -279,7 +279,7 @@ // We always want this function to skip at least one token if the first token // isn't T and if not at EOF. bool isFirstTokenSkipped = true; - while (1) { + while (true) { // If we found one of the tokens, stop and return true. for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) { if (Tok.is(Toks[i])) { @@ -386,7 +386,7 @@ case tok::semi: if (HasFlagsSet(Flags, StopAtSemi)) return false; - LLVM_FALLTHROUGH; + [[fallthrough]]; default: // Skip this token. ConsumeAnyToken(); @@ -581,15 +581,20 @@ /// 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 @@ /// 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,34 +653,45 @@ 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; } - case tok::annot_module_include: - Actions.ActOnModuleInclude(Tok.getLocation(), - reinterpret_cast<Module *>( - Tok.getAnnotationValue())); + case tok::annot_module_include: { + auto Loc = Tok.getLocation(); + Module *Mod = reinterpret_cast<Module *>(Tok.getAnnotationValue()); + // FIXME: We need a better way to disambiguate C++ clang modules and + // standard C++ modules. + if (!getLangOpts().CPlusPlusModules || !Mod->isHeaderUnit()) + Actions.ActOnModuleInclude(Loc, Mod); + else { + DeclResult Import = + Actions.ActOnModuleImport(Loc, SourceLocation(), Loc, Mod); + Decl *ImportDecl = Import.isInvalid() ? nullptr : Import.get(); + Result = Actions.ConvertDeclToDeclGroup(ImportDecl); + } ConsumeAnnotationToken(); return false; + } case tok::annot_module_begin: 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 +731,28 @@ 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 +777,8 @@ /// /// [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); @@ -785,6 +814,7 @@ HandlePragmaFPContract(); return nullptr; case tok::annot_pragma_fenv_access: + case tok::annot_pragma_fenv_access_ms: HandlePragmaFEnvAccess(); return nullptr; case tok::annot_pragma_fenv_round: @@ -802,7 +832,7 @@ 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(); @@ -822,7 +852,7 @@ 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: @@ -836,10 +866,10 @@ // __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; @@ -864,7 +894,7 @@ break; } case tok::at: - return ParseObjCAtDirectives(attrs); + return ParseObjCAtDirectives(Attrs); case tok::minus: case tok::plus: if (!getLangOpts().ObjC) { @@ -886,17 +916,23 @@ 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; } // This must be 'export template'. Parse it so we can diagnose our lack // of support. - LLVM_FALLTHROUGH; + [[fallthrough]]; case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: @@ -906,9 +942,21 @@ // 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_cbuffer: + case tok::kw_tbuffer: + if (getLangOpts().HLSL) { + SourceLocation DeclEnd; + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); + } + goto dont_know; + case tok::kw_static: // Parse (then ignore) 'static' prior to a template instantiation. This is // a GCC extension that we intentionally do not support. @@ -916,7 +964,9 @@ 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; @@ -927,7 +977,9 @@ // 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 @@ -936,7 +988,9 @@ 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; @@ -951,7 +1005,7 @@ 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; @@ -972,7 +1026,7 @@ 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 @@ -1009,7 +1063,7 @@ // Handle K&R C argument lists: int X(f) int f; {} if (!getLangOpts().CPlusPlus && Declarator.getFunctionTypeInfo().isKNRPrototype()) - return isDeclarationSpecifier(); + return isDeclarationSpecifier(ImplicitTypenameContext::No); if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) { const Token &KW = NextToken(); @@ -1036,10 +1090,8 @@ /// [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, @@ -1078,11 +1130,11 @@ ? 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}; @@ -1091,8 +1143,6 @@ 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. @@ -1107,6 +1157,7 @@ } DS.abort(); + DS.takeAttributesFrom(Attrs); const char *PrevSpec = nullptr; unsigned DiagID; @@ -1130,19 +1181,18 @@ 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 @@ -1150,7 +1200,7 @@ // afterwards. ObjCDeclContextSwitch ObjCDC(*this); - return ParseDeclOrFunctionDefInternal(attrs, PDS, AS); + return ParseDeclOrFunctionDefInternal(Attrs, PDS, AS); } } @@ -1176,10 +1226,12 @@ 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(); @@ -1280,6 +1332,41 @@ 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; @@ -1287,10 +1374,13 @@ 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; } @@ -1301,6 +1391,13 @@ // 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)) @@ -1310,42 +1407,6 @@ // 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(); @@ -1411,7 +1472,7 @@ Scope::FunctionDeclarationScope | Scope::DeclScope); // Read all the argument declarations. - while (isDeclarationSpecifier()) { + while (isDeclarationSpecifier(ImplicitTypenameContext::No)) { SourceLocation DSStart = Tok.getLocation(); // Parse the common declaration-specifiers piece. @@ -1443,11 +1504,12 @@ } // 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. - while (1) { + while (true) { // If attributes are present, parse them. MaybeParseGNUAttributes(ParmDeclarator); @@ -1532,7 +1594,7 @@ 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(); @@ -1623,8 +1685,12 @@ /// /// \param CCC Indicates how to perform typo-correction for this name. If NULL, /// no typo correction will be performed. +/// \param AllowImplicitTypename Whether we are in a context where a dependent +/// nested-name-specifier without typename is treated as a type (e.g. +/// T::type). Parser::AnnotatedNameKind -Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { +Parser::TryAnnotateName(CorrectionCandidateCallback *CCC, + ImplicitTypenameContext AllowImplicitTypename) { assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope)); const bool EnteringContext = false; @@ -1633,12 +1699,13 @@ CXXScopeSpec SS; if (getLangOpts().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, EnteringContext)) return ANK_Error; if (Tok.isNot(tok::identifier) || SS.isInvalid()) { - if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation)) + if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation, + AllowImplicitTypename)) return ANK_Error; return ANK_Unresolved; } @@ -1648,10 +1715,11 @@ // FIXME: Move the tentative declaration logic into ClassifyName so we can // typo-correct to tentatively-declared identifiers. - if (isTentativelyDeclared(Name)) { + if (isTentativelyDeclared(Name) && SS.isEmpty()) { // Identifier has been tentatively declared, and thus cannot be resolved as // an expression. Fall back to annotating it as a type. - if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation)) + if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation, + AllowImplicitTypename)) return ANK_Error; return Tok.is(tok::annot_typename) ? ANK_Success : ANK_TentativeDecl; } @@ -1778,7 +1846,7 @@ AnnotateScopeToken(SS, !WasScopeAnnotation); return ANK_TemplateName; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::NC_VarTemplate: case Sema::NC_FunctionTemplate: case Sema::NC_UndeclaredTemplate: { @@ -1847,7 +1915,8 @@ /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. -bool Parser::TryAnnotateTypeOrScopeToken() { +bool Parser::TryAnnotateTypeOrScopeToken( + ImplicitTypenameContext AllowImplicitTypename) { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) || @@ -1864,7 +1933,7 @@ if (getLangOpts().MSVCCompat && NextToken().is(tok::kw_typedef)) { Token TypedefToken; PP.Lex(TypedefToken); - bool Result = TryAnnotateTypeOrScopeToken(); + bool Result = TryAnnotateTypeOrScopeToken(AllowImplicitTypename); PP.EnterToken(Tok, /*IsReinject=*/true); Tok = TypedefToken; if (!Result) @@ -1881,7 +1950,7 @@ SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false, nullptr, /*IsTypename*/ true)) return true; @@ -1890,7 +1959,8 @@ Tok.is(tok::annot_decltype)) { // Attempt to recover by skipping the invalid 'typename' if (Tok.is(tok::annot_decltype) || - (!TryAnnotateTypeOrScopeToken() && Tok.isAnnotation())) { + (!TryAnnotateTypeOrScopeToken(AllowImplicitTypename) && + Tok.isAnnotation())) { unsigned DiagID = diag::err_expected_qualified_after_typename; // MS compatibility: MSVC permits using known types with typename. // e.g. "typedef typename T* pointer_type" @@ -1952,26 +2022,28 @@ CXXScopeSpec SS; if (getLangOpts().CPlusPlus) if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext*/ false)) return true; - return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation); + return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation, + AllowImplicitTypename); } /// Try to annotate a type or scope token, having already parsed an /// optional scope specifier. \p IsNewScope should be \c true unless the scope /// specifier was extracted from an existing tok::annot_cxxscope annotation. -bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, - bool IsNewScope) { +bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec( + CXXScopeSpec &SS, bool IsNewScope, + ImplicitTypenameContext AllowImplicitTypename) { if (Tok.is(tok::identifier)) { // Determine whether the identifier is a type name. if (ParsedType Ty = Actions.getTypeName( *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, false, NextToken().is(tok::period), nullptr, /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo*/true, - /*IsClassTemplateDeductionContext*/true)) { + /*NonTrivialTypeSourceInfo=*/true, + /*IsClassTemplateDeductionContext=*/true, AllowImplicitTypename)) { SourceLocation BeginLoc = Tok.getLocation(); if (SS.isNotEmpty()) // it was a C++ qualified type name. BeginLoc = SS.getBeginLoc(); @@ -2008,9 +2080,9 @@ } if (!getLangOpts().CPlusPlus) { - // If we're in C, we can't have :: tokens at all (the lexer won't return - // them). If the identifier is not a type, then it can't be scope either, - // just early exit. + // If we're in C, the only place we can have :: tokens is C2x + // attribute which is parsed elsewhere. If the identifier is not a type, + // then it can't be scope either, just early exit. return false; } @@ -2057,7 +2129,7 @@ // template-id annotation in a context where we weren't allowed // to produce a type annotation token. Update the template-id // annotation token to a type annotation token now. - AnnotateTemplateIdTokenAsType(SS); + AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename); return false; } } @@ -2083,7 +2155,7 @@ CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, EnteringContext)) return true; if (SS.isEmpty()) @@ -2115,7 +2187,7 @@ Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal) << Kind << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "="); - LLVM_FALLTHROUGH; + [[fallthrough]]; case tok::equal: return true; } @@ -2126,14 +2198,14 @@ 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; @@ -2194,7 +2266,7 @@ // Parse nested-name-specifier. if (getLangOpts().CPlusPlus) ParseOptionalCXXScopeSpecifier(Result.SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, + /*ObjectHasErrors=*/false, /*EnteringContext=*/false); // Check nested-name specifier. @@ -2268,9 +2340,9 @@ // 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()); } @@ -2290,7 +2362,8 @@ /// 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) @@ -2310,7 +2383,7 @@ // 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; @@ -2319,6 +2392,7 @@ Diag(StartLoc, diag::err_module_fragment_exported) << /*global*/0 << FixItHint::CreateRemoval(StartLoc); } + ImportState = Sema::ModuleImportState::GlobalFragment; return Actions.ActOnGlobalModuleFragmentDecl(ModuleLoc); } @@ -2333,52 +2407,56 @@ 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; @@ -2390,9 +2468,10 @@ 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 @@ -2402,24 +2481,27 @@ // 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. @@ -2427,12 +2509,51 @@ 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; @@ -2441,8 +2562,8 @@ // 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); }