diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-02-19 23:47:15 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-02-19 23:47:15 +0000 |
commit | 053214013990ad8ec096dafc64aa7c0ad2b05bc0 (patch) | |
tree | 780636c1e0577c4aa63aa31e832b8f8324079cb4 /lib | |
parent | 65f991ccbec43b4a860f70594c92528ee8fb7c6f (diff) | |
download | clang-053214013990ad8ec096dafc64aa7c0ad2b05bc0.tar.gz |
PR15300: Support C++11 attributes on base-specifiers. We don't support any such
attributes yet, so just issue the appropriate diagnostics. Also generalize the
fixit for attributes-in-the-wrong-place code and reuse it here, if attributes
are placed after the access-specifier or 'virtual' in a base specifier.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175575 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 19 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 50 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaStmtAttr.cpp | 4 |
4 files changed, 63 insertions, 27 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 0dd1e0a6f4..cc47ee1d90 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1144,6 +1144,25 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() { llvm_unreachable("All cases handled above."); } +/// DiagnoseMisplacedCXX11Attribute - We have found the opening square brackets +/// of a C++11 attribute-specifier in a location where an attribute is not +/// permitted, but we know where the attributes ought to be written. Parse them +/// anyway, and provide a fixit moving them to the right place. +void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs, + SourceLocation CorrectLocation) { + assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) || + Tok.is(tok::kw_alignas)); + + // Consume the attributes. + SourceLocation Loc = Tok.getLocation(); + ParseCXX11Attributes(Attrs); + CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true); + + Diag(Loc, diag::err_attributes_not_allowed) + << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange) + << FixItHint::CreateRemoval(AttrRange); +} + void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 1a1eeb9402..4d428ceea1 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -802,15 +802,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 @@ -1636,26 +1639,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)) { @@ -1669,6 +1679,8 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { IsVirtual = true; } + CheckMisplacedCXX11Attribute(Attributes, StartLoc); + // Parse the class-name. SourceLocation EndLocation; SourceLocation BaseLoc; @@ -1688,8 +1700,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 @@ -2384,7 +2397,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, /// void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation AttrFixitLoc, - ParsedAttributes &Attrs, + ParsedAttributesWithRange &Attrs, unsigned TagType, Decl *TagDecl) { assert((TagType == DeclSpec::TST_struct || TagType == DeclSpec::TST_interface || @@ -2457,20 +2470,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // 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. - ParsedAttributesWithRange Attributes(AttrFactory); - MaybeParseCXX11Attributes(Attributes); - 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 attributes to the attribute list of the class - // so they can be applied on the class later. - Attrs.takeAllFrom(Attributes); - } + CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc); } if (Tok.is(tok::colon)) { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1711c8726e..8b0ccd7146 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1172,6 +1172,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, /// 'public bar' and 'virtual private baz' are each base-specifiers. BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, + ParsedAttributes &Attributes, bool Virtual, AccessSpecifier Access, ParsedType basetype, SourceLocation BaseLoc, SourceLocation EllipsisLoc) { @@ -1183,6 +1184,22 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, if (!Class) return true; + // We do not support any C++11 attributes on base-specifiers yet. + // Diagnose any attributes we see. + if (!Attributes.empty()) { + for (AttributeList *Attr = Attributes.getList(); Attr; + Attr = Attr->getNext()) { + if (Attr->isInvalid() || + Attr->getKind() == AttributeList::IgnoredAttribute) + continue; + Diag(Attr->getLoc(), + Attr->getKind() == AttributeList::UnknownAttribute + ? diag::warn_unknown_attribute_ignored + : diag::err_base_specifier_attribute) + << Attr->getName(); + } + } + TypeSourceInfo *TInfo = 0; GetTypeFromParser(basetype, &TInfo); diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index b268b4502c..eb0188a0db 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -58,8 +58,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, default: // if we're here, then we parsed a known attribute, but didn't recognize // it as a statement attribute => it is declaration attribute - S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt) - << A.getName()->getName() << St->getLocStart(); + S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) + << A.getName() << St->getLocStart(); return 0; } } |