diff options
author | Ehsan Akhgari <ehsan.akhgari@gmail.com> | 2015-03-25 00:53:27 +0000 |
---|---|---|
committer | Ehsan Akhgari <ehsan.akhgari@gmail.com> | 2015-03-25 00:53:27 +0000 |
commit | 93ed5cf5e62e828248ec80ba3a032df1d2159fdc (patch) | |
tree | 11e764899f5471726487b27477e05f56fb75173b | |
parent | d811ffa5e6c0f30367b98a137298498bfc671bf2 (diff) | |
download | bcm5719-llvm-93ed5cf5e62e828248ec80ba3a032df1d2159fdc.tar.gz bcm5719-llvm-93ed5cf5e62e828248ec80ba3a032df1d2159fdc.zip |
Diagnose declspecs occuring after virt-specifier-seq and generate fixit hints
Summary: This fixes PR22075.
Reviewers: rsmith
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D6828
llvm-svn: 233160
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 2 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 2 | ||||
-rw-r--r-- | clang/include/clang/Sema/DeclSpec.h | 6 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 52 | ||||
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 3 | ||||
-rw-r--r-- | clang/test/FixIt/fixit-cxx0x.cpp | 11 |
7 files changed, 75 insertions, 3 deletions
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 56a984baf4c..d96fbac50d3 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -183,6 +183,8 @@ def warn_attribute_no_decl : Warning< "attribute %0 ignored, because it is not attached to a declaration">, InGroup<IgnoredAttributes>; def err_expected_method_body : Error<"expected method body">; +def err_declspec_after_virtspec : Error< + "'%0' qualifier may not appear after the virtual specifier '%1'">; def err_invalid_token_after_toplevel_declarator : Error< "expected ';' after top level declarator">; def err_invalid_token_after_declarator_suggest_equal : Error< diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 498af7c5b7c..ba3fd133cc6 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2293,6 +2293,8 @@ private: VirtSpecifiers &VS, ExprResult &BitfieldSize, LateParsedAttrList &LateAttrs); + void MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(Declarator &D, + VirtSpecifiers &VS); void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), ParsingDeclRAIIObject *DiagsFromTParams = nullptr); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 76ccb1d23a8..03c3427d68b 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -2180,7 +2180,7 @@ public: VS_Sealed = 4 }; - VirtSpecifiers() : Specifiers(0) { } + VirtSpecifiers() : Specifiers(0), LastSpecifier(VS_None) { } bool SetSpecifier(Specifier VS, SourceLocation Loc, const char *&PrevSpec); @@ -2198,12 +2198,16 @@ public: static const char *getSpecifierName(Specifier VS); + SourceLocation getFirstLocation() const { return FirstLocation; } SourceLocation getLastLocation() const { return LastLocation; } + Specifier getLastSpecifier() const { return LastSpecifier; } private: unsigned Specifiers; + Specifier LastSpecifier; SourceLocation VS_overrideLoc, VS_finalLoc; + SourceLocation FirstLocation; SourceLocation LastLocation; }; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index b4a76642981..c19759e596c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5329,7 +5329,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, diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 3403cdea7ae..aac7d630954 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2037,10 +2037,13 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( BitfieldSize = ParseConstantExpression(); if (BitfieldSize.isInvalid()) SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); - } else + } else { ParseOptionalCXX11VirtSpecifierSeq( VS, getCurrentClass().IsInterface, DeclaratorInfo.getDeclSpec().getFriendSpecLoc()); + if (!VS.isUnset()) + MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS); + } // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { @@ -2071,6 +2074,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( Diag(Attr->getLoc(), diag::warn_gcc_attribute_location); Attr = Attr->getNext(); } + MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS); } } @@ -2084,6 +2088,52 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( return false; } +/// \brief Look for declaration specifiers possibly occurring after C++11 +/// virt-specifier-seq and diagnose them. +void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( + Declarator &D, + VirtSpecifiers &VS) { + DeclSpec DS(AttrFactory); + + // GNU-style and C++11 attributes are not allowed here, but they will be + // handled by the caller. Diagnose everything else. + ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, false); + D.ExtendWithDeclSpec(DS); + + if (D.isFunctionDeclarator()) { + if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { + auto DeclSpecCheck = [&] (DeclSpec::TQ TypeQual, + const char *FixItName, + SourceLocation SpecLoc, + unsigned* QualifierLoc) { + FixItHint Insertion; + auto &Function = D.getFunctionTypeInfo(); + if (DS.getTypeQualifiers() & TypeQual) { + if (!(Function.TypeQuals & TypeQual)) { + std::string Name(FixItName); + Name += " "; + Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name.c_str()); + Function.TypeQuals |= TypeQual; + *QualifierLoc = SpecLoc.getRawEncoding(); + } + Diag(SpecLoc, diag::err_declspec_after_virtspec) + << FixItName + << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) + << FixItHint::CreateRemoval(SpecLoc) + << Insertion; + } + }; + auto &Function = D.getFunctionTypeInfo(); + DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc(), + &Function.ConstQualifierLoc); + DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc(), + &Function.VolatileQualifierLoc); + DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc(), + &Function.RestrictQualifierLoc); + } + } +} + /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// /// member-declaration: diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 5e349bc2ad2..f6689a96bdc 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -1220,7 +1220,10 @@ void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, const char *&PrevSpec) { + if (!FirstLocation.isValid()) + FirstLocation = Loc; LastLocation = Loc; + LastSpecifier = VS; if (Specifiers & VS) { PrevSpec = getSpecifierName(VS); diff --git a/clang/test/FixIt/fixit-cxx0x.cpp b/clang/test/FixIt/fixit-cxx0x.cpp index 49a05ff8d1e..6e096e5e78e 100644 --- a/clang/test/FixIt/fixit-cxx0x.cpp +++ b/clang/test/FixIt/fixit-cxx0x.cpp @@ -158,3 +158,14 @@ namespace MisplacedParameterPack { template <int... N...> // expected-error {{'...' must immediately precede declared identifier}} void redundantEllipsisInNonTypeTemplateParameter(); } + +namespace MisplacedDeclSpecAfterVirtSpec { + struct B { + virtual void f(); + virtual void f() volatile const; + }; + struct D : B { + virtual void f() override; + virtual void f() override final const volatile; // expected-error {{'const' qualifier may not appear after the virtual specifier 'final'}} expected-error {{'volatile' qualifier may not appear after the virtual specifier 'final'}} + }; +} |