diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp | 445 |
1 files changed, 327 insertions, 118 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 4d05e16..45878b9 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -285,7 +285,7 @@ unsigned Parser::ParseAttributeArgsCommon( if (AttrKind == AttributeList::UnknownAttribute || AttrKind == AttributeList::IgnoredAttribute) { const Token &Next = NextToken(); - IsIdentifierArg = Next.is(tok::r_paren) || Next.is(tok::comma); + IsIdentifierArg = Next.isOneOf(tok::r_paren, tok::comma); } if (IsIdentifierArg) @@ -365,7 +365,8 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, // These may refer to the function arguments, but need to be parsed early to // participate in determining whether it's a redeclaration. std::unique_ptr<ParseScope> PrototypeScope; - if (AttrName->isStr("enable_if") && D && D->isFunctionDeclarator()) { + if (normalizeAttrName(AttrName->getName()) == "enable_if" && + D && D->isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo(); PrototypeScope.reset(new ParseScope(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | @@ -529,64 +530,72 @@ bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, /// [MS] extended-decl-modifier-seq: /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq -void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) { +void Parser::ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs, + SourceLocation *End) { + assert((getLangOpts().MicrosoftExt || getLangOpts().Borland || + getLangOpts().CUDA) && + "Incorrect language options for parsing __declspec"); assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); - ConsumeToken(); - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, "__declspec", - tok::r_paren)) - return; - - // An empty declspec is perfectly legal and should not warn. Additionally, - // you can specify multiple attributes per declspec. - while (Tok.isNot(tok::r_paren)) { - // Attribute not present. - if (TryConsumeToken(tok::comma)) - continue; - - // We expect either a well-known identifier or a generic string. Anything - // else is a malformed declspec. - bool IsString = Tok.getKind() == tok::string_literal ? true : false; - if (!IsString && Tok.getKind() != tok::identifier && - Tok.getKind() != tok::kw_restrict) { - Diag(Tok, diag::err_ms_declspec_type); - T.skipToEnd(); + while (Tok.is(tok::kw___declspec)) { + ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, "__declspec", + tok::r_paren)) return; - } - IdentifierInfo *AttrName; - SourceLocation AttrNameLoc; - if (IsString) { - SmallString<8> StrBuffer; - bool Invalid = false; - StringRef Str = PP.getSpelling(Tok, StrBuffer, &Invalid); - if (Invalid) { + // An empty declspec is perfectly legal and should not warn. Additionally, + // you can specify multiple attributes per declspec. + while (Tok.isNot(tok::r_paren)) { + // Attribute not present. + if (TryConsumeToken(tok::comma)) + continue; + + // We expect either a well-known identifier or a generic string. Anything + // else is a malformed declspec. + bool IsString = Tok.getKind() == tok::string_literal; + if (!IsString && Tok.getKind() != tok::identifier && + Tok.getKind() != tok::kw_restrict) { + Diag(Tok, diag::err_ms_declspec_type); T.skipToEnd(); return; } - AttrName = PP.getIdentifierInfo(Str); - AttrNameLoc = ConsumeStringToken(); - } else { - AttrName = Tok.getIdentifierInfo(); - AttrNameLoc = ConsumeToken(); - } - bool AttrHandled = false; + IdentifierInfo *AttrName; + SourceLocation AttrNameLoc; + if (IsString) { + SmallString<8> StrBuffer; + bool Invalid = false; + StringRef Str = PP.getSpelling(Tok, StrBuffer, &Invalid); + if (Invalid) { + T.skipToEnd(); + return; + } + AttrName = PP.getIdentifierInfo(Str); + AttrNameLoc = ConsumeStringToken(); + } else { + AttrName = Tok.getIdentifierInfo(); + AttrNameLoc = ConsumeToken(); + } + + bool AttrHandled = false; - // Parse attribute arguments. - if (Tok.is(tok::l_paren)) - AttrHandled = ParseMicrosoftDeclSpecArgs(AttrName, AttrNameLoc, Attrs); - else if (AttrName->getName() == "property") - // The property attribute must have an argument list. - Diag(Tok.getLocation(), diag::err_expected_lparen_after) - << AttrName->getName(); + // Parse attribute arguments. + if (Tok.is(tok::l_paren)) + AttrHandled = ParseMicrosoftDeclSpecArgs(AttrName, AttrNameLoc, Attrs); + else if (AttrName->getName() == "property") + // The property attribute must have an argument list. + Diag(Tok.getLocation(), diag::err_expected_lparen_after) + << AttrName->getName(); - if (!AttrHandled) - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, - AttributeList::AS_Declspec); + if (!AttrHandled) + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + AttributeList::AS_Declspec); + } + T.consumeClose(); + if (End) + *End = T.getCloseLocation(); } - T.consumeClose(); } void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { @@ -679,6 +688,28 @@ void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) { AttributeList::AS_Keyword); } +void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) { + // Treat these like attributes, even though they're type specifiers. + while (true) { + switch (Tok.getKind()) { + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + if (!getLangOpts().ObjC1) + Diag(AttrNameLoc, diag::ext_nullability) + << AttrName; + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + AttributeList::AS_Keyword); + break; + } + default: + return; + } + } +} + static bool VersionNumberSeparator(const char Separator) { return (Separator == '.' || Separator == '_'); } @@ -1360,6 +1391,46 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) { } } +// As an exception to the rule, __declspec(align(...)) before the +// class-key affects the type instead of the variable. +void Parser::handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs, + DeclSpec &DS, + Sema::TagUseKind TUK) { + if (TUK == Sema::TUK_Reference) + return; + + ParsedAttributes &PA = DS.getAttributes(); + AttributeList *AL = PA.getList(); + AttributeList *Prev = nullptr; + while (AL) { + AttributeList *Next = AL->getNext(); + + // We only consider attributes using the appropriate '__declspec' spelling, + // this behavior doesn't extend to any other spellings. + if (AL->getKind() == AttributeList::AT_Aligned && + AL->isDeclspecAttribute()) { + // Stitch the attribute into the tag's attribute list. + AL->setNext(nullptr); + Attrs.add(AL); + + // Remove the attribute from the variable's attribute list. + if (Prev) { + // Set the last variable attribute's next attribute to be the attribute + // after the current one. + Prev->setNext(Next); + } else { + // Removing the head of the list requires us to reset the head to the + // next attribute. + PA.set(Next); + } + } else { + Prev = AL; + } + + AL = Next; + } +} + /// ParseDeclaration - Parse a full 'declaration', which consists of /// declaration-specifiers, some number of declarators, and a semicolon. /// 'Context' should be a Declarator::TheContext value. This returns the @@ -1551,7 +1622,7 @@ void Parser::SkipMalformedDecl() { // a malformed class or function definition or similar. ConsumeBrace(); SkipUntil(tok::r_brace); - if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) { + if (Tok.isOneOf(tok::comma, tok::l_brace, tok::kw_try)) { // This declaration isn't over yet. Keep skipping. continue; } @@ -1657,7 +1728,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // and we don't have any other declarators in this declaration. bool Fixit = !DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID); MaybeParseGNUAttributes(D, &LateParsedAttrs); - Fixit &= Tok.is(tok::semi) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try); + Fixit &= Tok.isOneOf(tok::semi, tok::l_brace, tok::kw_try); Diag(Loc, diag::err_c11_noreturn_misplaced) << (Fixit ? FixItHint::CreateRemoval(Loc) : FixItHint()) @@ -1691,11 +1762,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } if (isDeclarationSpecifier()) { - // 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 that handles it as a - // prototype, and let the top-level code handle the erroneous declspec - // where it would otherwise expect a comma or semicolon. + // 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 + // that handles it as a prototype, and let the top-level code handle + // the erroneous declspec where it would otherwise expect a comma or + // semicolon. } else { Diag(Tok, diag::err_expected_fn_body); SkipUntil(tok::semi); @@ -1993,7 +2065,11 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); } - if (ParseExpressionList(Exprs, CommaLocs)) { + if (ParseExpressionList(Exprs, CommaLocs, [&] { + Actions.CodeCompleteConstructor(getCurScope(), + cast<VarDecl>(ThisDecl)->getType()->getCanonicalTypeInternal(), + ThisDecl->getLocation(), Exprs); + })) { Actions.ActOnInitializerError(ThisDecl); SkipUntil(tok::r_paren, StopAtSemi); @@ -2069,8 +2145,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); - } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && - !DS.hasAttributes()) { + } else if (Specs == DeclSpec::PQ_None && !DS.hasAttributes()) { Diag(Tok, diag::err_typename_requires_specqual); if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); @@ -2098,7 +2173,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, } // Issue diagnostic and remove constexpr specfier if present. - if (DS.isConstexprSpecified()) { + if (DS.isConstexprSpecified() && DSC != DSC_condition) { Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr); DS.ClearConstexprSpec(); } @@ -2123,9 +2198,9 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, /// int (x) /// static bool isValidAfterIdentifierInDeclarator(const Token &T) { - return T.is(tok::l_square) || T.is(tok::l_paren) || T.is(tok::r_paren) || - T.is(tok::semi) || T.is(tok::comma) || T.is(tok::equal) || - T.is(tok::kw_asm) || T.is(tok::l_brace) || T.is(tok::colon); + return T.isOneOf(tok::l_square, tok::l_paren, tok::r_paren, tok::semi, + tok::comma, tok::equal, tok::kw_asm, tok::l_brace, + tok::colon); } @@ -2385,7 +2460,7 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start, /// [C++11] 'alignas' '(' assignment-expression ...[opt] ')' void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *EndLoc) { - assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) && + assert(Tok.isOneOf(tok::kw_alignas, tok::kw__Alignas) && "Not an alignment-specifier!"); IdentifierInfo *KWName = Tok.getIdentifierInfo(); @@ -2428,8 +2503,8 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); if (getLangOpts().CPlusPlus && - (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) && + Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype, + tok::annot_template_id) && TryAnnotateCXXScopeToken(EnteringContext)) { SkipMalformedDecl(); return true; @@ -2442,7 +2517,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, // Determine whether the following tokens could possibly be a // declarator. bool MightBeDeclarator = true; - if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) { + if (Tok.isOneOf(tok::kw_typename, tok::annot_typename)) { // A declarator-id can't start with 'typename'. MightBeDeclarator = false; } else if (AfterScope.is(tok::annot_template_id)) { @@ -2457,9 +2532,8 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, // These tokens cannot come after the declarator-id in a // simple-declaration, and are likely to come after a type-specifier. - if (Next.is(tok::star) || Next.is(tok::amp) || Next.is(tok::ampamp) || - Next.is(tok::identifier) || Next.is(tok::annot_cxxscope) || - Next.is(tok::coloncolon)) { + if (Next.isOneOf(tok::star, tok::amp, tok::ampamp, tok::identifier, + tok::annot_cxxscope, tok::coloncolon)) { // Missing a semicolon. MightBeDeclarator = false; } else if (HasScope) { @@ -2528,6 +2602,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, /// [C11] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] +/// [ObjC1] '__kindof' declaration-specifiers[opt] /// /// storage-class-specifier: [C99 6.7.1] /// 'typedef' @@ -2564,7 +2639,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); bool AttrsLastTime = false; ParsedAttributesWithRange attrs(AttrFactory); - const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); + // We use Sema's policy to get bool macros right. + const PrintingPolicy &Policy = Actions.getPrintingPolicy(); while (1) { bool isInvalid = false; bool isStorageClass = false; @@ -2811,12 +2887,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); - continue; } @@ -2866,14 +2936,27 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.isTypeAltiVecVector()) goto DoneWithDeclSpec; + if (DSContext == DSC_objc_method_result && isObjCInstancetype()) { + ParsedType TypeRep = Actions.ActOnObjCInstanceType(Loc); + assert(TypeRep); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, TypeRep, Policy); + if (isInvalid) + break; + + DS.SetRangeEnd(Loc); + ConsumeToken(); + continue; + } + ParsedType TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope()); // MSVC: If we weren't able to parse a default template argument, and it's - // just a simple identifier, create a DependentNameType. This will allow us - // to defer the name lookup to template instantiation time, as long we forge a - // NestedNameSpecifier for the current context. + // just a simple identifier, create a DependentNameType. This will allow + // us to defer the name lookup to template instantiation time, as long we + // forge a NestedNameSpecifier for the current context. if (!TypeRep && DSContext == DSC_template_type_arg && getLangOpts().MSVCCompat && getCurScope()->isTemplateParamScope()) { TypeRep = Actions.ActOnDelayedDefaultTemplateArg( @@ -2909,11 +2992,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The identifier - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); + // Objective-C supports type arguments and protocol references + // following an Objective-C object or object pointer + // type. Handle either one of them. + if (Tok.is(tok::less) && getLangOpts().ObjC1) { + SourceLocation NewEndLoc; + TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers( + Loc, TypeRep, /*consumeLastToken=*/true, + NewEndLoc); + if (NewTypeRep.isUsable()) { + DS.UpdateTypeRep(NewTypeRep.get()); + DS.SetRangeEnd(NewEndLoc); + } + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -2950,7 +3041,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Microsoft declspec support. case tok::kw___declspec: - ParseMicrosoftDeclSpec(DS.getAttributes()); + ParseMicrosoftDeclSpecs(DS.getAttributes()); continue; // Microsoft single token adornments. @@ -2987,6 +3078,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseOpenCLAttributes(DS.getAttributes()); continue; + // Nullability type specifiers. + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + ParseNullabilityTypeSpecifiers(DS.getAttributes()); + continue; + + // Objective-C 'kindof' types. + case tok::kw___kindof: + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, + nullptr, 0, AttributeList::AS_Keyword); + (void)ConsumeToken(); + continue; + // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc, @@ -3097,6 +3202,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); break; + // concept + case tok::kw_concept: + isInvalid = DS.SetConceptSpec(Loc, PrevSpec, DiagID); + break; + // type-specifier case tok::kw_short: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, @@ -3318,10 +3428,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1) goto DoneWithDeclSpec; - if (!ParseObjCProtocolQualifiers(DS)) - Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) - << FixItHint::CreateInsertion(Loc, "id") - << SourceRange(Loc, DS.getSourceRange().getEnd()); + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + TypeResult Type = parseObjCProtocolQualifierType(EndLoc); + if (Type.isUsable()) { + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, StartLoc, + PrevSpec, DiagID, Type.get(), + Actions.getASTContext().getPrintingPolicy())) + Diag(StartLoc, DiagID) << PrevSpec; + + DS.SetRangeEnd(EndLoc); + } else { + DS.SetTypeSpecError(); + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. @@ -3484,6 +3603,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_openmp)) { + // Result can be ignored, because it must be always empty. + auto Res = ParseOpenMPDeclarativeDirective(); + assert(!Res); + // Silence possible warnings. + (void)Res; + continue; + } if (!Tok.is(tok::at)) { auto CFieldCallback = [&](ParsingFieldDeclarator &FD) { // Install the declarator into the current TagDecl. @@ -3594,16 +3721,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); MaybeParseCXX11Attributes(attrs); - - // If declspecs exist after tag, parse them. - while (Tok.is(tok::kw___declspec)) - ParseMicrosoftDeclSpec(attrs); + MaybeParseMicrosoftDeclSpecs(attrs); SourceLocation ScopedEnumKWLoc; bool IsScopedUsingClassTag = false; // In C++11, recognize 'enum class' and 'enum struct'. - if (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct)) { + if (Tok.isOneOf(tok::kw_class, tok::kw_struct)) { Diag(Tok, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_scoped_enum : diag::ext_scoped_enum); IsScopedUsingClassTag = Tok.is(tok::kw_class); @@ -3616,8 +3740,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // They are allowed afterwards, though. MaybeParseGNUAttributes(attrs); MaybeParseCXX11Attributes(attrs); - while (Tok.is(tok::kw___declspec)) - ParseMicrosoftDeclSpec(attrs); + MaybeParseMicrosoftDeclSpecs(attrs); } // C++11 [temp.explicit]p12: @@ -3644,11 +3767,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // if a fixed underlying type is allowed. ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + CXXScopeSpec Spec; + if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(), /*EnteringContext=*/true)) return; - if (SS.isSet() && Tok.isNot(tok::identifier)) { + if (Spec.isSet() && Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; if (Tok.isNot(tok::l_brace)) { // Has no name and is not a definition. @@ -3657,6 +3781,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } } + + SS = Spec; } // Must have either 'enum name' or 'enum {...}'. @@ -3842,6 +3968,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } + handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); + + Sema::SkipBodyInfo SkipBody; + if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) && + NextToken().is(tok::identifier)) + SkipBody = Actions.shouldSkipAnonEnumBody(getCurScope(), + NextToken().getIdentifierInfo(), + NextToken().getLocation()); + bool Owned = false; bool IsDependent = false; const char *PrevSpec = nullptr; @@ -3851,7 +3986,22 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType, - DSC == DSC_type_specifier); + DSC == DSC_type_specifier, &SkipBody); + + if (SkipBody.ShouldSkip) { + assert(TUK == Sema::TUK_Definition && "can only skip a definition"); + + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + T.skipToEnd(); + + if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TagDecl, Owned, + Actions.getASTContext().getPrintingPolicy())) + Diag(StartLoc, DiagID) << PrevSpec; + return; + } if (IsDependent) { // This enum has a dependent nested-name-specifier. Handle it as a @@ -3923,6 +4073,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { Diag(Tok, diag::error_empty_enum); SmallVector<Decl *, 32> EnumConstantDecls; + SmallVector<SuppressAccessChecks, 32> EnumAvailabilityDiags; Decl *LastEnumConstDecl = nullptr; @@ -3953,7 +4104,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation EqualLoc; ExprResult AssignedVal; - ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); + EnumAvailabilityDiags.emplace_back(*this); if (TryConsumeToken(tok::equal, EqualLoc)) { AssignedVal = ParseConstantExpression(); @@ -3967,7 +4118,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { IdentLoc, Ident, attrs.getList(), EqualLoc, AssignedVal.get()); - PD.complete(EnumConstDecl); + EnumAvailabilityDiags.back().done(); EnumConstantDecls.push_back(EnumConstDecl); LastEnumConstDecl = EnumConstDecl; @@ -4023,6 +4174,14 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { getCurScope(), attrs.getList()); + // Now handle enum constant availability diagnostics. + assert(EnumConstantDecls.size() == EnumAvailabilityDiags.size()); + for (size_t i = 0, e = EnumConstantDecls.size(); i != e; ++i) { + ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); + EnumAvailabilityDiags[i].redelay(); + PD.complete(EnumConstantDecls[i]); + } + EnumScope.Exit(); Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, T.getCloseLocation()); @@ -4199,6 +4358,12 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___pascal: case tok::kw___unaligned: + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + + case tok::kw___kindof: + case tok::kw___private: case tok::kw___local: case tok::kw___global: @@ -4344,6 +4509,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::annot_decltype: case tok::kw_constexpr: + // C++ Concepts TS - concept + case tok::kw_concept: + // C11 _Atomic case tok::kw__Atomic: return true; @@ -4372,6 +4540,12 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___pascal: case tok::kw___unaligned: + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + + case tok::kw___kindof: + case tok::kw___private: case tok::kw___local: case tok::kw___global: @@ -4397,7 +4571,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { } // Parse the constructor name. - if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { + if (Tok.isOneOf(tok::identifier, tok::annot_template_id)) { // We already know that we have a constructor name; just consume // the token. ConsumeToken(); @@ -4601,6 +4775,21 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, continue; } goto DoneWithTypeQuals; + + // Nullability type specifiers. + case tok::kw__Nonnull: + case tok::kw__Nullable: + case tok::kw__Null_unspecified: + ParseNullabilityTypeSpecifiers(DS.getAttributes()); + continue; + + // Objective-C 'kindof' types. + case tok::kw___kindof: + DS.getAttributes().addNew(Tok.getIdentifierInfo(), Loc, nullptr, Loc, + nullptr, 0, AttributeList::AS_Keyword); + (void)ConsumeToken(); + continue; + case tok::kw___attribute: if (AttrReqs & AR_GNUAttributesParsedAndRejected) // When GNU attributes are expressly forbidden, diagnose their usage. @@ -4773,7 +4962,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, DS.getConstSpecLoc(), DS.getVolatileSpecLoc(), - DS.getRestrictSpecLoc()), + DS.getRestrictSpecLoc(), + DS.getAtomicSpecLoc()), DS.getAttributes(), SourceLocation()); else @@ -4916,7 +5106,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { } if (D.getCXXScopeSpec().isValid()) { - if (Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) + if (Actions.ShouldEnterDeclaratorScope(getCurScope(), + D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); @@ -4953,8 +5144,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // the l_paren token. } - if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || - Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { + if (Tok.isOneOf(tok::identifier, tok::kw_operator, tok::annot_template_id, + tok::tilde)) { // We found something that indicates the start of an unqualified-id. // Parse that unqualified-id. bool AllowConstructorName; @@ -4968,6 +5159,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { AllowConstructorName = (D.getContext() == Declarator::MemberContext); SourceLocation TemplateKWLoc; + bool HadScope = D.getCXXScopeSpec().isValid(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, @@ -4981,6 +5173,13 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(nullptr, Tok.getLocation()); D.setInvalidType(true); } else { + // ParseUnqualifiedId might have parsed a scope specifier during error + // recovery. If it did so, enter that scope. + if (!HadScope && D.getCXXScopeSpec().isValid() && + Actions.ShouldEnterDeclaratorScope(getCurScope(), + D.getCXXScopeSpec())) + DeclScopeObj.EnterDeclaratorScope(); + // Parsed the unqualified-id; update range information and move along. if (D.getSourceRange().getBegin().isInvalid()) D.SetRangeBegin(D.getName().getSourceRange().getBegin()); @@ -5022,7 +5221,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // If there was an error parsing parenthesized declarator, declarator // scope may have been entered before. Don't do it again. if (!D.isInvalidType() && - Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) + Actions.ShouldEnterDeclaratorScope(getCurScope(), + D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); @@ -5048,7 +5248,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { << (D.getDeclSpec().isEmpty() ? SourceRange() : D.getDeclSpec().getSourceRange()); } else if (getLangOpts().CPlusPlus) { - if (Tok.is(tok::period) || Tok.is(tok::arrow)) + if (Tok.isOneOf(tok::period, tok::arrow)) Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow); else { SourceLocation Loc = D.getCXXScopeSpec().getEndLoc(); @@ -5310,7 +5510,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (getLangOpts().CPlusPlus) { // FIXME: Accept these components in any order, and produce fixits to // correct the order if the user gets it wrong. Ideally we should deal - // with the virt-specifier-seq and pure-specifier in the same way. + // with the pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, @@ -5323,15 +5523,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, } // Parse ref-qualifier[opt]. - if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { - Diag(Tok, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_ref_qualifier : - diag::ext_ref_qualifier); - - RefQualifierIsLValueRef = Tok.is(tok::amp); - RefQualifierLoc = ConsumeToken(); + if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) EndLoc = RefQualifierLoc; - } // C++11 [expr.prim.general]p3: // If a declaration declares a member function or member function @@ -5427,6 +5620,22 @@ void Parser::ParseFunctionDeclarator(Declarator &D, FnAttrs, EndLoc); } +/// ParseRefQualifier - Parses a member function ref-qualifier. Returns +/// true if a ref-qualifier is found. +bool Parser::ParseRefQualifier(bool &RefQualifierIsLValueRef, + SourceLocation &RefQualifierLoc) { + if (Tok.isOneOf(tok::amp, tok::ampamp)) { + Diag(Tok, getLangOpts().CPlusPlus11 ? + diag::warn_cxx98_compat_ref_qualifier : + diag::ext_ref_qualifier); + + RefQualifierIsLValueRef = Tok.is(tok::amp); + RefQualifierLoc = ConsumeToken(); + return true; + } + return false; +} + /// isFunctionDeclaratorIdentifierList - This parameter list may have an /// identifier list form for a K&R-style function: void foo(a,b,c) /// |