diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-05-27 18:47:56 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-05-27 18:47:56 +0000 |
commit | 5e20cdd81c44a443562a09007668ffdf76c455af (patch) | |
tree | dbbd4047878da71c1a706e26ce05b4e7791b14cc /lib/Parse/ParseDecl.cpp | |
parent | d5f23b0b7528b5c3caed1ba14f897cc4aaa9e3c3 (diff) | |
download | src-5e20cdd81c44a443562a09007668ffdf76c455af.tar.gz src-5e20cdd81c44a443562a09007668ffdf76c455af.zip |
Notes
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 268 |
1 files changed, 187 insertions, 81 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 4d05e16491b0..bd114d7e34a7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -529,64 +529,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) { @@ -1360,6 +1368,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 @@ -1691,11 +1739,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 +2042,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); @@ -2564,7 +2617,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; @@ -2871,9 +2925,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, 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( @@ -2950,7 +3004,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Microsoft declspec support. case tok::kw___declspec: - ParseMicrosoftDeclSpec(DS.getAttributes()); + ParseMicrosoftDeclSpecs(DS.getAttributes()); continue; // Microsoft single token adornments. @@ -3594,10 +3648,7 @@ 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; @@ -3616,8 +3667,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 +3694,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 +3708,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } } + + SS = Spec; } // Must have either 'enum name' or 'enum {...}'. @@ -3842,6 +3895,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 +3913,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 +4000,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 +4031,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 +4045,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 +4101,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()); @@ -4773,7 +4859,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 +5003,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(); @@ -4968,6 +5056,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 +5070,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 +5118,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(); @@ -5310,7 +5407,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 +5420,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 +5517,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.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(); + 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) /// |