diff options
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 373 |
1 files changed, 266 insertions, 107 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f11a9d1..d7f8e98 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -11,16 +11,17 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/OperatorKinds.h" #include "clang/Parse/Parser.h" +#include "RAIIObjectsForParser.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" -#include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" +#include "clang/Sema/Scope.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallString.h" -#include "RAIIObjectsForParser.h" using namespace clang; /// ParseNamespace - We know that the current token is a namespace keyword. This @@ -157,7 +158,7 @@ Decl *Parser::ParseNamespace(unsigned Context, // If we're still good, complain about inline namespaces in non-C++0x now. if (InlineLoc.isValid()) - Diag(InlineLoc, getLangOpts().CPlusPlus0x ? + Diag(InlineLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace); // Enter a scope for the namespace. @@ -195,7 +196,7 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, if (index == Ident.size()) { while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs); + MaybeParseCXX11Attributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); } @@ -295,7 +296,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { : SourceLocation()); ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs); + MaybeParseCXX11Attributes(attrs); MaybeParseMicrosoftAttributes(attrs); if (Tok.isNot(tok::l_brace)) { @@ -318,7 +319,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { T.consumeOpen(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs); + MaybeParseCXX11Attributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); } @@ -439,8 +440,8 @@ Decl *Parser::ParseUsingDirective(unsigned Context, /// unqualified-id /// 'using' :: unqualified-id /// -/// alias-declaration: C++0x [decl.typedef]p2 -/// 'using' identifier = type-id ; +/// alias-declaration: C++11 [dcl.dcl]p1 +/// 'using' identifier attribute-specifier-seq[opt] = type-id ; /// Decl *Parser::ParseUsingDeclaration(unsigned Context, const ParsedTemplateInfo &TemplateInfo, @@ -450,27 +451,27 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Decl **OwnedType) { CXXScopeSpec SS; SourceLocation TypenameLoc; - bool IsTypeName; - ParsedAttributesWithRange attrs(AttrFactory); + bool IsTypeName = false; + ParsedAttributesWithRange Attrs(AttrFactory); // FIXME: Simply skip the attributes and diagnose, don't bother parsing them. - MaybeParseCXX0XAttributes(attrs); - ProhibitAttributes(attrs); - attrs.clear(); - attrs.Range = SourceRange(); + MaybeParseCXX11Attributes(Attrs); + ProhibitAttributes(Attrs); + Attrs.clear(); + Attrs.Range = SourceRange(); // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { - TypenameLoc = Tok.getLocation(); - ConsumeToken(); + TypenameLoc = ConsumeToken(); IsTypeName = true; } - else - IsTypeName = false; // Parse nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + IdentifierInfo *LastII = 0; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false, + /*MayBePseudoDtor=*/0, /*IsTypename=*/false, + /*LastII=*/&LastII); // Check nested-name specifier. if (SS.isInvalid()) { @@ -478,33 +479,45 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + // Parse the unqualified-id. We allow parsing of both constructor and // destructor names and allow the action module to diagnose any semantic // errors. - SourceLocation TemplateKWLoc; - UnqualifiedId Name; - if (ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/true, - /*AllowConstructorName=*/true, - ParsedType(), - TemplateKWLoc, - Name)) { + // + // C++11 [class.qual]p2: + // [...] in a using-declaration that is a member-declaration, if the name + // specified after the nested-name-specifier is the same as the identifier + // or the simple-template-id's template-name in the last component of the + // nested-name-specifier, the name is [...] considered to name the + // constructor. + if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext && + Tok.is(tok::identifier) && NextToken().is(tok::semi) && + SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && + !SS.getScopeRep()->getAsNamespace() && + !SS.getScopeRep()->getAsNamespaceAlias()) { + SourceLocation IdLoc = ConsumeToken(); + ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII); + Name.setConstructorName(Type, IdLoc, IdLoc); + } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false, + /*AllowDestructorName=*/ true, + /*AllowConstructorName=*/ true, ParsedType(), + TemplateKWLoc, Name)) { SkipUntil(tok::semi); return 0; } - MaybeParseCXX0XAttributes(attrs); + MaybeParseCXX11Attributes(Attrs); // Maybe this is an alias-declaration. bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; if (IsAliasDecl) { - // TODO: Attribute support. C++0x attributes may appear before the equals. - // Where can GNU attributes appear? + // TODO: Can GNU attributes appear here? ConsumeToken(); - Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_alias_declaration : diag::ext_alias_declaration); @@ -546,25 +559,26 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? Declarator::AliasTemplateContext : - Declarator::AliasDeclContext, AS, OwnedType); + Declarator::AliasDeclContext, AS, OwnedType, + &Attrs); } else { // C++11 attributes are not allowed on a using-declaration, but GNU ones // are. - ProhibitAttributes(attrs); + ProhibitAttributes(Attrs); // Parse (optional) attributes (most likely GNU strong-using extension). - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(Attrs); } // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - !attrs.empty() ? "attributes list" : + !Attrs.empty() ? "attributes list" : IsAliasDecl ? "alias declaration" : "using declaration", tok::semi); // Diagnose an attempt to declare a templated using-declaration. - // In C++0x, alias-declarations can be templates: + // In C++11, alias-declarations can be templates: // template <...> using id = type; if (TemplateInfo.Kind && !IsAliasDecl) { SourceRange R = TemplateInfo.getSourceRange(); @@ -591,13 +605,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, MultiTemplateParamsArg TemplateParamsArg( TemplateParams ? TemplateParams->data() : 0, TemplateParams ? TemplateParams->size() : 0); - // FIXME: Propagate attributes. return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, - UsingLoc, Name, TypeAlias); + UsingLoc, Name, Attrs.getList(), + TypeAlias); } return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, - Name, attrs.getList(), + Name, Attrs.getList(), IsTypeName, TypenameLoc); } @@ -637,7 +651,8 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ return 0; if (!isTokenStringLiteral()) { - Diag(Tok, diag::err_expected_string_literal); + Diag(Tok, diag::err_expected_string_literal) + << /*Source='static_assert'*/1; SkipMalformedDecl(); return 0; } @@ -800,15 +815,18 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { /// class. The result is either a type or null, depending on whether a type /// name was found. /// -/// base-type-specifier: [C++ 10.1] +/// base-type-specifier: [C++11 class.derived] /// class-or-decltype -/// class-or-decltype: [C++ 10.1] +/// class-or-decltype: [C++11 class.derived] /// nested-name-specifier[opt] class-name /// decltype-specifier -/// class-name: [C++ 9.1] +/// class-name: [C++ class.name] /// identifier /// simple-template-id /// +/// In C++98, instead of base-type-specifier, we have: +/// +/// ::[opt] nested-name-specifier[opt] class-name Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, SourceLocation &EndLocation) { // Ignore attempts to use typename @@ -956,6 +974,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { case tok::semi: // struct foo {...} ; case tok::star: // struct foo {...} * P; case tok::amp: // struct foo {...} & R = ... + case tok::ampamp: // struct foo {...} && R = ... case tok::identifier: // struct foo {...} V ; case tok::r_paren: //(struct foo {...} ) {4} case tok::annot_cxxscope: // struct foo {...} a:: b; @@ -963,6 +982,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { case tok::annot_template_id: // struct foo {...} a<int> ::b; case tok::l_paren: // struct foo {...} ( x); case tok::comma: // __builtin_offsetof(struct foo{...} , + case tok::kw_operator: // struct foo operator ++() {...} return true; case tok::colon: return CouldBeBitfield; // enum E { ... } : 2; @@ -970,7 +990,12 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { case tok::kw_const: // struct foo {...} const x; case tok::kw_volatile: // struct foo {...} volatile x; case tok::kw_restrict: // struct foo {...} restrict x; - case tok::kw_inline: // struct foo {...} inline foo() {}; + // Function specifiers + // Note, no 'explicit'. An explicit function must be either a conversion + // operator or a constructor. Either way, it can't have a return type. + case tok::kw_inline: // struct foo inline f(); + case tok::kw_virtual: // struct foo virtual f(); + case tok::kw_friend: // struct foo friend f(); // Storage-class specifiers case tok::kw_static: // struct foo {...} static x; case tok::kw_extern: // struct foo {...} extern x; @@ -978,6 +1003,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { case tok::kw_register: // struct foo {...} register x; case tok::kw_auto: // struct foo {...} auto x; case tok::kw_mutable: // struct foo {...} mutable x; + case tok::kw_thread_local: // struct foo {...} thread_local x; case tok::kw_constexpr: // struct foo {...} constexpr x; // As shown above, type qualifiers and storage class specifiers absolutely // can occur after class specifiers according to the grammar. However, @@ -1002,6 +1028,13 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { if (!getLangOpts().CPlusPlus) return true; break; + // C++11 attributes + case tok::l_square: // enum E [[]] x + // Note, no tok::kw_alignas here; alignas cannot appertain to a type. + return getLangOpts().CPlusPlus11 && NextToken().is(tok::l_square); + case tok::greater: + // template<class T = class X> + return getLangOpts().CPlusPlus; } return false; } @@ -1050,7 +1083,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation StartLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, - bool EnteringContext, DeclSpecContext DSC) { + bool EnteringContext, DeclSpecContext DSC, + ParsedAttributesWithRange &Attributes) { DeclSpec::TST TagType; if (TagTokKind == tok::kw_struct) TagType = DeclSpec::TST_struct; @@ -1102,7 +1136,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different // styles of attributes? - MaybeParseCXX0XAttributes(attrs); + MaybeParseCXX11Attributes(attrs); + + // Source location used by FIXIT to insert misplaced + // C++11 attributes + SourceLocation AttrFixitLoc = Tok.getLocation(); if (TagType == DeclSpec::TST_struct && !Tok.is(tok::identifier) && @@ -1232,18 +1270,30 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // - If we have 'struct foo;', then this is either a forward declaration // or a friend declaration, which have to be treated differently. // - Otherwise we have something like 'struct foo xyz', a reference. + // + // We also detect these erroneous cases to provide better diagnostic for + // C++11 attributes parsing. + // - attributes follow class name: + // struct foo [[]] {}; + // - attributes appear before or after 'final': + // struct foo [[]] final [[]] {}; + // // However, in type-specifier-seq's, things look like declarations but are // just references, e.g. // new struct s; // or // &T::operator struct s; // For these, DSC is DSC_type_specifier. + + // If there are attributes after class name, parse them. + MaybeParseCXX11Attributes(Attributes); + Sema::TagUseKind TUK; if (DSC == DSC_trailing) TUK = Sema::TUK_Reference; else if (Tok.is(tok::l_brace) || (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || - (isCXX0XFinalKeyword() && + (isCXX11FinalKeyword() && (NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) { if (DS.isFriendSpecified()) { // C++ [class.friend]p2: @@ -1259,6 +1309,37 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Okay, this is a class definition. TUK = Sema::TUK_Definition; } + } else if (isCXX11FinalKeyword() && (NextToken().is(tok::l_square) || + NextToken().is(tok::kw_alignas))) { + // We can't tell if this is a definition or reference + // until we skipped the 'final' and C++11 attribute specifiers. + TentativeParsingAction PA(*this); + + // Skip the 'final' keyword. + ConsumeToken(); + + // Skip C++11 attribute specifiers. + while (true) { + if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { + ConsumeBracket(); + if (!SkipUntil(tok::r_square)) + break; + } else if (Tok.is(tok::kw_alignas) && NextToken().is(tok::l_paren)) { + ConsumeToken(); + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + break; + } else { + break; + } + } + + if (Tok.is(tok::l_brace) || Tok.is(tok::colon)) + TUK = Sema::TUK_Definition; + else + TUK = Sema::TUK_Reference; + + PA.Revert(); } else if (DSC != DSC_type_specifier && (Tok.is(tok::semi) || (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) { @@ -1273,6 +1354,28 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else TUK = Sema::TUK_Reference; + // Forbid misplaced attributes. In cases of a reference, we pass attributes + // to caller to handle. + if (TUK != Sema::TUK_Reference) { + // If this is not a reference, then the only possible + // valid place for C++11 attributes to appear here + // is between class-key and class-name. If there are + // any attributes after class-name, we try a fixit to move + // them to the right place. + SourceRange AttrRange = Attributes.Range; + if (AttrRange.isValid()) { + Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed) + << AttrRange + << FixItHint::CreateInsertionFromRange(AttrFixitLoc, + CharSourceRange(AttrRange, true)) + << FixItHint::CreateRemoval(AttrRange); + + // Recover by adding misplaced attributes to the attribute list + // of the class so they can be applied on the class later. + attrs.takeAllFrom(Attributes); + } + } + // If this is an elaborated type specifier, and we delayed // diagnostics before, just merge them into the current pool. if (shouldDelayDiagsInTag) { @@ -1414,11 +1517,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); } else { - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TUK == Sema::TUK_Definition) { - // FIXME: Diagnose this particular error. - } - if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition) ProhibitAttributes(attrs); @@ -1453,9 +1551,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || - isCXX0XFinalKeyword()); + isCXX11FinalKeyword()); if (getLangOpts().CPlusPlus) - ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); + ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, + TagOrTempResult.get()); else ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); } @@ -1490,13 +1589,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // is permitted. if (TUK == Sema::TUK_Definition && (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - DeclSpec::getSpecifierName(TagType)); - // Push this token back into the preprocessor and change our current token - // to ';' so that the rest of the code recovers as though there were an - // ';' after the definition. - PP.EnterToken(Tok); - Tok.setKind(tok::semi); + if (Tok.isNot(tok::semi)) { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + DeclSpec::getSpecifierName(TagType)); + // Push this token back into the preprocessor and change our current token + // to ';' so that the rest of the code recovers as though there were an + // ';' after the definition. + PP.EnterToken(Tok); + Tok.setKind(tok::semi); + } } } @@ -1544,26 +1645,33 @@ void Parser::ParseBaseClause(Decl *ClassDecl) { /// 'public bar' and 'virtual private baz' are each base-specifiers. /// /// base-specifier: [C++ class.derived] -/// ::[opt] nested-name-specifier[opt] class-name -/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt] -/// base-type-specifier -/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt] -/// base-type-specifier +/// attribute-specifier-seq[opt] base-type-specifier +/// attribute-specifier-seq[opt] 'virtual' access-specifier[opt] +/// base-type-specifier +/// attribute-specifier-seq[opt] access-specifier 'virtual'[opt] +/// base-type-specifier Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { bool IsVirtual = false; SourceLocation StartLoc = Tok.getLocation(); + ParsedAttributesWithRange Attributes(AttrFactory); + MaybeParseCXX11Attributes(Attributes); + // Parse the 'virtual' keyword. if (Tok.is(tok::kw_virtual)) { ConsumeToken(); IsVirtual = true; } + CheckMisplacedCXX11Attribute(Attributes, StartLoc); + // Parse an (optional) access specifier. AccessSpecifier Access = getAccessSpecifierIfPresent(); if (Access != AS_none) ConsumeToken(); + CheckMisplacedCXX11Attribute(Attributes, StartLoc); + // Parse the 'virtual' keyword (again!), in case it came after the // access specifier. if (Tok.is(tok::kw_virtual)) { @@ -1577,6 +1685,8 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { IsVirtual = true; } + CheckMisplacedCXX11Attribute(Attributes, StartLoc); + // Parse the class-name. SourceLocation EndLocation; SourceLocation BaseLoc; @@ -1596,8 +1706,9 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { // Notify semantic analysis that we have parsed a complete // base-specifier. - return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, - BaseType.get(), BaseLoc, EllipsisLoc); + return Actions.ActOnBaseSpecifier(ClassDecl, Range, Attributes, IsVirtual, + Access, BaseType.get(), BaseLoc, + EllipsisLoc); } /// getAccessSpecifierIfPresent - Determine whether the next token is @@ -1653,13 +1764,13 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, } } -/// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x +/// isCXX11VirtSpecifier - Determine whether the given token is a C++11 /// virt-specifier. /// /// virt-specifier: /// override /// final -VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const { +VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { if (!getLangOpts().CPlusPlus) return VirtSpecifiers::VS_None; @@ -1682,15 +1793,15 @@ VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const { return VirtSpecifiers::VS_None; } -/// ParseOptionalCXX0XVirtSpecifierSeq - Parse a virt-specifier-seq. +/// ParseOptionalCXX11VirtSpecifierSeq - Parse a virt-specifier-seq. /// /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier -void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, +void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface) { while (true) { - VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier(); + VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(); if (Specifier == VirtSpecifiers::VS_None) return; @@ -1706,7 +1817,7 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, Diag(Tok.getLocation(), diag::err_override_control_interface) << VirtSpecifiers::getSpecifierName(Specifier); } else { - Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_override_control_keyword : diag::ext_override_control_keyword) << VirtSpecifiers::getSpecifierName(Specifier); @@ -1715,9 +1826,9 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, } } -/// isCXX0XFinalKeyword - Determine whether the next token is a C++0x +/// isCXX11FinalKeyword - Determine whether the next token is a C++11 /// contextual 'final' keyword. -bool Parser::isCXX0XFinalKeyword() const { +bool Parser::isCXX11FinalKeyword() const { if (!getLangOpts().CPlusPlus) return false; @@ -1861,8 +1972,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ColonProtectionRAIIObject X(*this); ParsedAttributesWithRange attrs(AttrFactory); - // Optional C++0x attribute-specifier - MaybeParseCXX0XAttributes(attrs); + ParsedAttributesWithRange FnAttrs(AttrFactory); + // Optional C++11 attribute-specifier + MaybeParseCXX11Attributes(attrs); + // We need to keep these attributes for future diagnostic + // before they are taken over by declaration specifier. + FnAttrs.addAll(attrs.getList()); + FnAttrs.Range = attrs.Range; + MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { @@ -1901,6 +2018,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::semi)) { ConsumeToken(); + + if (DS.isFriendSpecified()) + ProhibitAttributes(FnAttrs); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams); DS.complete(TheDecl); @@ -1931,7 +2052,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface); + ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface); // If attributes exist after the declarator, but before an '{', parse them. MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); @@ -1955,7 +2076,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // In C++11, a non-function declarator followed by an open brace is a // braced-init-list for an in-class member initialization, not an // erroneous function definition. - if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus0x) { + if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus11) { DefinitionKind = FDK_Definition; } else if (DeclaratorInfo.isFunctionDeclarator()) { if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) { @@ -1969,12 +2090,21 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } } + // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains + // to a friend declaration, that declaration shall be a definition. + if (DeclaratorInfo.isFunctionDeclarator() && + DefinitionKind != FDK_Definition && DS.isFriendSpecified()) { + // Diagnose attributes that appear before decl specifier: + // [[]] friend int foo(); + ProhibitAttributes(FnAttrs); + } + if (DefinitionKind) { if (!DeclaratorInfo.isFunctionDeclarator()) { Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params); ConsumeBrace(); SkipUntil(tok::r_brace, /*StopAtSemi*/false); - + // Consume the optional ';' if (Tok.is(tok::semi)) ConsumeToken(); @@ -1984,16 +2114,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_function_declared_typedef); - // This recovery skips the entire function body. It would be nice - // to simply call ParseCXXInlineMethodDef() below, however Sema - // assumes the declarator represents a function, not a typedef. - ConsumeBrace(); - SkipUntil(tok::r_brace, /*StopAtSemi*/false); - // Consume the optional ';' - if (Tok.is(tok::semi)) - ConsumeToken(); - return; + // Recover by treating the 'typedef' as spurious. + DS.ClearStorageClassSpecs(); } Decl *FunDecl = @@ -2052,7 +2175,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // FIXME: When g++ adds support for this, we'll need to check whether it // goes before or after the GNU attributes and __asm__. - ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface); + ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface); InClassInitStyle HasInClassInit = ICIS_NoInit; if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { @@ -2063,8 +2186,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, HasInitializer = true; if (!DeclaratorInfo.isDeclarationOfFunction() && DeclaratorInfo.getDeclSpec().getStorageClassSpec() - != DeclSpec::SCS_static && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit; } @@ -2074,8 +2195,23 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // this call will *not* return the created decl; It will return null. // See Sema::ActOnCXXMemberDeclarator for details. - Decl *ThisDecl = 0; + NamedDecl *ThisDecl = 0; if (DS.isFriendSpecified()) { + // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains + // to a friend declaration, that declaration shall be a definition. + // + // Diagnose attributes appear after friend member function declarator: + // foo [[]] (); + SmallVector<SourceRange, 4> Ranges; + DeclaratorInfo.getCXX11AttributeRanges(Ranges); + if (!Ranges.empty()) { + for (SmallVector<SourceRange, 4>::iterator I = Ranges.begin(), + E = Ranges.end(); I != E; ++I) { + Diag((*I).getBegin(), diag::err_attributes_not_allowed) + << *I; + } + } + // TODO: handle initializers, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, TemplateParams); @@ -2100,9 +2236,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, LateParsedAttrs.clear(); // Handle the initializer. - if (HasInClassInit != ICIS_NoInit) { + if (HasInClassInit != ICIS_NoInit && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() != + DeclSpec::SCS_static) { // The initializer was deferred; parse it and cache the tokens. - Diag(Tok, getLangOpts().CPlusPlus0x ? + Diag(Tok, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_nonstatic_member_init : diag::ext_nonstatic_member_init); @@ -2264,6 +2402,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, /// access-specifier ':' member-specification[opt] /// void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, + SourceLocation AttrFixitLoc, + ParsedAttributesWithRange &Attrs, unsigned TagType, Decl *TagDecl) { assert((TagType == DeclSpec::TST_struct || TagType == DeclSpec::TST_interface || @@ -2320,17 +2460,23 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Parse the optional 'final' keyword. if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { - assert(isCXX0XFinalKeyword() && "not a class definition"); + assert(isCXX11FinalKeyword() && "not a class definition"); FinalLoc = ConsumeToken(); if (TagType == DeclSpec::TST_interface) { Diag(FinalLoc, diag::err_override_control_interface) << "final"; } else { - Diag(FinalLoc, getLangOpts().CPlusPlus0x ? + Diag(FinalLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_override_control_keyword : diag::ext_override_control_keyword) << "final"; } + + // Parse any C++11 attributes after 'final' keyword. + // These attributes are not allowed to appear here, + // and the only possible place for them to appertain + // to the class would be between class-key and class-name. + CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc); } if (Tok.is(tok::colon)) { @@ -2395,6 +2541,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_openmp)) { + ParseOpenMPDeclarativeDirective(); + continue; + } + AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. @@ -2551,8 +2702,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { } } while (true); - Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, - MemInitializers.data(), MemInitializers.size(), + Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, MemInitializers, AnyErrors); } @@ -2606,7 +2756,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // Parse the '('. - if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) { + if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); ExprResult InitList = ParseBraceInitializer(); @@ -2645,7 +2795,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { EllipsisLoc); } - Diag(Tok, getLangOpts().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace + Diag(Tok, getLangOpts().CPlusPlus11 ? diag::err_expected_lparen_or_lbrace : diag::err_expected_lparen); return true; } @@ -2892,9 +3042,9 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { case tok::exclaimequal: // 'not_eq' // Alternative tokens do not have identifier info, but their spelling // starts with an alphabetical character. - llvm::SmallString<8> SpellingBuf; + SmallString<8> SpellingBuf; StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); - if (std::isalpha(Spelling[0])) { + if (isLetter(Spelling[0])) { Loc = ConsumeToken(); return &PP.getIdentifierTable().get(Spelling); } @@ -2908,7 +3058,7 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, AttributeList::AS_CXX11)) { case AttributeList::AT_CarriesDependency: case AttributeList::AT_FallThrough: - case AttributeList::AT_NoReturn: { + case AttributeList::AT_CXX11NoReturn: { return true; } @@ -2971,6 +3121,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, ConsumeBracket(); ConsumeBracket(); + llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs; + while (Tok.isNot(tok::r_square)) { // attribute not present if (Tok.is(tok::comma)) { @@ -3004,6 +3156,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName,ScopeName); bool AttrParsed = false; + if (StandardAttr && + !SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second) + Diag(AttrLoc, diag::err_cxx11_attribute_repeated) + << AttrName << SourceRange(SeenAttrs[AttrName]); + // Parse attribute arguments if (Tok.is(tok::l_paren)) { if (ScopeName && ScopeName->getName() == "gnu") { @@ -3050,6 +3207,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, /// attribute-specifier-seq[opt] attribute-specifier void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc) { + assert(getLangOpts().CPlusPlus11); + SourceLocation StartLoc = Tok.getLocation(), Loc; if (!endLoc) endLoc = &Loc; |