diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp | 397 |
1 files changed, 301 insertions, 96 deletions
diff --git a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp index 73b4f50fda46..cdc3506d5c68 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp @@ -86,8 +86,8 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) { } /// Check if the a start and end source location expand to the same macro. -bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc, - SourceLocation EndLoc) { +static bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc, + SourceLocation EndLoc) { if (!StartLoc.isMacroID() || !EndLoc.isMacroID()) return false; @@ -335,6 +335,7 @@ unsigned Parser::ParseAttributeArgsCommon( ConsumeParen(); bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName); + bool AttributeIsTypeArgAttr = attributeIsTypeArgAttr(*AttrName); // Interpret "kw_this" as an identifier if the attributed requests it. if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) @@ -346,7 +347,7 @@ unsigned Parser::ParseAttributeArgsCommon( bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName) || attributeHasVariadicIdentifierArg(*AttrName); ParsedAttr::Kind AttrKind = - ParsedAttr::getKind(AttrName, ScopeName, Syntax); + ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax); // If we don't know how to parse this attribute, but this is the only // token in this argument, assume it's meant to be an identifier. @@ -360,6 +361,7 @@ unsigned Parser::ParseAttributeArgsCommon( ArgExprs.push_back(ParseIdentifierLoc()); } + ParsedType TheParsedType; if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) { // Eat the comma. if (!ArgExprs.empty()) @@ -372,8 +374,17 @@ unsigned Parser::ParseAttributeArgsCommon( Tok.setKind(tok::identifier); ExprResult ArgExpr; - if (Tok.is(tok::identifier) && - attributeHasVariadicIdentifierArg(*AttrName)) { + if (AttributeIsTypeArgAttr) { + TypeResult T = ParseTypeName(); + if (T.isInvalid()) { + SkipUntil(tok::r_paren, StopAtSemi); + return 0; + } + if (T.isUsable()) + TheParsedType = T.get(); + break; // FIXME: Multiple type arguments are not implemented. + } else if (Tok.is(tok::identifier) && + attributeHasVariadicIdentifierArg(*AttrName)) { ArgExprs.push_back(ParseIdentifierLoc()); } else { bool Uneval = attributeParsedArgsUnevaluated(*AttrName); @@ -397,14 +408,20 @@ unsigned Parser::ParseAttributeArgsCommon( SourceLocation RParen = Tok.getLocation(); if (!ExpectAndConsume(tok::r_paren)) { SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; - Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, - ArgExprs.data(), ArgExprs.size(), Syntax); + + if (AttributeIsTypeArgAttr && !TheParsedType.get().isNull()) { + Attrs.addNewTypeAttr(AttrName, SourceRange(AttrNameLoc, RParen), + ScopeName, ScopeLoc, TheParsedType, Syntax); + } else { + Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, + ArgExprs.data(), ArgExprs.size(), Syntax); + } } if (EndLoc) *EndLoc = RParen; - return static_cast<unsigned>(ArgExprs.size()); + return static_cast<unsigned>(ArgExprs.size() + !TheParsedType.get().isNull()); } /// Parse the arguments to a parameterized GNU attribute or @@ -421,7 +438,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); ParsedAttr::Kind AttrKind = - ParsedAttr::getKind(AttrName, ScopeName, Syntax); + ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax); if (AttrKind == ParsedAttr::AT_Availability) { ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, @@ -471,7 +488,7 @@ unsigned Parser::ParseClangAttributeArgs( assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); ParsedAttr::Kind AttrKind = - ParsedAttr::getKind(AttrName, ScopeName, Syntax); + ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax); switch (AttrKind) { default: @@ -1672,9 +1689,9 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, if (!AL.isCXX11Attribute() && !AL.isC2xAttribute()) continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName(); + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL; else { - Diag(AL.getLoc(), DiagID) << AL.getName(); + Diag(AL.getLoc(), DiagID) << AL; AL.setInvalid(); } } @@ -1724,9 +1741,10 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs, /// [C++11/C11] static_assert-declaration /// others... [FIXME] /// -Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributesWithRange &attrs) { +Parser::DeclGroupPtrTy +Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs, + SourceLocation *DeclSpecStart) { ParenBraceBracketBalancer BalancerRAIIObj(*this); // Must temporarily exit the objective-c container scope for // parsing c none objective-c decls. @@ -1746,8 +1764,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation InlineLoc = ConsumeToken(); return ParseNamespace(Context, DeclEnd, InlineLoc); } - return ParseSimpleDeclaration(Context, DeclEnd, attrs, - true); + return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr, + DeclSpecStart); case tok::kw_namespace: ProhibitAttributes(attrs); return ParseNamespace(Context, DeclEnd); @@ -1760,7 +1778,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: - return ParseSimpleDeclaration(Context, DeclEnd, attrs, true); + return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr, + DeclSpecStart); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -1785,11 +1804,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, /// If FRI is non-null, we might be parsing a for-range-declaration instead /// of a simple-declaration. If we find that we are, we also parse the /// for-range-initializer, and place it here. -Parser::DeclGroupPtrTy -Parser::ParseSimpleDeclaration(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributesWithRange &Attrs, - bool RequireSemi, ForRangeInit *FRI) { +/// +/// DeclSpecStart is used when decl-specifiers are parsed before parsing +/// the Declaration. The SourceLocation for this Decl is set to +/// DeclSpecStart if DeclSpecStart is non-null. +Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributesWithRange &Attrs, bool RequireSemi, ForRangeInit *FRI, + SourceLocation *DeclSpecStart) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); @@ -1819,6 +1841,9 @@ Parser::ParseSimpleDeclaration(DeclaratorContext Context, return Actions.ConvertDeclToDeclGroup(TheDecl); } + if (DeclSpecStart) + DS.SetRangeStart(*DeclSpecStart); + DS.takeAttributesFrom(Attrs); return ParseDeclGroup(DS, Context, &DeclEnd, FRI); } @@ -1989,6 +2014,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, return nullptr; } + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + // Save late-parsed attributes for now; they need to be parsed in the // appropriate function scope after the function Decl has been constructed. // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList. @@ -2075,6 +2103,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, bool IsForRangeLoop = false; if (TryConsumeToken(tok::colon, FRI->ColonLoc)) { IsForRangeLoop = true; + if (getLangOpts().OpenMP) + Actions.startOpenMPCXXRangeFor(); if (Tok.is(tok::l_brace)) FRI->RangeExpr = ParseBraceInitializer(); else @@ -2138,6 +2168,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParseDeclarator(D); if (!D.isInvalidType()) { + // C++2a [dcl.decl]p1 + // init-declarator: + // declarator initializer[opt] + // declarator requires-clause + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); D.complete(ThisDecl); if (ThisDecl) @@ -2170,7 +2206,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, StopBeforeMatch); return true; @@ -2322,7 +2358,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) << 0 /* default */; else - Diag(ConsumeToken(), diag::err_default_special_members); + Diag(ConsumeToken(), diag::err_default_special_members) + << getLangOpts().CPlusPlus2a; } else { InitializerScopeRAII InitScope(*this, D, ThisDecl); @@ -2489,7 +2526,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, // Issue diagnostic and remove constexpr specifier if present. if (DS.hasConstexprSpecifier() && DSC != DeclSpecContext::DSC_condition) { Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr) - << (DS.getConstexprSpecifier() == CSK_consteval); + << DS.getConstexprSpecifier(); DS.ClearConstexprSpec(); } } @@ -2902,28 +2939,30 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, IdentifierInfo *Name = AfterScope.getIdentifierInfo(); Sema::NameClassification Classification = Actions.ClassifyName( getCurScope(), SS, Name, AfterScope.getLocation(), Next, - /*IsAddressOfOperand=*/false, /*CCC=*/nullptr); + /*CCC=*/nullptr); switch (Classification.getKind()) { case Sema::NC_Error: SkipMalformedDecl(); return true; case Sema::NC_Keyword: - case Sema::NC_NestedNameSpecifier: - llvm_unreachable("typo correction and nested name specifiers not " - "possible here"); + llvm_unreachable("typo correction is not possible here"); case Sema::NC_Type: case Sema::NC_TypeTemplate: + case Sema::NC_UndeclaredNonType: + case Sema::NC_UndeclaredTemplate: // Not a previously-declared non-type entity. MightBeDeclarator = false; break; case Sema::NC_Unknown: - case Sema::NC_Expression: + case Sema::NC_NonType: + case Sema::NC_DependentNonType: + case Sema::NC_ContextIndependentExpr: case Sema::NC_VarTemplate: case Sema::NC_FunctionTemplate: - case Sema::NC_UndeclaredTemplate: + case Sema::NC_Concept: // Might be a redeclaration of a prior entity. break; } @@ -3139,7 +3178,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DSContext == DeclSpecContext::DSC_class) && TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) && - isConstructorDeclarator(/*Unqualified*/ false)) { + isConstructorDeclarator(/*Unqualified=*/false)) { // The user meant this to be an out-of-line constructor // definition, but template arguments are not allowed // there. Just allow this as a constructor; we'll @@ -3151,7 +3190,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumeAnnotationToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); - AnnotateTemplateIdTokenAsType(); + AnnotateTemplateIdTokenAsType(SS); + continue; + } + + if (Next.is(tok::annot_template_id) && + static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) + ->Kind == TNK_Concept_template && + GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) { + DS.getTypeSpecScope() = SS; + // This is a qualified placeholder-specifier, e.g., ::C<int> auto ... + // Consume the scope annotation and continue to consume the template-id + // as a placeholder-specifier. + ConsumeAnnotationToken(); continue; } @@ -3197,6 +3248,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the // typename. if (!TypeRep) { + if (TryAnnotateTypeConstraint()) + goto DoneWithDeclSpec; + if (isTypeConstraintAnnotation()) + continue; // Eat the scope spec so the identifier is current. ConsumeAnnotationToken(); ParsedAttributesWithRange Attrs(AttrFactory); @@ -3346,6 +3401,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (!TypeRep) { + if (TryAnnotateTypeConstraint()) + goto DoneWithDeclSpec; + if (isTypeConstraintAnnotation()) + continue; ParsedAttributesWithRange Attrs(AttrFactory); if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { if (!Attrs.empty()) { @@ -3395,9 +3454,51 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } - // type-name + // type-name or placeholder-specifier case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->Kind == TNK_Concept_template) { + if (NextToken().is(tok::identifier)) { + Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto) + << FixItHint::CreateInsertion(NextToken().getLocation(), "auto"); + // Attempt to continue as if 'auto' was placed here. + isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, + TemplateId, Policy); + break; + } + if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype)) + goto DoneWithDeclSpec; + ConsumeAnnotationToken(); + SourceLocation AutoLoc = Tok.getLocation(); + if (TryConsumeToken(tok::kw_decltype)) { + BalancedDelimiterTracker Tracker(*this, tok::l_paren); + if (Tracker.consumeOpen()) { + // Something like `void foo(Iterator decltype i)` + Diag(Tok, diag::err_expected) << tok::l_paren; + } else { + if (!TryConsumeToken(tok::kw_auto)) { + // Something like `void foo(Iterator decltype(int) i)` + Tracker.skipToEnd(); + Diag(Tok, diag::err_placeholder_expected_auto_or_decltype_auto) + << FixItHint::CreateReplacement(SourceRange(AutoLoc, + Tok.getLocation()), + "auto"); + } else { + Tracker.consumeClose(); + } + } + ConsumedEnd = Tok.getLocation(); + // Even if something went wrong above, continue as if we've seen + // `decltype(auto)`. + isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec, + DiagID, TemplateId, Policy); + } else { + isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, + TemplateId, Policy); + } + break; + } + if (TemplateId->Kind != TNK_Type_template && TemplateId->Kind != TNK_Undeclared_template) { // This template-id does not refer to a type name, so we're @@ -3410,12 +3511,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // constructor declaration. if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class && Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) && - isConstructorDeclarator(TemplateId->SS.isEmpty())) + isConstructorDeclarator(/*Unqualified=*/true)) goto DoneWithDeclSpec; // Turn the template-id annotation token into a type annotation // token, then try again to parse it as a type-specifier. - AnnotateTemplateIdTokenAsType(); + CXXScopeSpec SS; + AnnotateTemplateIdTokenAsType(SS); continue; } @@ -3549,6 +3651,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isStorageClass = true; break; case tok::kw__Thread_local: + if (!getLangOpts().C11) + Diag(Tok, diag::ext_c11_feature) << Tok.getName(); isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local, Loc, PrevSpec, DiagID); isStorageClass = true; @@ -3577,7 +3681,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumedEnd = ExplicitLoc; ConsumeToken(); // kw_explicit if (Tok.is(tok::l_paren)) { - if (getLangOpts().CPlusPlus2a) { + if (getLangOpts().CPlusPlus2a || isExplicitBool() == TPResult::True) { + Diag(Tok.getLocation(), getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_explicit_bool + : diag::ext_explicit_bool); + ExprResult ExplicitExpr(static_cast<Expr *>(nullptr)); BalancedDelimiterTracker Tracker(*this, tok::l_paren); Tracker.consumeOpen(); @@ -3590,8 +3698,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get()); } else Tracker.skipToEnd(); - } else + } else { Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool); + } } isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID, ExplicitSpec, CloseParenLoc); @@ -3599,14 +3708,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } case tok::kw__Noreturn: if (!getLangOpts().C11) - Diag(Loc, diag::ext_c11_noreturn); + Diag(Tok, diag::ext_c11_feature) << Tok.getName(); isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID); break; // alignment-specifier case tok::kw__Alignas: if (!getLangOpts().C11) - Diag(Tok, diag::ext_c11_alignment) << Tok.getName(); + Diag(Tok, diag::ext_c11_feature) << Tok.getName(); ParseAlignmentSpecifier(DS.getAttributes()); continue; @@ -3626,15 +3735,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID); break; - // constexpr + // constexpr, consteval, constinit specifiers case tok::kw_constexpr: isInvalid = DS.SetConstexprSpec(CSK_constexpr, Loc, PrevSpec, DiagID); break; - - // consteval case tok::kw_consteval: isInvalid = DS.SetConstexprSpec(CSK_consteval, Loc, PrevSpec, DiagID); break; + case tok::kw_constinit: + isInvalid = DS.SetConstexprSpec(CSK_constinit, Loc, PrevSpec, DiagID); + break; // type-specifier case tok::kw_short: @@ -3662,10 +3772,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DiagID); break; case tok::kw__Complex: + if (!getLangOpts().C99) + Diag(Tok, diag::ext_c99_feature) << Tok.getName(); isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, DiagID); break; case tok::kw__Imaginary: + if (!getLangOpts().C99) + Diag(Tok, diag::ext_c99_feature) << Tok.getName(); isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, DiagID); break; @@ -3746,6 +3860,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; case tok::kw_bool: case tok::kw__Bool: + if (Tok.is(tok::kw__Bool) && !getLangOpts().C99) + Diag(Tok, diag::ext_c99_feature) << Tok.getName(); + if (Tok.is(tok::kw_bool) && DS.getTypeSpecType() != DeclSpec::TST_unspecified && DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { @@ -3889,6 +4006,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // 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(); + if (NextToken().is(tok::l_paren)) { ParseAtomicSpecifier(DS); continue; @@ -3907,9 +4027,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, PrevSpec = Tok.getIdentifierInfo()->getNameStart(); isInvalid = true; break; - }; + } LLVM_FALLTHROUGH; case tok::kw_private: + // It's fine (but redundant) to check this for __generic on the + // fallthrough path; we only form the __generic token in OpenCL mode. + if (!getLangOpts().OpenCL) + goto DoneWithDeclSpec; + LLVM_FALLTHROUGH; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -4081,7 +4206,7 @@ void Parser::ParseStructDeclaration( /// [OBC] '@' 'defs' '(' class-name ')' /// void Parser::ParseStructUnionBody(SourceLocation RecordLoc, - unsigned TagType, Decl *TagDecl) { + DeclSpec::TST TagType, Decl *TagDecl) { PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc, "parsing struct/union body"); assert(!getLangOpts().CPlusPlus && "C++ declarations not supported"); @@ -4131,6 +4256,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } + if (tok::isPragmaAnnotation(Tok.getKind())) { + Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl) + << DeclSpec::getSpecifierName( + TagType, Actions.getASTContext().getPrintingPolicy()); + ConsumeAnnotationToken(); + continue; + } + if (!Tok.is(tok::at)) { auto CFieldCallback = [&](ParsingFieldDeclarator &FD) { // Install the declarator into the current TagDecl. @@ -4632,8 +4765,10 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { ExprResult AssignedVal; EnumAvailabilityDiags.emplace_back(*this); + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); if (TryConsumeToken(tok::equal, EqualLoc)) { - AssignedVal = ParseConstantExpression(); + AssignedVal = ParseConstantExpressionInExprEvalContext(); if (AssignedVal.isInvalid()) SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch); } @@ -4925,6 +5060,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return true; + if (TryAnnotateTypeConstraint()) + return true; if (Tok.is(tok::identifier)) return false; @@ -5038,8 +5175,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::annot_decltype: case tok::kw_constexpr: - // C++20 consteval. + // C++20 consteval and constinit. case tok::kw_consteval: + case tok::kw_constinit: // C11 _Atomic case tok::kw__Atomic: @@ -5054,6 +5192,16 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { return !DisambiguatingWithExpression || !isStartOfObjCClassMessageMissingOpenBracket(); + // placeholder-type-specifier + case tok::annot_template_id: { + return isTypeConstraintAnnotation() && + (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype)); + } + case tok::annot_cxxscope: + if (NextToken().is(tok::identifier) && TryAnnotateTypeConstraint()) + return true; + return isTypeConstraintAnnotation() && + GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype); case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: @@ -5286,6 +5434,8 @@ void Parser::ParseTypeQualifierListOpt( case tok::kw__Atomic: if (!AtomicAllowed) goto DoneWithTypeQuals; + if (!getLangOpts().C11) + Diag(Tok, diag::ext_c11_feature) << Tok.getName(); isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID, getLangOpts()); break; @@ -5945,11 +6095,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) { while (1) { if (Tok.is(tok::l_paren)) { + bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration(); // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope| - (D.isFunctionDeclaratorAFunctionDeclaration() + (IsFunctionDeclaration ? Scope::FunctionDeclarationScope : 0)); // The paren may be part of a C++ direct initializer, eg. "int x(1);". @@ -5968,10 +6119,31 @@ void Parser::ParseDirectDeclarator(Declarator &D) { ParsedAttributes attrs(AttrFactory); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); + if (IsFunctionDeclaration) + Actions.ActOnStartFunctionDeclarationDeclarator(D, + TemplateParameterDepth); ParseFunctionDeclarator(D, attrs, T, IsAmbiguous); + if (IsFunctionDeclaration) + Actions.ActOnFinishFunctionDeclarationDeclarator(D); PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); + } else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) { + // This declarator is declaring a function, but the requires clause is + // in the wrong place: + // void (f() requires true); + // instead of + // void f() requires true; + // or + // void (f()) requires true; + Diag(Tok, diag::err_requires_clause_inside_parens); + ConsumeToken(); + ExprResult TrailingRequiresClause = Actions.CorrectDelayedTyposInExpr( + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true)); + if (TrailingRequiresClause.isUsable() && D.isFunctionDeclarator() && + !D.hasTrailingRequiresClause()) + // We're already ill-formed if we got here but we'll accept it anyway. + D.setTrailingRequiresClause(TrailingRequiresClause.get()); } else { break; } @@ -6152,6 +6324,47 @@ void Parser::ParseParenDeclarator(Declarator &D) { PrototypeScope.Exit(); } +void Parser::InitCXXThisScopeForDeclaratorIfRelevant( + const Declarator &D, const DeclSpec &DS, + llvm::Optional<Sema::CXXThisScopeRAII> &ThisScope) { + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + // FIXME: currently, "static" case isn't handled correctly. + bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + (D.getContext() == DeclaratorContext::MemberContext + ? !D.getDeclSpec().isFriendSpecified() + : D.getContext() == DeclaratorContext::FileContext && + D.getCXXScopeSpec().isValid() && + Actions.CurContext->isRecord()); + if (!IsCXX11MemberFunction) + return; + + Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); + if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14) + Q.addConst(); + // FIXME: Collect C++ address spaces. + // If there are multiple different address spaces, the source is invalid. + // Carry on using the first addr space for the qualifiers of 'this'. + // The diagnostic will be given later while creating the function + // prototype for the method. + if (getLangOpts().OpenCLCPlusPlus) { + for (ParsedAttr &attr : DS.getAttributes()) { + LangAS ASIdx = attr.asOpenCLLangAS(); + if (ASIdx != LangAS::Default) { + Q.addAddressSpace(ASIdx); + break; + } + } + } + ThisScope.emplace(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q, + IsCXX11MemberFunction); +} + /// ParseFunctionDeclarator - We are after the identifier and have parsed the /// declarator D up to a paren, which indicates that we are parsing function /// arguments. @@ -6165,7 +6378,8 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// /// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt], /// (C++11) ref-qualifier[opt], exception-specification[opt], -/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt]. +/// (C++11) attribute-specifier-seq[opt], (C++11) trailing-return-type[opt] and +/// (C++2a) the trailing requires-clause. /// /// [C++11] exception-specification: /// dynamic-exception-specification @@ -6226,7 +6440,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, ProhibitAttributes(FnAttrs); } else { if (Tok.isNot(tok::r_paren)) - ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, + ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo, EllipsisLoc); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); @@ -6260,43 +6474,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) EndLoc = RefQualifierLoc; - // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type - // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or - // declarator. - // FIXME: currently, "static" case isn't handled correctly. - bool IsCXX11MemberFunction = - getLangOpts().CPlusPlus11 && - D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && - (D.getContext() == DeclaratorContext::MemberContext - ? !D.getDeclSpec().isFriendSpecified() - : D.getContext() == DeclaratorContext::FileContext && - D.getCXXScopeSpec().isValid() && - Actions.CurContext->isRecord()); - - Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); - if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14) - Q.addConst(); - // FIXME: Collect C++ address spaces. - // If there are multiple different address spaces, the source is invalid. - // Carry on using the first addr space for the qualifiers of 'this'. - // The diagnostic will be given later while creating the function - // prototype for the method. - if (getLangOpts().OpenCLCPlusPlus) { - for (ParsedAttr &attr : DS.getAttributes()) { - LangAS ASIdx = attr.asOpenCLLangAS(); - if (ASIdx != LangAS::Default) { - Q.addAddressSpace(ASIdx); - break; - } - } - } - - Sema::CXXThisScopeRAII ThisScope( - Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q, - IsCXX11MemberFunction); + llvm::Optional<Sema::CXXThisScopeRAII> ThisScope; + InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope); // Parse exception-specification[opt]. bool Delayed = D.isFirstDeclarationOfMember() && @@ -6479,9 +6658,9 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// after the opening parenthesis. This function will not parse a K&R-style /// identifier list. /// -/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the -/// caller parsed those arguments immediately after the open paren - they should -/// be considered to be part of the first parameter. +/// DeclContext is the context of the declarator being parsed. If FirstArgAttrs +/// is non-null, then the caller parsed those attributes immediately after the +/// open paren - they should be considered to be part of the first parameter. /// /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will /// be the location of the ellipsis, if any was parsed. @@ -6507,10 +6686,23 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// [C++11] attribute-specifier-seq parameter-declaration /// void Parser::ParseParameterDeclarationClause( - Declarator &D, + DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc) { + + // Avoid exceeding the maximum function scope depth. + // See https://bugs.llvm.org/show_bug.cgi?id=19607 + // Note Sema::ActOnParamDeclarator calls ParmVarDecl::setScopeInfo with + // getFunctionPrototypeDepth() - 1. + if (getCurScope()->getFunctionPrototypeDepth() - 1 > + ParmVarDecl::getMaxFunctionScopeDepth()) { + Diag(Tok.getLocation(), diag::err_function_scope_depth_exceeded) + << ParmVarDecl::getMaxFunctionScopeDepth(); + cutOffParsing(); + return; + } + do { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq // before deciding this was a parameter-declaration-clause. @@ -6543,14 +6735,27 @@ void Parser::ParseParameterDeclarationClause( // "LambdaExprParameterContext", because we must accept either // 'declarator' or 'abstract-declarator' here. Declarator ParmDeclarator( - DS, D.getContext() == DeclaratorContext::LambdaExprContext - ? DeclaratorContext::LambdaExprParameterContext - : DeclaratorContext::PrototypeContext); + DS, DeclaratorCtx == DeclaratorContext::RequiresExprContext + ? DeclaratorContext::RequiresExprContext + : DeclaratorCtx == DeclaratorContext::LambdaExprContext + ? DeclaratorContext::LambdaExprParameterContext + : DeclaratorContext::PrototypeContext); ParseDeclarator(ParmDeclarator); // Parse GNU attributes, if present. MaybeParseGNUAttributes(ParmDeclarator); + if (Tok.is(tok::kw_requires)) { + // User tried to define a requires clause in a parameter declaration, + // which is surely not a function declaration. + // void f(int (*g)(int, int) requires true); + Diag(Tok, + diag::err_requires_clause_on_declarator_not_declaring_a_function); + ConsumeToken(); + Actions.CorrectDelayedTyposInExpr( + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true)); + } + // Remember this parsed parameter in ParamInfo. IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); @@ -6588,7 +6793,7 @@ void Parser::ParseParameterDeclarationClause( SourceLocation EqualLoc = Tok.getLocation(); // Parse the default argument - if (D.getContext() == DeclaratorContext::MemberContext) { + if (DeclaratorCtx == DeclaratorContext::MemberContext) { // If we're inside a class definition, cache the tokens // corresponding to the default argument. We'll actually parse // them when we see the end of the class definition. |
