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

llvm-svn: 233070
This commit is contained in:
Ehsan Akhgari 2015-03-24 13:02:50 +00:00
parent 9a7adfcf3a
commit 86638e59bf
4 changed files with 46 additions and 11 deletions

View File

@ -2214,6 +2214,8 @@ private:
BalancedDelimiterTracker &Tracker, BalancedDelimiterTracker &Tracker,
bool IsAmbiguous, bool IsAmbiguous,
bool RequiresArg = false); bool RequiresArg = false);
bool ParseRefQualifier(bool &RefQualifierIsLValueRef,
SourceLocation &RefQualifierLoc);
bool isFunctionDeclaratorIdentifierList(); bool isFunctionDeclaratorIdentifierList();
void ParseFunctionDeclaratorIdentifierList( void ParseFunctionDeclaratorIdentifierList(
Declarator &D, Declarator &D,

View File

@ -5342,15 +5342,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
} }
// Parse ref-qualifier[opt]. // Parse ref-qualifier[opt].
if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc))
Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_ref_qualifier :
diag::ext_ref_qualifier);
RefQualifierIsLValueRef = Tok.is(tok::amp);
RefQualifierLoc = ConsumeToken();
EndLoc = RefQualifierLoc; EndLoc = RefQualifierLoc;
}
// C++11 [expr.prim.general]p3: // C++11 [expr.prim.general]p3:
// If a declaration declares a member function or member function // If a declaration declares a member function or member function
@ -5446,6 +5439,22 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
FnAttrs, EndLoc); 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 /// isFunctionDeclaratorIdentifierList - This parameter list may have an
/// identifier list form for a K&R-style function: void foo(a,b,c) /// identifier list form for a K&R-style function: void foo(a,b,c)
/// ///

View File

@ -2100,13 +2100,13 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, false); ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, false);
D.ExtendWithDeclSpec(DS); D.ExtendWithDeclSpec(DS);
auto &Function = D.getFunctionTypeInfo();
if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
auto DeclSpecCheck = [&] (DeclSpec::TQ TypeQual, auto DeclSpecCheck = [&] (DeclSpec::TQ TypeQual,
const char *FixItName, const char *FixItName,
SourceLocation SpecLoc, SourceLocation SpecLoc,
unsigned* QualifierLoc) { unsigned* QualifierLoc) {
FixItHint Insertion; FixItHint Insertion;
auto &Function = D.getFunctionTypeInfo();
if (DS.getTypeQualifiers() & TypeQual) { if (DS.getTypeQualifiers() & TypeQual) {
if (!(Function.TypeQuals & TypeQual)) { if (!(Function.TypeQuals & TypeQual)) {
std::string Name(FixItName); std::string Name(FixItName);
@ -2122,7 +2122,6 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
<< Insertion; << Insertion;
} }
}; };
auto &Function = D.getFunctionTypeInfo();
DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc(), DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc(),
&Function.ConstQualifierLoc); &Function.ConstQualifierLoc);
DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc(), DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc(),
@ -2130,6 +2129,23 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc(), DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc(),
&Function.RestrictQualifierLoc); &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);
}
} }
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.

View File

@ -159,7 +159,7 @@ namespace MisplacedParameterPack {
void redundantEllipsisInNonTypeTemplateParameter(); void redundantEllipsisInNonTypeTemplateParameter();
} }
namespace MisplacedDeclSpecAfterVirtSpec { namespace MisplacedDeclAndRefSpecAfterVirtSpec {
struct B { struct B {
virtual void f(); virtual void f();
virtual void f() volatile const; virtual void f() volatile const;
@ -168,4 +168,12 @@ namespace MisplacedDeclSpecAfterVirtSpec {
virtual void f() override; 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'}} 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'}}
};
} }