Skip to content

Commit

Permalink
Diagnose declspecs occuring after virt-specifier-seq and generate fix…
Browse files Browse the repository at this point in the history
…it hints

Summary: This fixes PR22075.

Reviewers: rsmith

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D6828

llvm-svn: 233160
  • Loading branch information
ehsan committed Mar 25, 2015
1 parent d811ffa commit 93ed5cf
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 3 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Expand Up @@ -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<
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Parse/Parser.h
Expand Up @@ -2293,6 +2293,8 @@ class Parser : public CodeCompletionHandler {
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);
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang/Sema/DeclSpec.h
Expand Up @@ -2180,7 +2180,7 @@ class VirtSpecifiers {
VS_Sealed = 4
};

VirtSpecifiers() : Specifiers(0) { }
VirtSpecifiers() : Specifiers(0), LastSpecifier(VS_None) { }

bool SetSpecifier(Specifier VS, SourceLocation Loc,
const char *&PrevSpec);
Expand All @@ -2198,12 +2198,16 @@ class VirtSpecifiers {

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;
};

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseDecl.cpp
Expand Up @@ -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,
Expand Down
52 changes: 51 additions & 1 deletion clang/lib/Parse/ParseDeclCXX.cpp
Expand Up @@ -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)) {
Expand Down Expand Up @@ -2071,6 +2074,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
Diag(Attr->getLoc(), diag::warn_gcc_attribute_location);
Attr = Attr->getNext();
}
MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS);
}
}

Expand All @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/DeclSpec.cpp
Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions clang/test/FixIt/fixit-cxx0x.cpp
Expand Up @@ -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'}}
};
}

0 comments on commit 93ed5cf

Please sign in to comment.