From a0cadf2f4b91568c5b91685ba8ff18b8f8509868 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Wed, 25 Mar 2015 00:53:33 +0000 Subject: [PATCH] Diagnose ref-qualifiers occuring after virt-specifier-seq and generate fixit hints Summary: Follow-up to the fix of PR22075. Reviewers: rsmith Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D7012 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@233161 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 2 ++ lib/Parse/ParseDecl.cpp | 25 +++++++++++++++++-------- lib/Parse/ParseDeclCXX.cpp | 20 ++++++++++++++++++-- test/FixIt/fixit-cxx0x.cpp | 10 +++++++++- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index ba3fd133cc..179bc038d5 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2214,6 +2214,8 @@ private: BalancedDelimiterTracker &Tracker, bool IsAmbiguous, bool RequiresArg = false); + bool ParseRefQualifier(bool &RefQualifierIsLValueRef, + SourceLocation &RefQualifierLoc); bool isFunctionDeclaratorIdentifierList(); void ParseFunctionDeclaratorIdentifierList( Declarator &D, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c19759e596..5726fb622c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5342,15 +5342,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 @@ -5446,6 +5439,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) /// diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index aac7d63095..3824f4b0d3 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2101,13 +2101,13 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( D.ExtendWithDeclSpec(DS); if (D.isFunctionDeclarator()) { + auto &Function = D.getFunctionTypeInfo(); 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); @@ -2123,7 +2123,6 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( << Insertion; } }; - auto &Function = D.getFunctionTypeInfo(); DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc(), &Function.ConstQualifierLoc); DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc(), @@ -2131,6 +2130,23 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc(), &Function.RestrictQualifierLoc); } + + // Parse ref-qualifiers. + bool RefQualifierIsLValueRef = true; + SourceLocation RefQualifierLoc; + if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) { + const char *Name = (RefQualifierIsLValueRef ? "& " : "&& "); + FixItHint Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name); + Function.RefQualifierIsLValueRef = RefQualifierIsLValueRef; + Function.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); + + Diag(RefQualifierLoc, diag::err_declspec_after_virtspec) + << (RefQualifierIsLValueRef ? "&" : "&&") + << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) + << FixItHint::CreateRemoval(RefQualifierLoc) + << Insertion; + D.SetRangeEnd(RefQualifierLoc); + } } } diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp index 6e096e5e78..5aebcb3def 100644 --- a/test/FixIt/fixit-cxx0x.cpp +++ b/test/FixIt/fixit-cxx0x.cpp @@ -159,7 +159,7 @@ namespace MisplacedParameterPack { void redundantEllipsisInNonTypeTemplateParameter(); } -namespace MisplacedDeclSpecAfterVirtSpec { +namespace MisplacedDeclAndRefSpecAfterVirtSpec { struct B { virtual void f(); virtual void f() volatile const; @@ -168,4 +168,12 @@ namespace MisplacedDeclSpecAfterVirtSpec { 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'}} }; + struct B2 { + virtual void f() &; + virtual void f() volatile const &&; + }; + struct D2 : B2 { + virtual void f() override &; // expected-error {{'&' qualifier may not appear after the virtual specifier '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'}} expected-error {{'&&' qualifier may not appear after the virtual specifier 'final'}} + }; } -- 2.40.0