diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp | 760 |
1 files changed, 606 insertions, 154 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp index 356e7851ec63..7ce9a9cea1c7 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp @@ -26,7 +26,11 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaCUDA.h" +#include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaOpenMP.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -89,13 +93,23 @@ static StringRef normalizeAttrName(StringRef Name) { return Name; } -/// isAttributeLateParsed - Return true if the attribute has arguments that -/// require late parsing. -static bool isAttributeLateParsed(const IdentifierInfo &II) { +/// returns true iff attribute is annotated with `LateAttrParseExperimentalExt` +/// in `Attr.td`. +static bool IsAttributeLateParsedExperimentalExt(const IdentifierInfo &II) { +#define CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_EXT_LIST + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(false); +#undef CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_EXT_LIST +} + +/// returns true iff attribute is annotated with `LateAttrParseStandard` in +/// `Attr.td`. +static bool IsAttributeLateParsedStandard(const IdentifierInfo &II) { #define CLANG_ATTR_LATE_PARSED_LIST - return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) #include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); + .Default(false); #undef CLANG_ATTR_LATE_PARSED_LIST } @@ -205,7 +219,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &Attrs, break; if (Tok.is(tok::code_completion)) { cutOffParsing(); - Actions.CodeCompleteAttribute(AttributeCommonInfo::Syntax::AS_GNU); + Actions.CodeCompletion().CodeCompleteAttribute( + AttributeCommonInfo::Syntax::AS_GNU); break; } IdentifierInfo *AttrName = Tok.getIdentifierInfo(); @@ -220,8 +235,26 @@ void Parser::ParseGNUAttributes(ParsedAttributes &Attrs, continue; } + bool LateParse = false; + if (!LateAttrs) + LateParse = false; + else if (LateAttrs->lateAttrParseExperimentalExtOnly()) { + // The caller requested that this attribute **only** be late + // parsed for `LateAttrParseExperimentalExt` attributes. This will + // only be late parsed if the experimental language option is enabled. + LateParse = getLangOpts().ExperimentalLateParseAttributes && + IsAttributeLateParsedExperimentalExt(*AttrName); + } else { + // The caller did not restrict late parsing to only + // `LateAttrParseExperimentalExt` attributes so late parse + // both `LateAttrParseStandard` and `LateAttrParseExperimentalExt` + // attributes. + LateParse = IsAttributeLateParsedExperimentalExt(*AttrName) || + IsAttributeLateParsedStandard(*AttrName); + } + // Handle "parameterized" attributes - if (!LateAttrs || !isAttributeLateParsed(*AttrName)) { + if (!LateParse) { ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, &EndLoc, nullptr, SourceLocation(), ParsedAttr::Form::GNU(), D); continue; @@ -291,7 +324,7 @@ static bool attributeHasIdentifierArg(const IdentifierInfo &II) { /// Determine whether the given attribute has an identifier argument. static ParsedAttributeArgumentsProperties -attributeStringLiteralListArg(const IdentifierInfo &II) { +attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II) { #define CLANG_ATTR_STRING_LITERAL_ARG_LIST return llvm::StringSwitch<uint32_t>(normalizeAttrName(II.getName())) #include "clang/Parse/AttrParserStringSwitches.inc" @@ -335,6 +368,27 @@ static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { #undef CLANG_ATTR_TYPE_ARG_LIST } +/// Determine whether the given attribute takes identifier arguments. +static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II) { +#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST + return (llvm::StringSwitch<uint64_t>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(0)) != 0; +#undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST +} + +/// Determine whether the given attribute takes an identifier argument at a +/// specific index +static bool attributeHasStrictIdentifierArgAtIndex(const IdentifierInfo &II, + size_t argIndex) { +#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST + return (llvm::StringSwitch<uint64_t>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(0)) & + (1ull << argIndex); +#undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST +} + /// Determine whether the given attribute requires parsing its arguments /// in an unevaluated context or not. static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II) { @@ -434,6 +488,11 @@ bool Parser::ParseAttributeArgumentList( break; } + if (Actions.DiagnoseUnexpandedParameterPack(Expr.get())) { + SawError = true; + break; + } + Exprs.push_back(Expr.get()); if (Tok.isNot(tok::comma)) @@ -508,7 +567,8 @@ unsigned Parser::ParseAttributeArgsCommon( } if (T.isUsable()) TheParsedType = T.get(); - } else if (AttributeHasVariadicIdentifierArg) { + } else if (AttributeHasVariadicIdentifierArg || + attributeHasStrictIdentifierArgs(*AttrName)) { // Parse variadic identifier arg. This can either consume identifiers or // expressions. Variadic identifier args do not support parameter packs // because those are typically used for attributes with enumeration @@ -519,6 +579,12 @@ unsigned Parser::ParseAttributeArgsCommon( if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) Tok.setKind(tok::identifier); + if (Tok.is(tok::identifier) && attributeHasStrictIdentifierArgAtIndex( + *AttrName, ArgExprs.size())) { + ArgExprs.push_back(ParseIdentifierLoc()); + continue; + } + ExprResult ArgExpr; if (Tok.is(tok::identifier)) { ArgExprs.push_back(ParseIdentifierLoc()); @@ -527,7 +593,9 @@ unsigned Parser::ParseAttributeArgsCommon( EnterExpressionEvaluationContext Unevaluated( Actions, Uneval ? Sema::ExpressionEvaluationContext::Unevaluated - : Sema::ExpressionEvaluationContext::ConstantEvaluated); + : Sema::ExpressionEvaluationContext::ConstantEvaluated, + nullptr, + Sema::ExpressionEvaluationContextRecord::EK_AttrArgument); ExprResult ArgExpr( Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); @@ -544,13 +612,16 @@ unsigned Parser::ParseAttributeArgsCommon( // General case. Parse all available expressions. bool Uneval = attributeParsedArgsUnevaluated(*AttrName); EnterExpressionEvaluationContext Unevaluated( - Actions, Uneval - ? Sema::ExpressionEvaluationContext::Unevaluated - : Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, + Uneval ? Sema::ExpressionEvaluationContext::Unevaluated + : Sema::ExpressionEvaluationContext::ConstantEvaluated, + nullptr, + Sema::ExpressionEvaluationContextRecord::ExpressionKind:: + EK_AttrArgument); ExprVector ParsedExprs; ParsedAttributeArgumentsProperties ArgProperties = - attributeStringLiteralListArg(*AttrName); + attributeStringLiteralListArg(getTargetInfo().getTriple(), *AttrName); if (ParseAttributeArgumentList(*AttrName, ParsedExprs, ArgProperties)) { SkipUntil(tok::r_paren, StopAtSemi); return 0; @@ -629,6 +700,16 @@ void Parser::ParseGNUAttributeArgs( ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, Form); return; + } else if (AttrKind == ParsedAttr::AT_CountedBy || + AttrKind == ParsedAttr::AT_CountedByOrNull || + AttrKind == ParsedAttr::AT_SizedBy || + AttrKind == ParsedAttr::AT_SizedByOrNull) { + ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, + Form); + return; + } else if (AttrKind == ParsedAttr::AT_CXXAssume) { + ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form); + return; } // These may refer to the function arguments, but need to be parsed early to @@ -683,6 +764,10 @@ unsigned Parser::ParseClangAttributeArgs( ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Form); break; + + case ParsedAttr::AT_CXXAssume: + ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form); + break; } return !Attrs.empty() ? Attrs.begin()->getNumArgs() : 0; } @@ -860,7 +945,8 @@ void Parser::ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs) { if (Tok.is(tok::code_completion)) { cutOffParsing(); - Actions.CodeCompleteAttribute(AttributeCommonInfo::AS_Declspec); + Actions.CodeCompletion().CodeCompleteAttribute( + AttributeCommonInfo::AS_Declspec); return; } @@ -1218,6 +1304,7 @@ void Parser::ParseAvailabilityAttribute( enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; ExprResult MessageExpr, ReplacementExpr; + IdentifierLoc *EnvironmentLoc = nullptr; // Opening '('. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -1234,8 +1321,11 @@ void Parser::ParseAvailabilityAttribute( } IdentifierLoc *Platform = ParseIdentifierLoc(); if (const IdentifierInfo *const Ident = Platform->Ident) { + // Disallow xrOS for availability attributes. + if (Ident->getName().contains("xrOS") || Ident->getName().contains("xros")) + Diag(Platform->Loc, diag::warn_availability_unknown_platform) << Ident; // Canonicalize platform name from "macosx" to "macos". - if (Ident->getName() == "macosx") + else if (Ident->getName() == "macosx") Platform->Ident = PP.getIdentifierInfo("macos"); // Canonicalize platform name from "macosx_app_extension" to // "macos_app_extension". @@ -1262,6 +1352,7 @@ void Parser::ParseAvailabilityAttribute( Ident_message = PP.getIdentifierInfo("message"); Ident_strict = PP.getIdentifierInfo("strict"); Ident_replacement = PP.getIdentifierInfo("replacement"); + Ident_environment = PP.getIdentifierInfo("environment"); } // Parse the optional "strict", the optional "replacement" and the set of @@ -1309,6 +1400,13 @@ void Parser::ParseAvailabilityAttribute( continue; } + if (Keyword == Ident_environment) { + if (EnvironmentLoc != nullptr) { + Diag(KeywordLoc, diag::err_availability_redundant) + << Keyword << SourceRange(EnvironmentLoc->Loc); + } + } + if (Tok.isNot(tok::equal)) { Diag(Tok, diag::err_expected_after) << Keyword << tok::equal; SkipUntil(tok::r_paren, StopAtSemi); @@ -1330,6 +1428,15 @@ void Parser::ParseAvailabilityAttribute( continue; } } + if (Keyword == Ident_environment) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_availability_expected_environment); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + EnvironmentLoc = ParseIdentifierLoc(); + continue; + } // Special handling of 'NA' only when applied to introduced or // deprecated. @@ -1411,7 +1518,7 @@ void Parser::ParseAvailabilityAttribute( SourceRange(AvailabilityLoc, T.getCloseLocation()), ScopeName, ScopeLoc, Platform, Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], UnavailableLoc, MessageExpr.get(), Form, - StrictLoc, ReplacementExpr.get()); + StrictLoc, ReplacementExpr.get(), EnvironmentLoc); } /// Parse the contents of the "external_source_symbol" attribute. @@ -1864,9 +1971,8 @@ void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs) { // variable. // This function moves attributes that should apply to the type off DS to Attrs. void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs, - DeclSpec &DS, - Sema::TagUseKind TUK) { - if (TUK == Sema::TUK_Reference) + DeclSpec &DS, TagUseKind TUK) { + if (TUK == TagUseKind::Reference) return; llvm::SmallVector<ParsedAttr *, 1> ToBeMoved; @@ -1916,9 +2022,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, case tok::kw_export: ProhibitAttributes(DeclAttrs); ProhibitAttributes(DeclSpecAttrs); - SingleDecl = - ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs); - break; + return ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs); case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) { @@ -1994,8 +2098,9 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( ParsingDeclSpec DS(*this); DS.takeAttributesFrom(DeclSpecAttrs); + ParsedTemplateInfo TemplateInfo; DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context); - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, DSContext); // If we had a free-standing type definition with a missing semicolon, we // may get this far before the problem becomes obvious. @@ -2027,7 +2132,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( if (DeclSpecStart) DS.SetRangeStart(*DeclSpecStart); - return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI); + return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd, FRI); } /// Returns true if this might be the start of a declarator, or a common typo @@ -2184,6 +2289,7 @@ void Parser::SkipMalformedDecl() { Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, ParsedAttributes &Attrs, + ParsedTemplateInfo &TemplateInfo, SourceLocation *DeclEnd, ForRangeInit *FRI) { // Parse the first declarator. @@ -2193,8 +2299,19 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParsedAttributes LocalAttrs(AttrFactory); LocalAttrs.takeAllFrom(Attrs); ParsingDeclarator D(*this, DS, LocalAttrs, Context); + if (TemplateInfo.TemplateParams) + D.setTemplateParameterLists(*TemplateInfo.TemplateParams); + + bool IsTemplateSpecOrInst = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); + ParseDeclarator(D); + if (IsTemplateSpecOrInst) + SAC.done(); + // Bail out if the first declarator didn't seem well-formed. if (!D.hasName() && !D.mayOmitIdentifier()) { SkipMalformedDecl(); @@ -2202,7 +2319,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } if (getLangOpts().HLSL) - MaybeParseHLSLSemantics(D); + MaybeParseHLSLAnnotations(D); if (Tok.is(tok::kw_requires)) ParseTrailingRequiresClause(D); @@ -2237,7 +2354,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Check to see if we have a function *definition* which must have a body. if (Tok.is(tok::equal) && NextToken().is(tok::code_completion)) { cutOffParsing(); - Actions.CodeCompleteAfterFunctionEquals(D); + Actions.CodeCompletion().CodeCompleteAfterFunctionEquals(D); return nullptr; } // We're at the point where the parsing of function declarator is finished. @@ -2262,15 +2379,54 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // need to handle the file scope definition case. if (Context == DeclaratorContext::File) { if (isStartOfFunctionDefinition(D)) { + // C++23 [dcl.typedef] p1: + // The typedef specifier shall not be [...], and it shall not be + // used in the decl-specifier-seq of a parameter-declaration nor in + // the decl-specifier-seq of a function-definition. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); - - // Recover by treating the 'typedef' as spurious. + // If the user intended to write 'typename', we should have already + // suggested adding it elsewhere. In any case, recover by ignoring + // 'typedef' and suggest removing it. + Diag(DS.getStorageClassSpecLoc(), + diag::err_function_declared_typedef) + << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); DS.ClearStorageClassSpecs(); } + Decl *TheDecl = nullptr; + + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) { + // If the declarator-id is not a template-id, issue a diagnostic + // and recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0; + TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(), + &LateParsedAttrs); + } else { + SourceLocation LAngleLoc = + PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Recover as if it were an explicit specialization. + TemplateParameterLists FakedParamLists; + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, + std::nullopt, LAngleLoc, nullptr)); + + TheDecl = ParseFunctionDefinition( + D, + ParsedTemplateInfo(&FakedParamLists, + /*isSpecialization=*/true, + /*lastParameterListWasEmpty=*/true), + &LateParsedAttrs); + } + } else { + TheDecl = + ParseFunctionDefinition(D, TemplateInfo, &LateParsedAttrs); + } - Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(), - &LateParsedAttrs); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -2312,12 +2468,34 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, bool IsForRangeLoop = false; if (TryConsumeToken(tok::colon, FRI->ColonLoc)) { IsForRangeLoop = true; + EnterExpressionEvaluationContext ForRangeInitContext( + Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, + /*LambdaContextDecl=*/nullptr, + Sema::ExpressionEvaluationContextRecord::EK_Other, + getLangOpts().CPlusPlus23); + + // P2718R0 - Lifetime extension in range-based for loops. + if (getLangOpts().CPlusPlus23) { + auto &LastRecord = Actions.ExprEvalContexts.back(); + LastRecord.InLifetimeExtendingContext = true; + } + if (getLangOpts().OpenMP) - Actions.startOpenMPCXXRangeFor(); + Actions.OpenMP().startOpenMPCXXRangeFor(); if (Tok.is(tok::l_brace)) FRI->RangeExpr = ParseBraceInitializer(); else FRI->RangeExpr = ParseExpression(); + + // Before c++23, ForRangeLifetimeExtendTemps should be empty. + assert( + getLangOpts().CPlusPlus23 || + Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps.empty()); + + // Move the collected materialized temporaries into ForRangeInit before + // ForRangeInitContext exit. + FRI->LifetimeExtendTemps = std::move( + Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps); } Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); @@ -2334,8 +2512,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } SmallVector<Decl *, 8> DeclsInGroup; - Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes( - D, ParsedTemplateInfo(), FRI); + Decl *FirstDecl = + ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo, FRI); if (LateParsedAttrs.size() > 0) ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false); D.complete(FirstDecl); @@ -2358,6 +2536,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, break; } + // C++23 [temp.pre]p5: + // In a template-declaration, explicit specialization, or explicit + // instantiation the init-declarator-list in the declaration shall + // contain at most one declarator. + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + D.isFirstDeclarator()) { + Diag(CommaLoc, diag::err_multiple_template_declarators) + << TemplateInfo.Kind; + } + // Parse the next declarator. D.clear(); D.setCommaLoc(CommaLoc); @@ -2378,7 +2566,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParseDeclarator(D); if (getLangOpts().HLSL) - MaybeParseHLSLSemantics(D); + MaybeParseHLSLAnnotations(D); if (!D.isInvalidType()) { // C++2a [dcl.decl]p1 @@ -2387,7 +2575,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // declarator requires-clause if (Tok.is(tok::kw_requires)) ParseTrailingRequiresClause(D); - Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); + Decl *ThisDecl = ParseDeclarationAfterDeclarator(D, TemplateInfo); D.complete(ThisDecl); if (ThisDecl) DeclsInGroup.push_back(ThisDecl); @@ -2468,25 +2656,30 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Parser &P; Declarator &D; Decl *ThisDecl; + bool Entered; InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl) - : P(P), D(D), ThisDecl(ThisDecl) { + : P(P), D(D), ThisDecl(ThisDecl), Entered(false) { if (ThisDecl && P.getLangOpts().CPlusPlus) { Scope *S = nullptr; if (D.getCXXScopeSpec().isSet()) { P.EnterScope(0); S = P.getCurScope(); } - P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl); + if (ThisDecl && !ThisDecl->isInvalidDecl()) { + P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl); + Entered = true; + } } } - ~InitializerScopeRAII() { pop(); } - void pop() { + ~InitializerScopeRAII() { if (ThisDecl && P.getLangOpts().CPlusPlus) { Scope *S = nullptr; if (D.getCXXScopeSpec().isSet()) S = P.getCurScope(); - P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl); + + if (Entered) + P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl); if (S) P.ExitScope(); } @@ -2571,7 +2764,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } } - Sema::CUDATargetContextRAII X(Actions, Sema::CTCK_InitGlobalVar, ThisDecl); + SemaCUDA::CUDATargetContextRAII X(Actions.CUDA(), + SemaCUDA::CTCK_InitGlobalVar, ThisDecl); switch (TheInitKind) { // Parse declarator '=' initializer. case InitKind::Equal: { @@ -2583,6 +2777,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( << 1 /* delete */; else Diag(ConsumeToken(), diag::err_deleted_non_function); + SkipDeletedFunctionBody(); } else if (Tok.is(tok::kw_default)) { if (D.isFunctionDeclarator()) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) @@ -2595,7 +2790,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( if (Tok.is(tok::code_completion)) { cutOffParsing(); - Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); + Actions.CodeCompletion().CodeCompleteInitializer(getCurScope(), + ThisDecl); Actions.FinalizeDeclaration(ThisDecl); return nullptr; } @@ -2615,8 +2811,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( FRI->RangeExpr = Init; } - InitScope.pop(); - if (Init.isInvalid()) { SmallVector<tok::TokenKind, 2> StopTokens; StopTokens.push_back(tok::comma); @@ -2642,10 +2836,11 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl); auto RunSignatureHelp = [&]() { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - ThisVarDecl->getType()->getCanonicalTypeInternal(), - ThisDecl->getLocation(), Exprs, T.getOpenLocation(), - /*Braced=*/false); + QualType PreferredType = + Actions.CodeCompletion().ProduceConstructorSignatureHelp( + ThisVarDecl->getType()->getCanonicalTypeInternal(), + ThisDecl->getLocation(), Exprs, T.getOpenLocation(), + /*Braced=*/false); CalledSignatureHelp = true; return PreferredType; }; @@ -2664,11 +2859,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( bool SawError = ParseExpressionList(Exprs, ExpressionStarts); - InitScope.pop(); - if (SawError) { if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceConstructorSignatureHelp( + Actions.CodeCompletion().ProduceConstructorSignatureHelp( ThisVarDecl->getType()->getCanonicalTypeInternal(), ThisDecl->getLocation(), Exprs, T.getOpenLocation(), /*Braced=*/false); @@ -2697,8 +2890,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl); ExprResult Init(ParseBraceInitializer()); - InitScope.pop(); - if (Init.isInvalid()) { Actions.ActOnInitializerError(ThisDecl); } else @@ -2724,10 +2915,11 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( void Parser::ParseSpecifierQualifierList( DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename, AccessSpecifier AS, DeclSpecContext DSC) { + ParsedTemplateInfo TemplateInfo; /// specifier-qualifier-list is a subset of declaration-specifiers. Just /// parse declaration-specifiers and complain about extra stuff. /// TODO: diagnose attribute-specifiers and alignment-specifiers. - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC, nullptr, + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, nullptr, AllowImplicitTypename); // Validate declspec for type-name. @@ -2806,7 +2998,7 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) { /// other pieces of declspec after it, it returns true. /// bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, - const ParsedTemplateInfo &TemplateInfo, + ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC, ParsedAttributes &Attrs) { assert(Tok.is(tok::identifier) && "should have identifier"); @@ -2905,7 +3097,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, << TokenName << TagName << getLangOpts().CPlusPlus << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName); - if (Actions.LookupParsedName(R, getCurScope(), SS)) { + if (Actions.LookupName(R, getCurScope())) { for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) @@ -3161,6 +3353,67 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, } } +void Parser::DistributeCLateParsedAttrs(Decl *Dcl, + LateParsedAttrList *LateAttrs) { + if (!LateAttrs) + return; + + if (Dcl) { + for (auto *LateAttr : *LateAttrs) { + if (LateAttr->Decls.empty()) + LateAttr->addDecl(Dcl); + } + } +} + +/// Bounds attributes (e.g., counted_by): +/// AttrName '(' expression ')' +void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + ParsedAttr::Form Form) { + assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + + BalancedDelimiterTracker Parens(*this, tok::l_paren); + Parens.consumeOpen(); + + if (Tok.is(tok::r_paren)) { + Diag(Tok.getLocation(), diag::err_argument_required_after_attribute); + Parens.consumeClose(); + return; + } + + ArgsVector ArgExprs; + // Don't evaluate argument when the attribute is ignored. + using ExpressionKind = + Sema::ExpressionEvaluationContextRecord::ExpressionKind; + EnterExpressionEvaluationContext EC( + Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, nullptr, + ExpressionKind::EK_AttrArgument); + + ExprResult ArgExpr( + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); + + if (ArgExpr.isInvalid()) { + Parens.skipToEnd(); + return; + } + + ArgExprs.push_back(ArgExpr.get()); + Parens.consumeClose(); + + ASTContext &Ctx = Actions.getASTContext(); + + ArgExprs.push_back(IntegerLiteral::Create( + Ctx, llvm::APInt(Ctx.getTypeSize(Ctx.getSizeType()), 0), + Ctx.getSizeType(), SourceLocation())); + + Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), + ScopeName, ScopeLoc, ArgExprs.data(), ArgExprs.size(), Form); +} + ExprResult Parser::ParseExtIntegerArgument() { assert(Tok.isOneOf(tok::kw__ExtInt, tok::kw__BitInt) && "Not an extended int type"); @@ -3320,7 +3573,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, /// 'friend': [C++ dcl.friend] /// 'constexpr': [C++0x dcl.constexpr] void Parser::ParseDeclarationSpecifiers( - DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, + DeclSpec &DS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSContext, LateParsedAttrList *LateAttrs, ImplicitTypenameContext AllowImplicitTypename) { if (DS.getSourceRange().isInvalid()) { @@ -3432,8 +3685,23 @@ void Parser::ParseDeclarationSpecifiers( DS.Finish(Actions, Policy); return; - case tok::l_square: + // alignment-specifier + case tok::kw__Alignas: + diagnoseUseOfC11Keyword(Tok); + [[fallthrough]]; case tok::kw_alignas: + // _Alignas and alignas (C23, not C++) should parse the same way. The C++ + // parsing for alignas happens through the usual attribute parsing. This + // ensures that an alignas specifier can appear in a type position in C + // despite that not being valid in C++. + if (getLangOpts().C23 || Tok.getKind() == tok::kw__Alignas) { + if (Tok.getKind() == tok::kw_alignas) + Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName(); + ParseAlignmentSpecifier(DS.getAttributes()); + continue; + } + [[fallthrough]]; + case tok::l_square: if (!isAllowedCXX11AttributeSpecifier()) goto DoneWithDeclSpec; @@ -3450,7 +3718,8 @@ void Parser::ParseDeclarationSpecifiers( continue; case tok::code_completion: { - Sema::ParserCompletionContext CCC = Sema::PCC_Namespace; + SemaCodeCompletion::ParserCompletionContext CCC = + SemaCodeCompletion::PCC_Namespace; if (DS.hasTypeSpecifier()) { bool AllowNonIdentifiers = (getCurScope()->getFlags() & (Scope::ControlScope | @@ -3463,25 +3732,25 @@ void Parser::ParseDeclarationSpecifiers( (DSContext == DeclSpecContext::DSC_class && DS.isFriendSpecified()); cutOffParsing(); - Actions.CodeCompleteDeclSpec(getCurScope(), DS, - AllowNonIdentifiers, - AllowNestedNameSpecifiers); + Actions.CodeCompletion().CodeCompleteDeclSpec( + getCurScope(), DS, AllowNonIdentifiers, AllowNestedNameSpecifiers); return; } // Class context can appear inside a function/block, so prioritise that. if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) - CCC = DSContext == DeclSpecContext::DSC_class ? Sema::PCC_MemberTemplate - : Sema::PCC_Template; + CCC = DSContext == DeclSpecContext::DSC_class + ? SemaCodeCompletion::PCC_MemberTemplate + : SemaCodeCompletion::PCC_Template; else if (DSContext == DeclSpecContext::DSC_class) - CCC = Sema::PCC_Class; + CCC = SemaCodeCompletion::PCC_Class; else if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) - CCC = Sema::PCC_LocalDeclarationSpecifiers; + CCC = SemaCodeCompletion::PCC_LocalDeclarationSpecifiers; else if (CurParsedObjCImpl) - CCC = Sema::PCC_ObjCImplementation; + CCC = SemaCodeCompletion::PCC_ObjCImplementation; cutOffParsing(); - Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); + Actions.CodeCompletion().CodeCompleteOrdinaryName(getCurScope(), CCC); return; } @@ -3706,7 +3975,7 @@ void Parser::ParseDeclarationSpecifiers( // parse errors if this really is a __declspec attribute. Attempt to // recognize that scenario and recover gracefully. if (!getLangOpts().DeclSpecKeyword && Tok.is(tok::identifier) && - Tok.getIdentifierInfo()->getName().equals("__declspec")) { + Tok.getIdentifierInfo()->getName() == "__declspec") { Diag(Loc, diag::err_ms_attributes_not_enabled); // The next token should be an open paren. If it is, eat the entire @@ -3762,7 +4031,7 @@ void Parser::ParseDeclarationSpecifiers( if (DSContext == DeclSpecContext::DSC_objc_method_result && isObjCInstancetype()) { - ParsedType TypeRep = Actions.ActOnObjCInstanceType(Loc); + ParsedType TypeRep = Actions.ObjC().ActOnObjCInstanceType(Loc); assert(TypeRep); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, TypeRep, Policy); @@ -4082,8 +4351,7 @@ void Parser::ParseDeclarationSpecifiers( isStorageClass = true; break; case tok::kw__Thread_local: - if (!getLangOpts().C11) - Diag(Tok, diag::ext_c11_feature) << Tok.getName(); + diagnoseUseOfC11Keyword(Tok); isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local, Loc, PrevSpec, DiagID); isStorageClass = true; @@ -4143,23 +4411,18 @@ void Parser::ParseDeclarationSpecifiers( break; } case tok::kw__Noreturn: - if (!getLangOpts().C11) - Diag(Tok, diag::ext_c11_feature) << Tok.getName(); + diagnoseUseOfC11Keyword(Tok); isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID); break; - // alignment-specifier - case tok::kw__Alignas: - if (!getLangOpts().C11) - Diag(Tok, diag::ext_c11_feature) << Tok.getName(); - ParseAlignmentSpecifier(DS.getAttributes()); - continue; - // friend case tok::kw_friend: - if (DSContext == DeclSpecContext::DSC_class) + if (DSContext == DeclSpecContext::DSC_class) { isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID); - else { + Scope *CurS = getCurScope(); + if (!isInvalid && CurS) + CurS->setFlags(CurS->getFlags() | Scope::FriendScope); + } else { PrevSpec = ""; // not actually used by the diagnostic DiagID = diag::err_friend_invalid_in_context; isInvalid = true; @@ -4173,6 +4436,8 @@ void Parser::ParseDeclarationSpecifiers( // constexpr, consteval, constinit specifiers case tok::kw_constexpr: + if (getLangOpts().C23) + Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName(); isInvalid = DS.SetConstexprSpec(ConstexprSpecKind::Constexpr, Loc, PrevSpec, DiagID); break; @@ -4447,6 +4712,10 @@ void Parser::ParseDeclarationSpecifiers( ParseDecltypeSpecifier(DS); continue; + case tok::annot_pack_indexing_type: + ParsePackIndexingType(DS); + continue; + case tok::annot_pragma_pack: HandlePragmaPack(); continue; @@ -4477,9 +4746,7 @@ void Parser::ParseDeclarationSpecifiers( // If the _Atomic keyword is immediately followed by a left parenthesis, // it is interpreted as a type specifier (with a type name), not as a // type qualifier. - if (!getLangOpts().C11) - Diag(Tok, diag::ext_c11_feature) << Tok.getName(); - + diagnoseUseOfC11Keyword(Tok); if (NextToken().is(tok::l_paren)) { ParseAtomicSpecifier(DS); continue; @@ -4580,6 +4847,38 @@ void Parser::ParseDeclarationSpecifiers( } } +static void DiagnoseCountAttributedTypeInUnnamedAnon(ParsingDeclSpec &DS, + Parser &P) { + + if (DS.getTypeSpecType() != DeclSpec::TST_struct) + return; + + auto *RD = dyn_cast<RecordDecl>(DS.getRepAsDecl()); + // We're only interested in unnamed, non-anonymous struct + if (!RD || !RD->getName().empty() || RD->isAnonymousStructOrUnion()) + return; + + for (auto *I : RD->decls()) { + auto *VD = dyn_cast<ValueDecl>(I); + if (!VD) + continue; + + auto *CAT = VD->getType()->getAs<CountAttributedType>(); + if (!CAT) + continue; + + for (const auto &DD : CAT->dependent_decls()) { + if (!RD->containsDecl(DD.getDecl())) { + P.Diag(VD->getBeginLoc(), diag::err_count_attr_param_not_in_same_struct) + << DD.getDecl() << CAT->getKind() << CAT->isArrayType(); + P.Diag(DD.getDecl()->getBeginLoc(), + diag::note_flexible_array_counted_by_attr_field) + << DD.getDecl(); + } + } + } +} + /// ParseStructDeclaration - Parse a struct declaration without the terminating /// semicolon. /// @@ -4603,13 +4902,14 @@ void Parser::ParseDeclarationSpecifiers( /// void Parser::ParseStructDeclaration( ParsingDeclSpec &DS, - llvm::function_ref<void(ParsingFieldDeclarator &)> FieldsCallback) { + llvm::function_ref<Decl *(ParsingFieldDeclarator &)> FieldsCallback, + LateParsedAttrList *LateFieldAttrs) { if (Tok.is(tok::kw___extension__)) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseStructDeclaration(DS, FieldsCallback); + return ParseStructDeclaration(DS, FieldsCallback, LateFieldAttrs); } // Parse leading attributes. @@ -4660,6 +4960,11 @@ void Parser::ParseStructDeclaration( } else DeclaratorInfo.D.SetIdentifier(nullptr, Tok.getLocation()); + // Here, we now know that the unnamed struct is not an anonymous struct. + // Report an error if a counted_by attribute refers to a field in a + // different named struct. + DiagnoseCountAttributedTypeInUnnamedAnon(DS, *this); + if (TryConsumeToken(tok::colon)) { ExprResult Res(ParseConstantExpression()); if (Res.isInvalid()) @@ -4669,10 +4974,12 @@ void Parser::ParseStructDeclaration( } // If attributes exist after the declarator, parse them. - MaybeParseGNUAttributes(DeclaratorInfo.D); + MaybeParseGNUAttributes(DeclaratorInfo.D, LateFieldAttrs); // We're done with this declarator; invoke the callback. - FieldsCallback(DeclaratorInfo); + Decl *Field = FieldsCallback(DeclaratorInfo); + if (Field) + DistributeCLateParsedAttrs(Field, LateFieldAttrs); // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. @@ -4683,6 +4990,73 @@ void Parser::ParseStructDeclaration( } } +// TODO: All callers of this function should be moved to +// `Parser::ParseLexedAttributeList`. +void Parser::ParseLexedCAttributeList(LateParsedAttrList &LAs, bool EnterScope, + ParsedAttributes *OutAttrs) { + assert(LAs.parseSoon() && + "Attribute list should be marked for immediate parsing."); + for (auto *LA : LAs) { + ParseLexedCAttribute(*LA, EnterScope, OutAttrs); + delete LA; + } + LAs.clear(); +} + +/// Finish parsing an attribute for which parsing was delayed. +/// This will be called at the end of parsing a class declaration +/// for each LateParsedAttribute. We consume the saved tokens and +/// create an attribute with the arguments filled in. We add this +/// to the Attribute list for the decl. +void Parser::ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope, + ParsedAttributes *OutAttrs) { + // Create a fake EOF so that attribute parsing won't go off the end of the + // attribute. + Token AttrEnd; + AttrEnd.startToken(); + AttrEnd.setKind(tok::eof); + AttrEnd.setLocation(Tok.getLocation()); + AttrEnd.setEofData(LA.Toks.data()); + LA.Toks.push_back(AttrEnd); + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LA.Toks.push_back(Tok); + PP.EnterTokenStream(LA.Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/true); + // Drop the current token and bring the first cached one. It's the same token + // as when we entered this function. + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + + // TODO: Use `EnterScope` + (void)EnterScope; + + ParsedAttributes Attrs(AttrFactory); + + assert(LA.Decls.size() <= 1 && + "late field attribute expects to have at most one declaration."); + + // Dispatch based on the attribute and parse it + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, nullptr, nullptr, + SourceLocation(), ParsedAttr::Form::GNU(), nullptr); + + for (auto *D : LA.Decls) + Actions.ActOnFinishDelayedAttribute(getCurScope(), D, Attrs); + + // Due to a parsing error, we either went over the cached tokens or + // there are still cached tokens left, so we skip the leftover tokens. + while (Tok.isNot(tok::eof)) + ConsumeAnyToken(); + + // Consume the fake EOF token if it's there + if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData()) + ConsumeAnyToken(); + + if (OutAttrs) { + OutAttrs->takeAllFrom(Attrs); + } +} + /// ParseStructUnionBody /// struct-contents: /// struct-declaration-list @@ -4706,6 +5080,11 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); + // `LateAttrParseExperimentalExtOnly=true` requests that only attributes + // marked with `LateAttrParseExperimentalExt` are late parsed. + LateParsedAttrList LateFieldAttrs(/*PSoon=*/true, + /*LateAttrParseExperimentalExtOnly=*/true); + // While we still have something to read, read the declarations in the struct. while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -4756,18 +5135,19 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } if (!Tok.is(tok::at)) { - auto CFieldCallback = [&](ParsingFieldDeclarator &FD) { + auto CFieldCallback = [&](ParsingFieldDeclarator &FD) -> Decl * { // Install the declarator into the current TagDecl. Decl *Field = Actions.ActOnField(getCurScope(), TagDecl, FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D, FD.BitfieldSize); FD.complete(Field); + return Field; }; // Parse all the comma separated declarators. ParsingDeclSpec DS(*this); - ParseStructDeclaration(DS, CFieldCallback); + ParseStructDeclaration(DS, CFieldCallback, &LateFieldAttrs); } else { // Handle @defs ConsumeToken(); if (!Tok.isObjCAtKeyword(tok::objc_defs)) { @@ -4783,8 +5163,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } SmallVector<Decl *, 16> Fields; - Actions.ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(), - Tok.getIdentifierInfo(), Fields); + Actions.ObjC().ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(), + Tok.getIdentifierInfo(), Fields); ConsumeToken(); ExpectAndConsume(tok::r_paren); } @@ -4808,7 +5188,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParsedAttributes attrs(AttrFactory); // If attributes exist after struct contents, parse them. - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(attrs, &LateFieldAttrs); + + // Late parse field attributes if necessary. + ParseLexedCAttributeList(LateFieldAttrs, /*EnterScope=*/false); SmallVector<Decl *, 32> FieldDecls(TagDecl->fields()); @@ -4855,7 +5238,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::code_completion)) { // Code completion for an enum name. cutOffParsing(); - Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum); + Actions.CodeCompletion().CodeCompleteTag(getCurScope(), DeclSpec::TST_enum); DS.SetTypeSpecError(); // Needed by ActOnUsingDeclaration. return; } @@ -5042,9 +5425,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // enum foo {..}; void bar() { enum foo; } <- new foo in bar. // enum foo {..}; void bar() { enum foo x; } <- use of old foo. // - Sema::TagUseKind TUK; + TagUseKind TUK; if (AllowEnumSpecifier == AllowDefiningTypeSpec::No) - TUK = Sema::TUK_Reference; + TUK = TagUseKind::Reference; else if (Tok.is(tok::l_brace)) { if (DS.isFriendSpecified()) { Diag(Tok.getLocation(), diag::err_friend_decl_defines_type) @@ -5056,9 +5439,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ScopedEnumKWLoc = SourceLocation(); IsScopedUsingClassTag = false; BaseType = TypeResult(); - TUK = Sema::TUK_Friend; + TUK = TagUseKind::Friend; } else { - TUK = Sema::TUK_Definition; + TUK = TagUseKind::Definition; } } else if (!isTypeSpecifier(DSC) && (Tok.is(tok::semi) || @@ -5067,7 +5450,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // An opaque-enum-declaration is required to be standalone (no preceding or // following tokens in the declaration). Sema enforces this separately by // diagnosing anything else in the DeclSpec. - TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; + TUK = DS.isFriendSpecified() ? TagUseKind::Friend : TagUseKind::Declaration; if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. ExpectAndConsume(tok::semi, diag::err_expected_after, "enum"); @@ -5075,21 +5458,21 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Tok.setKind(tok::semi); } } else { - TUK = Sema::TUK_Reference; + TUK = TagUseKind::Reference; } bool IsElaboratedTypeSpecifier = - TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend; + TUK == TagUseKind::Reference || TUK == TagUseKind::Friend; // If this is an elaborated type specifier nested in a larger declaration, // and we delayed diagnostics before, just merge them into the current pool. - if (TUK == Sema::TUK_Reference && shouldDelayDiagsInTag) { + if (TUK == TagUseKind::Reference && shouldDelayDiagsInTag) { diagsFromTag.redelay(); } MultiTemplateParamsArg TParams; if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && - TUK != Sema::TUK_Reference) { + TUK != TagUseKind::Reference) { if (!getLangOpts().CPlusPlus11 || !SS.isSet()) { // Skip the rest of this declarator, up until the comma or semicolon. Diag(Tok, diag::err_enum_template); @@ -5110,7 +5493,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, SS.setTemplateParamLists(TParams); } - if (!Name && TUK != Sema::TUK_Definition) { + if (!Name && TUK != TagUseKind::Definition) { Diag(Tok, diag::err_enumerator_unnamed_no_def); DS.SetTypeSpecError(); @@ -5142,8 +5525,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, stripTypeAttributesOffDeclSpec(attrs, DS, TUK); - Sema::SkipBodyInfo SkipBody; - if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) && + SkipBodyInfo SkipBody; + if (!Name && TUK == TagUseKind::Definition && Tok.is(tok::l_brace) && NextToken().is(tok::identifier)) SkipBody = Actions.shouldSkipAnonEnumBody(getCurScope(), NextToken().getIdentifierInfo(), @@ -5164,7 +5547,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, OffsetOfState, &SkipBody).get(); if (SkipBody.ShouldSkip) { - assert(TUK == Sema::TUK_Definition && "can only skip a definition"); + assert(TUK == TagUseKind::Definition && "can only skip a definition"); BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); @@ -5206,7 +5589,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (!TagDecl) { // The action failed to produce an enumeration tag. If this is a // definition, consume the entire definition. - if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { + if (Tok.is(tok::l_brace) && TUK != TagUseKind::Reference) { ConsumeBrace(); SkipUntil(tok::r_brace, StopAtSemi); } @@ -5215,7 +5598,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - if (Tok.is(tok::l_brace) && TUK == Sema::TUK_Definition) { + if (Tok.is(tok::l_brace) && TUK == TagUseKind::Definition) { Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl; ParseEnumBody(StartLoc, D); if (SkipBody.CheckSameAsPrevious && @@ -5582,24 +5965,32 @@ Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() { // Parse a top-level-stmt. Parser::StmtVector Stmts; ParsedStmtContext SubStmtCtx = ParsedStmtContext(); - Actions.PushFunctionScope(); + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); + TopLevelStmtDecl *TLSD = Actions.ActOnStartTopLevelStmtDecl(getCurScope()); StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); - Actions.PopFunctionScopeInfo(); if (!R.isUsable()) return nullptr; - SmallVector<Decl *, 2> DeclsInGroup; - DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(R.get())); + Actions.ActOnFinishTopLevelStmtDecl(TLSD, R.get()); if (Tok.is(tok::annot_repl_input_end) && Tok.getAnnotationValue() != nullptr) { ConsumeAnnotationToken(); - cast<TopLevelStmtDecl>(DeclsInGroup.back())->setSemiMissing(); + TLSD->setSemiMissing(); } - // Currently happens for things like -fms-extensions and use `__if_exists`. - for (Stmt *S : Stmts) - DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(S)); + SmallVector<Decl *, 2> DeclsInGroup; + DeclsInGroup.push_back(TLSD); + + // Currently happens for things like -fms-extensions and use `__if_exists`. + for (Stmt *S : Stmts) { + // Here we should be safe as `__if_exists` and friends are not introducing + // new variables which need to live outside file scope. + TopLevelStmtDecl *D = Actions.ActOnStartTopLevelStmtDecl(getCurScope()); + Actions.ActOnFinishTopLevelStmtDecl(D, S); + DeclsInGroup.push_back(D); + } return Actions.BuildDeclaratorGroup(DeclsInGroup); } @@ -5756,6 +6147,7 @@ bool Parser::isDeclarationSpecifier( // C++11 decltype and constexpr. case tok::annot_decltype: + case tok::annot_pack_indexing_type: case tok::kw_constexpr: // C++20 consteval and constinit. @@ -5766,6 +6158,11 @@ bool Parser::isDeclarationSpecifier( case tok::kw__Atomic: return true; + case tok::kw_alignas: + // alignas is a type-specifier-qualifier in C23, which is a kind of + // declaration-specifier. Outside of C23 mode (including in C++), it is not. + return getLangOpts().C23; + // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'. case tok::less: return getLangOpts().ObjC; @@ -6031,7 +6428,7 @@ void Parser::ParseTypeQualifierListOpt( if (CodeCompletionHandler) (*CodeCompletionHandler)(); else - Actions.CodeCompleteTypeQualifiers(DS); + Actions.CodeCompletion().CodeCompleteTypeQualifiers(DS); return; case tok::kw_const: @@ -6049,8 +6446,7 @@ void Parser::ParseTypeQualifierListOpt( case tok::kw__Atomic: if (!AtomicAllowed) goto DoneWithTypeQuals; - if (!getLangOpts().C11) - Diag(Tok, diag::ext_c11_feature) << Tok.getName(); + diagnoseUseOfC11Keyword(Tok); isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID, getLangOpts()); break; @@ -6495,6 +6891,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) { /*ObjectHasErrors=*/false, EnteringContext); } + // C++23 [basic.scope.namespace]p1: + // For each non-friend redeclaration or specialization whose target scope + // is or is contained by the scope, the portion after the declarator-id, + // class-head-name, or enum-head-name is also included in the scope. + // C++23 [basic.scope.class]p1: + // For each non-friend redeclaration or specialization whose target scope + // is or is contained by the scope, the portion after the declarator-id, + // class-head-name, or enum-head-name is also included in the scope. + // + // FIXME: We should not be doing this for friend declarations; they have + // their own special lookup semantics specified by [basic.lookup.unqual]p6. if (D.getCXXScopeSpec().isValid()) { if (Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) @@ -6561,12 +6968,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { } bool HadScope = D.getCXXScopeSpec().isValid(); + SourceLocation TemplateKWLoc; if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, - AllowDeductionGuide, nullptr, D.getName()) || + AllowDeductionGuide, &TemplateKWLoc, + D.getName()) || // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. D.getCXXScopeSpec().isInvalid()) { @@ -6823,18 +7232,23 @@ void Parser::ParseDirectDeclarator(Declarator &D) { void Parser::ParseDecompositionDeclarator(Declarator &D) { assert(Tok.is(tok::l_square)); + TentativeParsingAction PA(*this); + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + + if (isCXX11AttributeSpecifier()) + DiagnoseAndSkipCXX11Attributes(); + // If this doesn't look like a structured binding, maybe it's a misplaced // array declarator. - // FIXME: Consume the l_square first so we don't need extra lookahead for - // this. - if (!(NextToken().is(tok::identifier) && - GetLookAheadToken(2).isOneOf(tok::comma, tok::r_square)) && - !(NextToken().is(tok::r_square) && - GetLookAheadToken(2).isOneOf(tok::equal, tok::l_brace))) + if (!(Tok.is(tok::identifier) && + NextToken().isOneOf(tok::comma, tok::r_square, tok::kw_alignas, + tok::l_square)) && + !(Tok.is(tok::r_square) && + NextToken().isOneOf(tok::equal, tok::l_brace))) { + PA.Revert(); return ParseMisplacedBracketDeclarator(D); - - BalancedDelimiterTracker T(*this, tok::l_square); - T.consumeOpen(); + } SmallVector<DecompositionDeclarator::Binding, 32> Bindings; while (Tok.isNot(tok::r_square)) { @@ -6859,13 +7273,27 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) { } } + if (isCXX11AttributeSpecifier()) + DiagnoseAndSkipCXX11Attributes(); + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; break; } - Bindings.push_back({Tok.getIdentifierInfo(), Tok.getLocation()}); + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation Loc = Tok.getLocation(); ConsumeToken(); + + ParsedAttributes Attrs(AttrFactory); + if (isCXX11AttributeSpecifier()) { + Diag(Tok, getLangOpts().CPlusPlus26 + ? diag::warn_cxx23_compat_decl_attrs_on_binding + : diag::ext_decl_attrs_on_binding); + MaybeParseCXX11Attributes(Attrs); + } + + Bindings.push_back({II, Loc, std::move(Attrs)}); } if (Tok.isNot(tok::r_square)) @@ -6880,6 +7308,8 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) { T.consumeClose(); } + PA.Commit(); + return D.setDecompositionBindings(T.getOpenLocation(), Bindings, T.getCloseLocation()); } @@ -7135,12 +7565,12 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // with the pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. - ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, - /*AtomicAllowed*/ false, - /*IdentifierRequired=*/false, - llvm::function_ref<void()>([&]() { - Actions.CodeCompleteFunctionQualifiers(DS, D); - })); + ParseTypeQualifierListOpt( + DS, AR_NoAttributesParsed, + /*AtomicAllowed*/ false, + /*IdentifierRequired=*/false, llvm::function_ref<void()>([&]() { + Actions.CodeCompletion().CodeCompleteFunctionQualifiers(DS, D); + })); if (!DS.getSourceRange().getEnd().isInvalid()) { EndLoc = DS.getSourceRange().getEnd(); } @@ -7152,12 +7582,20 @@ void Parser::ParseFunctionDeclarator(Declarator &D, std::optional<Sema::CXXThisScopeRAII> ThisScope; InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope); - // Parse exception-specification[opt]. - // FIXME: Per [class.mem]p6, all exception-specifications at class scope - // should be delayed, including those for non-members (eg, friend - // declarations). But only applying this to member declarations is - // consistent with what other implementations do. - bool Delayed = D.isFirstDeclarationOfMember() && + // C++ [class.mem.general]p8: + // A complete-class context of a class (template) is a + // - function body, + // - default argument, + // - default template argument, + // - noexcept-specifier, or + // - default member initializer + // within the member-specification of the class or class template. + // + // Parse exception-specification[opt]. If we are in the + // member-specification of a class or class template, this is a + // complete-class context and parsing of the noexcept-specifier should be + // delayed (even if this is a friend declaration). + bool Delayed = D.getContext() == DeclaratorContext::Member && D.isFunctionDeclaratorAFunctionDeclaration(); if (Delayed && Actions.isLibstdcxxEagerExceptionSpecHack(D) && GetLookAheadToken(0).is(tok::kw_noexcept) && @@ -7445,11 +7883,25 @@ void Parser::ParseParameterDeclarationClause( // Parse a C++23 Explicit Object Parameter // We do that in all language modes to produce a better diagnostic. SourceLocation ThisLoc; - if (getLangOpts().CPlusPlus && Tok.is(tok::kw_this)) + if (getLangOpts().CPlusPlus && Tok.is(tok::kw_this)) { ThisLoc = ConsumeToken(); + // C++23 [dcl.fct]p6: + // An explicit-object-parameter-declaration is a parameter-declaration + // with a this specifier. An explicit-object-parameter-declaration + // shall appear only as the first parameter-declaration of a + // parameter-declaration-list of either: + // - a member-declarator that declares a member function, or + // - a lambda-declarator. + // + // The parameter-declaration-list of a requires-expression is not such + // a context. + if (DeclaratorCtx == DeclaratorContext::RequiresExpr) + Diag(ThisLoc, diag::err_requires_expr_explicit_object_parameter); + } - ParseDeclarationSpecifiers(DS, /*TemplateInfo=*/ParsedTemplateInfo(), - AS_none, DeclSpecContext::DSC_normal, + ParsedTemplateInfo TemplateInfo; + ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, + DeclSpecContext::DSC_normal, /*LateAttrs=*/nullptr, AllowImplicitTypename); DS.takeAttributesFrom(ArgDeclSpecAttrs); @@ -7471,7 +7923,7 @@ void Parser::ParseParameterDeclarationClause( // Parse GNU attributes, if present. MaybeParseGNUAttributes(ParmDeclarator); if (getLangOpts().HLSL) - MaybeParseHLSLSemantics(DS.getAttributes()); + MaybeParseHLSLAnnotations(DS.getAttributes()); if (Tok.is(tok::kw_requires)) { // User tried to define a requires clause in a parameter declaration, @@ -7485,7 +7937,7 @@ void Parser::ParseParameterDeclarationClause( } // Remember this parsed parameter in ParamInfo. - IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); + const IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); // DefArgToks is used when the parsing of default arguments needs // to be delayed. @@ -7681,7 +8133,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { return; } else if (Tok.getKind() == tok::code_completion) { cutOffParsing(); - Actions.CodeCompleteBracketDeclarator(getCurScope()); + Actions.CodeCompletion().CodeCompleteBracketDeclarator(getCurScope()); return; } @@ -7816,7 +8268,7 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) { // Adding back the bracket info to the end of the Declarator. for (unsigned i = 0, e = TempDeclarator.getNumTypeObjects(); i < e; ++i) { const DeclaratorChunk &Chunk = TempDeclarator.getTypeObject(i); - D.AddTypeInfo(Chunk, SourceLocation()); + D.AddTypeInfo(Chunk, TempDeclarator.getAttributePool(), SourceLocation()); } // The missing identifier would have been diagnosed in ParseDirectDeclarator. |