diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib/Parse/ParseDecl.cpp | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) |
Diffstat (limited to 'clang/lib/Parse/ParseDecl.cpp')
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 414 |
1 files changed, 303 insertions, 111 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index aef9909a7c97..c7fd1156928c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -25,10 +25,10 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaDiagnostic.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" +#include <optional> using namespace clang; @@ -449,10 +449,8 @@ unsigned Parser::ParseAttributeArgsCommon( ? Sema::ExpressionEvaluationContext::Unevaluated : Sema::ExpressionEvaluationContext::ConstantEvaluated); - CommaLocsTy CommaLocs; ExprVector ParsedExprs; - if (ParseExpressionList(ParsedExprs, CommaLocs, - llvm::function_ref<void()>(), + if (ParseExpressionList(ParsedExprs, llvm::function_ref<void()>(), /*FailImmediatelyOnInvalidExpr=*/true, /*EarlyTypoCorrection=*/true)) { SkipUntil(tok::r_paren, StopAtSemi); @@ -536,7 +534,7 @@ void Parser::ParseGNUAttributeArgs( // These may refer to the function arguments, but need to be parsed early to // participate in determining whether it's a redeclaration. - llvm::Optional<ParseScope> PrototypeScope; + std::optional<ParseScope> PrototypeScope; if (normalizeAttrName(AttrName->getName()) == "enable_if" && D && D->isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo(); @@ -914,6 +912,17 @@ void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) { ParsedAttr::AS_Keyword); } +bool Parser::isHLSLQualifier(const Token &Tok) const { + return Tok.is(tok::kw_groupshared); +} + +void Parser::ParseHLSLQualifiers(ParsedAttributes &Attrs) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + ParsedAttr::AS_Keyword); +} + void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { // Treat these like attributes, even though they're type specifiers. while (true) { @@ -1417,7 +1426,7 @@ void Parser::ParseExternalSourceSymbolAttribute( ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(), GeneratedDeclaration}; Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()), - ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax); + ScopeName, ScopeLoc, Args, std::size(Args), Syntax); } /// Parse the contents of the "objc_bridge_related" attribute. @@ -1538,7 +1547,7 @@ void Parser::ParseSwiftNewTypeAttribute( ArgsUnion Args[] = {SwiftType}; Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, T.getCloseLocation()), - ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax); + ScopeName, ScopeLoc, Args, std::size(Args), Syntax); } void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, @@ -1680,7 +1689,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID, Lexer::getRawToken(Attrs.Range.getBegin(), FirstLSquare, SM, LangOpts); if (FirstLSquare.is(tok::l_square)) { - llvm::Optional<Token> SecondLSquare = + std::optional<Token> SecondLSquare = Lexer::findNextToken(FirstLSquare.getLocation(), SM, LangOpts); if (SecondLSquare && SecondLSquare->is(tok::l_square)) { @@ -1787,6 +1796,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, } return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs, true, nullptr, DeclSpecStart); + + case tok::kw_cbuffer: + case tok::kw_tbuffer: + SingleDecl = ParseHLSLBuffer(DeclEnd); + break; case tok::kw_namespace: ProhibitAttributes(DeclAttrs); ProhibitAttributes(DeclSpecAttrs); @@ -2049,6 +2063,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, return nullptr; } + if (getLangOpts().HLSL) + MaybeParseHLSLSemantics(D); + if (Tok.is(tok::kw_requires)) ParseTrailingRequiresClause(D); @@ -2078,10 +2095,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, << (Fixit ? FixItHint::CreateInsertion(D.getBeginLoc(), "_Noreturn ") : FixItHint()); } - } - // Check to see if we have a function *definition* which must have a body. - if (D.isFunctionDeclarator()) { + // 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); @@ -2121,7 +2136,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, return Actions.ConvertDeclToDeclGroup(TheDecl); } - if (isDeclarationSpecifier()) { + if (isDeclarationSpecifier(ImplicitTypenameContext::No)) { // If there is an invalid declaration specifier right after the // function prototype, then we must be in a missing semicolon case // where this isn't actually a body. Just fall through into the code @@ -2220,6 +2235,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DiagnoseAndSkipExtendedMicrosoftTypeAttributes(); ParseDeclarator(D); + + if (getLangOpts().HLSL) + MaybeParseHLSLSemantics(D); + if (!D.isInvalidType()) { // C++2a [dcl.decl]p1 // init-declarator: @@ -2244,7 +2263,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Okay, there was no semicolon and one was expected. If we see a // declaration specifier, just assume it was missing and continue parsing. // Otherwise things are very confused and we skip to recover. - if (!isDeclarationSpecifier()) { + if (!isDeclarationSpecifier(ImplicitTypenameContext::No)) { SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); TryConsumeToken(tok::semi); } @@ -2402,8 +2421,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( // Recover as if it were an explicit specialization. TemplateParameterLists FakedParamLists; FakedParamLists.push_back(Actions.ActOnTemplateParameterList( - 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None, - LAngleLoc, nullptr)); + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, + std::nullopt, LAngleLoc, nullptr)); ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D); @@ -2478,7 +2497,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( T.consumeOpen(); ExprVector Exprs; - CommaLocsTy CommaLocs; InitializerScopeRAII InitScope(*this, D, ThisDecl); @@ -2503,7 +2521,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( // ProduceConstructorSignatureHelp only on VarDecls. ExpressionStarts = SetPreferredType; } - if (ParseExpressionList(Exprs, CommaLocs, ExpressionStarts)) { + if (ParseExpressionList(Exprs, ExpressionStarts)) { if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) { Actions.ProduceConstructorSignatureHelp( ThisVarDecl->getType()->getCanonicalTypeInternal(), @@ -2516,10 +2534,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } else { // Match the ')'. T.consumeClose(); - - assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && - "Unexpected number of commas!"); - InitScope.pop(); ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), @@ -2563,12 +2577,14 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( /// type-qualifier specifier-qualifier-list[opt] /// [GNU] attributes specifier-qualifier-list[opt] /// -void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, - DeclSpecContext DSC) { +void Parser::ParseSpecifierQualifierList( + DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename, + AccessSpecifier AS, DeclSpecContext DSC) { /// 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); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC, nullptr, + AllowImplicitTypename); // Validate declspec for type-name. unsigned Specs = DS.getParsedSpecifiers(); @@ -2599,6 +2615,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec); if (DS.hasExplicitSpecifier()) Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec); + if (DS.isNoreturnSpecified()) + Diag(DS.getNoreturnSpecLoc(), diag::err_typename_invalid_functionspec); DS.ClearFunctionSpecs(); } @@ -2800,7 +2818,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, } } // Fall through. - LLVM_FALLTHROUGH; + [[fallthrough]]; } case tok::comma: case tok::equal: @@ -2876,24 +2894,50 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, /// DeclaratorContext enumerator values. Parser::DeclSpecContext Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) { - if (Context == DeclaratorContext::Member) + switch (Context) { + case DeclaratorContext::Member: return DeclSpecContext::DSC_class; - if (Context == DeclaratorContext::File) + case DeclaratorContext::File: return DeclSpecContext::DSC_top_level; - if (Context == DeclaratorContext::TemplateParam) + case DeclaratorContext::TemplateParam: return DeclSpecContext::DSC_template_param; - if (Context == DeclaratorContext::TemplateArg || - Context == DeclaratorContext::TemplateTypeArg) + case DeclaratorContext::TemplateArg: + return DeclSpecContext::DSC_template_arg; + case DeclaratorContext::TemplateTypeArg: return DeclSpecContext::DSC_template_type_arg; - if (Context == DeclaratorContext::TrailingReturn || - Context == DeclaratorContext::TrailingReturnVar) + case DeclaratorContext::TrailingReturn: + case DeclaratorContext::TrailingReturnVar: return DeclSpecContext::DSC_trailing; - if (Context == DeclaratorContext::AliasDecl || - Context == DeclaratorContext::AliasTemplate) + case DeclaratorContext::AliasDecl: + case DeclaratorContext::AliasTemplate: return DeclSpecContext::DSC_alias_declaration; - if (Context == DeclaratorContext::Association) + case DeclaratorContext::Association: return DeclSpecContext::DSC_association; - return DeclSpecContext::DSC_normal; + case DeclaratorContext::TypeName: + return DeclSpecContext::DSC_type_specifier; + case DeclaratorContext::Condition: + return DeclSpecContext::DSC_condition; + case DeclaratorContext::ConversionId: + return DeclSpecContext::DSC_conv_operator; + case DeclaratorContext::Prototype: + case DeclaratorContext::ObjCResult: + case DeclaratorContext::ObjCParameter: + case DeclaratorContext::KNRTypeList: + case DeclaratorContext::FunctionalCast: + case DeclaratorContext::Block: + case DeclaratorContext::ForInit: + case DeclaratorContext::SelectionInit: + case DeclaratorContext::CXXNew: + case DeclaratorContext::CXXCatch: + case DeclaratorContext::ObjCCatch: + case DeclaratorContext::BlockLiteral: + case DeclaratorContext::LambdaExpr: + case DeclaratorContext::LambdaExprParameter: + case DeclaratorContext::RequiresExpr: + return DeclSpecContext::DSC_normal; + } + + llvm_unreachable("Missing DeclaratorContext case"); } /// ParseAlignArgument - Parse the argument to an alignment-specifier. @@ -3129,11 +3173,10 @@ static void SetupFixedPointError(const LangOptions &LangOpts, /// [OpenCL] '__kernel' /// 'friend': [C++ dcl.friend] /// 'constexpr': [C++0x dcl.constexpr] -void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, - const ParsedTemplateInfo &TemplateInfo, - AccessSpecifier AS, - DeclSpecContext DSContext, - LateParsedAttrList *LateAttrs) { +void Parser::ParseDeclarationSpecifiers( + DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, + DeclSpecContext DSContext, LateParsedAttrList *LateAttrs, + ImplicitTypenameContext AllowImplicitTypename) { if (DS.getSourceRange().isInvalid()) { // Start the range at the current token but make the end of the range // invalid. This will make the entire range invalid unless we successfully @@ -3142,6 +3185,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(SourceLocation()); } + // If we are in a operator context, convert it back into a type specifier + // context for better error handling later on. + if (DSContext == DeclSpecContext::DSC_conv_operator) { + // No implicit typename here. + AllowImplicitTypename = ImplicitTypenameContext::No; + DSContext = DeclSpecContext::DSC_type_specifier; + } + bool EnteringContext = (DSContext == DeclSpecContext::DSC_class || DSContext == DeclSpecContext::DSC_top_level); bool AttrsLastTime = false; @@ -3266,13 +3317,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, return; } - if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) - CCC = Sema::PCC_LocalDeclarationSpecifiers; - else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) + // 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; else if (DSContext == DeclSpecContext::DSC_class) CCC = Sema::PCC_Class; + else if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) + CCC = Sema::PCC_LocalDeclarationSpecifiers; else if (CurParsedObjCImpl) CCC = Sema::PCC_ObjCImplementation; @@ -3329,7 +3381,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DSContext == DeclSpecContext::DSC_class) && TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) && - isConstructorDeclarator(/*Unqualified=*/false)) { + isConstructorDeclarator(/*Unqualified=*/false, + /*DeductionGuide=*/false, + DS.isFriendSpecified())) { // 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 @@ -3341,7 +3395,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumeAnnotationToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); - AnnotateTemplateIdTokenAsType(SS); + AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename); continue; } @@ -3368,6 +3422,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumeAnnotationToken(); // The typename } + if (AllowImplicitTypename == ImplicitTypenameContext::Yes && + Next.is(tok::annot_template_id) && + static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) + ->Kind == TNK_Dependent_template_name) { + DS.getTypeSpecScope() = SS; + ConsumeAnnotationToken(); // The C++ scope. + AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename); + continue; + } + if (Next.isNot(tok::identifier)) goto DoneWithDeclSpec; @@ -3378,7 +3442,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DSContext == DeclSpecContext::DSC_class) && Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(), &SS) && - isConstructorDeclarator(/*Unqualified*/ false)) + isConstructorDeclarator(/*Unqualified=*/false, + /*DeductionGuide=*/false, + DS.isFriendSpecified())) goto DoneWithDeclSpec; // C++20 [temp.spec] 13.9/6. @@ -3387,12 +3453,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // - `return type`. SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); - ParsedType TypeRep = - Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), - getCurScope(), &SS, false, false, nullptr, - /*IsCtorOrDtorName=*/false, - /*WantNontrivialTypeSourceInfo=*/true, - isClassTemplateDeductionContext(DSContext)); + ParsedType TypeRep = Actions.getTypeName( + *Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS, + false, false, nullptr, + /*IsCtorOrDtorName=*/false, + /*WantNontrivialTypeSourceInfo=*/true, + isClassTemplateDeductionContext(DSContext), AllowImplicitTypename); if (IsTemplateSpecOrInst) SAC.done(); @@ -3471,7 +3537,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // typedef-name case tok::kw___super: case tok::kw_decltype: - case tok::identifier: { + case tok::identifier: + ParseIdentifier: { // This identifier can only be a typedef name if we haven't already seen // a type-specifier. Without this check we misparse: // typedef int X; struct Y { short X; }; as 'short int'. @@ -3555,7 +3622,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // check whether this is a constructor declaration. if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class && Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) && - isConstructorDeclarator(/*Unqualified*/true)) + isConstructorDeclarator(/*Unqualified=*/true, + /*DeductionGuide=*/false, + DS.isFriendSpecified())) goto DoneWithDeclSpec; ParsedType TypeRep = Actions.getTypeName( @@ -3630,11 +3699,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (TemplateId->Kind == TNK_Concept_template) { // If we've already diagnosed that this type-constraint has invalid - // arguemnts, drop it and just form 'auto' or 'decltype(auto)'. + // arguments, drop it and just form 'auto' or 'decltype(auto)'. if (TemplateId->hasInvalidArgs()) TemplateId = nullptr; - if (NextToken().is(tok::identifier)) { + // Any of the following tokens are likely the start of the user + // forgetting 'auto' or 'decltype(auto)', so diagnose. + // Note: if updating this list, please make sure we update + // isCXXDeclarationSpecifier's check for IsPlaceholderSpecifier to have + // a matching list. + if (NextToken().isOneOf(tok::identifier, tok::kw_const, + tok::kw_volatile, tok::kw_restrict, tok::amp, + tok::ampamp)) { Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto) << FixItHint::CreateInsertion(NextToken().getLocation(), "auto"); // Attempt to continue as if 'auto' was placed here. @@ -3664,7 +3740,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } } ConsumedEnd = Tok.getLocation(); - DS.setTypeofParensRange(Tracker.getRange()); + DS.setTypeArgumentRange(Tracker.getRange()); // Even if something went wrong above, continue as if we've seen // `decltype(auto)`. isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec, @@ -3688,13 +3764,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // constructor declaration. if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class && Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) && - isConstructorDeclarator(/*Unqualified=*/true)) + isConstructorDeclarator(/*Unqualified=*/true, + /*DeductionGuide=*/false, + DS.isFriendSpecified())) goto DoneWithDeclSpec; // Turn the template-id annotation token into a type annotation // token, then try again to parse it as a type-specifier. CXXScopeSpec SS; - AnnotateTemplateIdTokenAsType(SS); + AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename); continue; } @@ -4181,8 +4259,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; break; - // GNU typeof support. + // C2x/GNU typeof support. case tok::kw_typeof: + case tok::kw_typeof_unqual: ParseTypeofSpecifier(DS); continue; @@ -4206,8 +4285,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, HandlePragmaMSPointersToMembers(); continue; - case tok::kw___underlying_type: - ParseUnderlyingTypeSpecifier(DS); +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" + // HACK: libstdc++ already uses '__remove_cv' as an alias template so we + // work around this by expecting all transform type traits to be suffixed + // with '('. They're an identifier otherwise. + if (!MaybeParseTypeTransformTypeSpecifier(DS)) + goto ParseIdentifier; continue; case tok::kw__Atomic: @@ -4238,13 +4322,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = true; break; } - LLVM_FALLTHROUGH; + [[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; + [[fallthrough]]; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -4256,6 +4340,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseOpenCLQualifiers(DS.getAttributes()); break; + case tok::kw_groupshared: + // NOTE: ParseHLSLQualifiers will consume the qualifier token. + ParseHLSLQualifiers(DS.getAttributes()); + continue; + case tok::less: // GCC ObjC supports types like "<SomeProtocol>" as a synonym for // "id<SomeProtocol>". This is hopelessly old fashioned and dangerous, @@ -4581,6 +4670,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // Code completion for an enum name. cutOffParsing(); Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum); + DS.SetTypeSpecError(); // Needed by ActOnUsingDeclaration. return; } @@ -4640,6 +4730,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Spec.isSet() && Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; + DS.SetTypeSpecError(); if (Tok.isNot(tok::l_brace)) { // Has no name and is not a definition. // Skip the rest of this declarator, up until the comma or semicolon. @@ -4656,6 +4747,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Tok.isNot(tok::colon)) { Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace; + DS.SetTypeSpecError(); // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, StopAtSemi); return; @@ -4727,7 +4819,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // enum E : int *p; // declares 'enum E : int; E *p;' not 'enum E : int*; E p;'. DeclSpec DS(AttrFactory); - ParseSpecifierQualifierList(DS, AS, DeclSpecContext::DSC_type_specifier); + // enum-base is not assumed to be a type and therefore requires the + // typename keyword [p0634r3]. + ParseSpecifierQualifierList(DS, ImplicitTypenameContext::No, AS, + DeclSpecContext::DSC_type_specifier); Declarator DeclaratorInfo(DS, ParsedAttributesView::none(), DeclaratorContext::TypeName); BaseType = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); @@ -4831,6 +4926,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (!Name && TUK != Sema::TUK_Definition) { Diag(Tok, diag::err_enumerator_unnamed_no_def); + DS.SetTypeSpecError(); // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, StopAtSemi); return; @@ -4869,14 +4965,16 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, bool IsDependent = false; const char *PrevSpec = nullptr; unsigned DiagID; - Decl *TagDecl = Actions.ActOnTag( - getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, - attrs, AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, - ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType, - DSC == DeclSpecContext::DSC_type_specifier, - DSC == DeclSpecContext::DSC_template_param || - DSC == DeclSpecContext::DSC_template_type_arg, - &SkipBody); + UsingShadowDecl* FoundUsing = nullptr; + Decl *TagDecl = + Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, + Name, NameLoc, attrs, AS, DS.getModulePrivateSpecLoc(), + TParams, Owned, IsDependent, ScopedEnumKWLoc, + IsScopedUsingClassTag, + BaseType, DSC == DeclSpecContext::DSC_type_specifier, + DSC == DeclSpecContext::DSC_template_param || + DSC == DeclSpecContext::DSC_template_type_arg, + OffsetOfState, FoundUsing, &SkipBody).get(); if (SkipBody.ShouldSkip) { assert(TUK == Sema::TUK_Definition && "can only skip a definition"); @@ -4886,8 +4984,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, T.skipToEnd(); if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, - NameLoc.isValid() ? NameLoc : StartLoc, - PrevSpec, DiagID, TagDecl, Owned, + NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, + DiagID, FoundUsing ? FoundUsing : TagDecl, Owned, Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; return; @@ -4941,8 +5039,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, - NameLoc.isValid() ? NameLoc : StartLoc, - PrevSpec, DiagID, TagDecl, Owned, + NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, + DiagID, FoundUsing ? FoundUsing : TagDecl, Owned, Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; } @@ -5159,7 +5257,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::identifier: // foo::bar if (TryAltiVecVectorToken()) return true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. @@ -5180,8 +5278,9 @@ bool Parser::isTypeSpecifierQualifier() { // GNU attributes support. case tok::kw___attribute: - // GNU typeof support. + // C2x/GNU typeof support. case tok::kw_typeof: + case tok::kw_typeof_unqual: // type-specifiers case tok::kw_short: @@ -5271,6 +5370,8 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___read_only: case tok::kw___read_write: case tok::kw___write_only: + + case tok::kw_groupshared: return true; case tok::kw_private: @@ -5282,12 +5383,35 @@ bool Parser::isTypeSpecifierQualifier() { } } +Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() { + assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode"); + + // Parse a top-level-stmt. + Parser::StmtVector Stmts; + ParsedStmtContext SubStmtCtx = ParsedStmtContext(); + StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); + if (!R.isUsable()) + return nullptr; + + SmallVector<Decl *, 2> DeclsInGroup; + DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(R.get())); + // Currently happens for things like -fms-extensions and use `__if_exists`. + for (Stmt *S : Stmts) + DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(S)); + + return Actions.BuildDeclaratorGroup(DeclsInGroup); +} + /// isDeclarationSpecifier() - Return true if the current token is part of a /// declaration specifier. /// +/// \param AllowImplicitTypename whether this is a context where T::type [T +/// dependent] can appear. /// \param DisambiguatingWithExpression True to indicate that the purpose of /// this check is to disambiguate between an expression and a declaration. -bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { +bool Parser::isDeclarationSpecifier( + ImplicitTypenameContext AllowImplicitTypename, + bool DisambiguatingWithExpression) { switch (Tok.getKind()) { default: return false; @@ -5302,12 +5426,12 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { return false; if (TryAltiVecVectorToken()) return true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case tok::kw_decltype: // decltype(T())::type case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename)) return true; if (TryAnnotateTypeConstraint()) return true; @@ -5323,9 +5447,11 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { isStartOfObjCClassMessageMissingOpenBracket()) return false; - return isDeclarationSpecifier(); + return isDeclarationSpecifier(AllowImplicitTypename); case tok::coloncolon: // ::foo::bar + if (!getLangOpts().CPlusPlus) + return false; if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; @@ -5334,7 +5460,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return true; - return isDeclarationSpecifier(); + return isDeclarationSpecifier(ImplicitTypenameContext::No); // storage-class-specifier case tok::kw_typedef: @@ -5419,8 +5545,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_static_assert: case tok::kw__Static_assert: - // GNU typeof support. + // C2x/GNU typeof support. case tok::kw_typeof: + case tok::kw_typeof_unqual: // GNU attributes. case tok::kw___attribute: @@ -5506,6 +5633,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" + case tok::kw_groupshared: return true; case tok::kw_private: @@ -5513,7 +5641,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { } } -bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) { +bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide, + DeclSpec::FriendSpecified IsFriend) { TentativeParsingAction TPA(*this); // Parse the C++ scope specifier. @@ -5577,8 +5706,11 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) { // Check whether the next token(s) are part of a declaration // specifier, in which case we have the start of a parameter and, // therefore, we know that this is a constructor. + // Due to an ambiguity with implicit typename, the above is not enough. + // Additionally, check to see if we are a friend. bool IsConstructor = false; - if (isDeclarationSpecifier()) + if (isDeclarationSpecifier(IsFriend ? ImplicitTypenameContext::No + : ImplicitTypenameContext::Yes)) IsConstructor = true; else if (Tok.is(tok::identifier) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) { @@ -5667,7 +5799,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) { void Parser::ParseTypeQualifierListOpt( DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed, bool IdentifierRequired, - Optional<llvm::function_ref<void()>> CodeCompletionHandler) { + std::optional<llvm::function_ref<void()>> CodeCompletionHandler) { if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) && isCXX11AttributeSpecifier()) { ParsedAttributes Attrs(AttrFactory); @@ -5717,7 +5849,7 @@ void Parser::ParseTypeQualifierListOpt( case tok::kw_private: if (!getLangOpts().OpenCL) goto DoneWithTypeQuals; - LLVM_FALLTHROUGH; + [[fallthrough]]; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -5729,6 +5861,11 @@ void Parser::ParseTypeQualifierListOpt( ParseOpenCLQualifiers(DS.getAttributes()); break; + case tok::kw_groupshared: + // NOTE: ParseHLSLQualifiers will consume the qualifier token. + ParseHLSLQualifiers(DS.getAttributes()); + continue; + case tok::kw___unaligned: isInvalid = DS.SetTypeQual(DeclSpec::TQ_unaligned, Loc, PrevSpec, DiagID, getLangOpts()); @@ -5741,7 +5878,7 @@ void Parser::ParseTypeQualifierListOpt( if (TryKeywordIdentFallback(false)) continue; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case tok::kw___sptr: case tok::kw___w64: case tok::kw___ptr64: @@ -5792,7 +5929,7 @@ void Parser::ParseTypeQualifierListOpt( continue; // do *not* consume the next token! } // otherwise, FALL THROUGH! - LLVM_FALLTHROUGH; + [[fallthrough]]; default: DoneWithTypeQuals: // If this is not a type-qualifier token, we're done reading type @@ -6393,10 +6530,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // is not, the declarator has been fully parsed. bool IsAmbiguous = false; if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + // C++2a [temp.res]p5 + // A qualified-id is assumed to name a type if + // - [...] + // - it is a decl-specifier of the decl-specifier-seq of a + // - [...] + // - parameter-declaration in a member-declaration [...] + // - parameter-declaration in a declarator of a function or function + // template declaration whose declarator-id is qualified [...] + auto AllowImplicitTypename = ImplicitTypenameContext::No; + if (D.getCXXScopeSpec().isSet()) + AllowImplicitTypename = + (ImplicitTypenameContext)Actions.isDeclaratorFunctionLike(D); + else if (D.getContext() == DeclaratorContext::Member) { + AllowImplicitTypename = ImplicitTypenameContext::Yes; + } + // The name of the declarator, if any, is tentatively declared within // a possible direct initializer. TentativelyDeclaredIdentifiers.push_back(D.getIdentifier()); - bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous); + bool IsFunctionDecl = + isCXXFunctionDeclarator(&IsAmbiguous, AllowImplicitTypename); TentativelyDeclaredIdentifiers.pop_back(); if (!IsFunctionDecl) break; @@ -6555,11 +6709,12 @@ void Parser::ParseParenDeclarator(Declarator &D) { // If this can't be an abstract-declarator, this *must* be a grouping // paren, because we haven't seen the identifier yet. isGrouping = true; - } else if (Tok.is(tok::r_paren) || // 'int()' is a function. + } else if (Tok.is(tok::r_paren) || // 'int()' is a function. (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || // C++ int(...) - isDeclarationSpecifier() || // 'int(int)' is a function. - isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function. + isDeclarationSpecifier( + ImplicitTypenameContext::No) || // 'int(int)' is a function. + isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function. // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is // considered to be a type, not a K&R identifier-list. isGrouping = false; @@ -6611,7 +6766,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { void Parser::InitCXXThisScopeForDeclaratorIfRelevant( const Declarator &D, const DeclSpec &DS, - llvm::Optional<Sema::CXXThisScopeRAII> &ThisScope) { + std::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 @@ -6727,8 +6882,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, ProhibitAttributes(FnAttrs); } else { if (Tok.isNot(tok::r_paren)) - ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo, - EllipsisLoc); + ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); @@ -6764,7 +6918,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) EndLoc = RefQualifierLoc; - llvm::Optional<Sema::CXXThisScopeRAII> ThisScope; + std::optional<Sema::CXXThisScopeRAII> ThisScope; InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope); // Parse exception-specification[opt]. @@ -6987,7 +7141,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList( void Parser::ParseParameterDeclarationClause( DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, - SourceLocation &EllipsisLoc) { + SourceLocation &EllipsisLoc, bool IsACXXFunctionDeclaration) { // Avoid exceeding the maximum function scope depth. // See https://bugs.llvm.org/show_bug.cgi?id=19607 @@ -7001,6 +7155,23 @@ void Parser::ParseParameterDeclarationClause( return; } + // C++2a [temp.res]p5 + // A qualified-id is assumed to name a type if + // - [...] + // - it is a decl-specifier of the decl-specifier-seq of a + // - [...] + // - parameter-declaration in a member-declaration [...] + // - parameter-declaration in a declarator of a function or function + // template declaration whose declarator-id is qualified [...] + // - parameter-declaration in a lambda-declarator [...] + auto AllowImplicitTypename = ImplicitTypenameContext::No; + if (DeclaratorCtx == DeclaratorContext::Member || + DeclaratorCtx == DeclaratorContext::LambdaExpr || + DeclaratorCtx == DeclaratorContext::RequiresExpr || + IsACXXFunctionDeclaration) { + AllowImplicitTypename = ImplicitTypenameContext::Yes; + } + do { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq // before deciding this was a parameter-declaration-clause. @@ -7030,7 +7201,9 @@ void Parser::ParseParameterDeclarationClause( SourceLocation DSStart = Tok.getLocation(); - ParseDeclarationSpecifiers(DS); + ParseDeclarationSpecifiers(DS, /*TemplateInfo=*/ParsedTemplateInfo(), + AS_none, DeclSpecContext::DSC_normal, + /*LateAttrs=*/nullptr, AllowImplicitTypename); DS.takeAttributesFrom(ArgDeclSpecAttrs); // Parse the declarator. This is "PrototypeContext" or @@ -7046,7 +7219,8 @@ void Parser::ParseParameterDeclarationClause( // Parse GNU attributes, if present. MaybeParseGNUAttributes(ParmDeclarator); - MaybeParseHLSLSemantics(DS.getAttributes()); + if (getLangOpts().HLSL) + MaybeParseHLSLSemantics(DS.getAttributes()); if (Tok.is(tok::kw_requires)) { // User tried to define a requires clause in a parameter declaration, @@ -7427,13 +7601,27 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) { /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression +/// [C2x] typeof-specifier: +/// typeof '(' typeof-specifier-argument ')' +/// typeof_unqual '(' typeof-specifier-argument ')' +/// +/// typeof-specifier-argument: +/// expression +/// type-name /// void Parser::ParseTypeofSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier"); + assert(Tok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual) && + "Not a typeof specifier"); + + bool IsUnqual = Tok.is(tok::kw_typeof_unqual); + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (getLangOpts().C2x && !II->getName().startswith("__")) + Diag(Tok.getLocation(), diag::warn_c2x_compat_typeof_type_specifier) + << IsUnqual; + Token OpTok = Tok; SourceLocation StartLoc = ConsumeToken(); - - const bool hasParens = Tok.is(tok::l_paren); + bool HasParens = Tok.is(tok::l_paren); EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated, @@ -7444,8 +7632,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { SourceRange CastRange; ExprResult Operand = Actions.CorrectDelayedTyposInExpr( ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange)); - if (hasParens) - DS.setTypeofParensRange(CastRange); + if (HasParens) + DS.setTypeArgumentRange(CastRange); if (CastRange.getEnd().isInvalid()) // FIXME: Not accurate, the range gets one token more than it should. @@ -7462,7 +7650,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { const char *PrevSpec = nullptr; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). - if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, + if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualType + : DeclSpec::TST_typeofType, + StartLoc, PrevSpec, DiagID, CastTy, Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; @@ -7485,7 +7675,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { const char *PrevSpec = nullptr; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). - if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, + if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualExpr + : DeclSpec::TST_typeofExpr, + StartLoc, PrevSpec, DiagID, Operand.get(), Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; @@ -7515,7 +7707,7 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) { if (T.getCloseLocation().isInvalid()) return; - DS.setTypeofParensRange(T.getRange()); + DS.setTypeArgumentRange(T.getRange()); DS.SetRangeEnd(T.getCloseLocation()); const char *PrevSpec = nullptr; |