Parse class-virt-specifier-seqs.

llvm-svn: 124036
This commit is contained in:
Anders Carlsson 2011-01-22 16:56:46 +00:00
parent f2ca389205
commit 4b63d0e0a7
6 changed files with 95 additions and 23 deletions

View File

@ -392,6 +392,8 @@ def warn_deleted_function_accepted_as_extension: ExtWarn<
// C++0x override control // C++0x override control
def err_duplicate_virt_specifier : Error< def err_duplicate_virt_specifier : Error<
"class member already marked '%0'">; "class member already marked '%0'">;
def err_duplicate_class_virt_specifier : Error<
"class already marked '%0'">;
def err_scoped_enum_missing_identifier : Error< def err_scoped_enum_missing_identifier : Error<
"scoped enumeration requires a name">; "scoped enumeration requires a name">;

View File

@ -1528,9 +1528,12 @@ private:
ExprResult ParseCXX0XAlignArgument(SourceLocation Start); ExprResult ParseCXX0XAlignArgument(SourceLocation Start);
VirtSpecifiers::VirtSpecifier isCXX0XVirtSpecifier() const; VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const;
void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS); void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS);
ClassVirtSpecifiers::Specifier isCXX0XClassVirtSpecifier() const;
void ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS);
/// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to
/// enter a new C++ declarator scope and exit it when the function is /// enter a new C++ declarator scope and exit it when the function is
/// finished. /// finished.

View File

@ -1471,7 +1471,7 @@ struct FieldDeclarator {
/// VirtSpecifiers - Represents a C++0x virt-specifier-seq. /// VirtSpecifiers - Represents a C++0x virt-specifier-seq.
class VirtSpecifiers { class VirtSpecifiers {
public: public:
enum VirtSpecifier { enum Specifier {
VS_None = 0, VS_None = 0,
VS_Override = 1, VS_Override = 1,
VS_Final = 2, VS_Final = 2,
@ -1480,7 +1480,7 @@ public:
VirtSpecifiers() : Specifiers(0) { } VirtSpecifiers() : Specifiers(0) { }
bool SetSpecifier(VirtSpecifier VS, SourceLocation Loc, bool SetSpecifier(Specifier VS, SourceLocation Loc,
const char *&PrevSpec); const char *&PrevSpec);
bool isOverrideSpecified() const { return Specifiers & VS_Override; } bool isOverrideSpecified() const { return Specifiers & VS_Override; }
@ -1497,14 +1497,14 @@ private:
SourceLocation VS_overrideLoc, VS_finalLoc, VS_newLoc; SourceLocation VS_overrideLoc, VS_finalLoc, VS_newLoc;
static const char *getSpecifierName(VirtSpecifier VS); static const char *getSpecifierName(Specifier VS);
}; };
/// ClassVirtSpecifiers - Represents a C++0x class-virt-specifier-seq. /// ClassVirtSpecifiers - Represents a C++0x class-virt-specifier-seq.
class ClassVirtSpecifiers { class ClassVirtSpecifiers {
public: public:
enum ClassVirtSpecifier { enum Specifier {
CVS_None = 0, CVS_None = 0,
CVS_Final = 1, CVS_Final = 1,
CVS_Explicit = 2 CVS_Explicit = 2
@ -1512,7 +1512,7 @@ public:
ClassVirtSpecifiers() : Specifiers(0) { } ClassVirtSpecifiers() : Specifiers(0) { }
bool SetSpecifier(ClassVirtSpecifier CVS, SourceLocation Loc, bool SetSpecifier(Specifier CVS, SourceLocation Loc,
const char *&PrevSpec); const char *&PrevSpec);
bool isFinalSpecified() const { return Specifiers & CVS_Final; } bool isFinalSpecified() const { return Specifiers & CVS_Final; }
@ -1526,7 +1526,7 @@ private:
SourceLocation CVS_finalLoc, CVS_explicitLoc; SourceLocation CVS_finalLoc, CVS_explicitLoc;
static const char *getSpecifierName(ClassVirtSpecifier CVS); static const char *getSpecifierName(Specifier CVS);
}; };
} // end namespace clang } // end namespace clang

View File

@ -807,9 +807,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// There are four options here. If we have 'struct foo;', then this // There are four options here. If we have 'struct foo;', then this
// is either a forward declaration or a friend declaration, which // is either a forward declaration or a friend declaration, which
// have to be treated differently. If we have 'struct foo {...' or // have to be treated differently. If we have 'struct foo {...',
// 'struct foo :...' then this is a definition. Otherwise we have // 'struct foo :...' or 'struct foo <class-virt-specifier>' then this is a
// something like 'struct foo xyz', a reference. // definition. Otherwise we have something like 'struct foo xyz', a reference.
// However, in some contexts, things look like declarations but are just // However, in some contexts, things look like declarations but are just
// references, e.g. // references, e.g.
// new struct s; // new struct s;
@ -819,7 +819,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Sema::TagUseKind TUK; Sema::TagUseKind TUK;
if (SuppressDeclarations) if (SuppressDeclarations)
TUK = Sema::TUK_Reference; TUK = Sema::TUK_Reference;
else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){ else if (Tok.is(tok::l_brace) ||
(getLang().CPlusPlus && Tok.is(tok::colon)) ||
isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None) {
if (DS.isFriendSpecified()) { if (DS.isFriendSpecified()) {
// C++ [class.friend]p2: // C++ [class.friend]p2:
// A class shall not be defined in a friend declaration. // A class shall not be defined in a friend declaration.
@ -1004,7 +1006,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// If there is a body, parse it and inform the actions module. // If there is a body, parse it and inform the actions module.
if (TUK == Sema::TUK_Definition) { if (TUK == Sema::TUK_Definition) {
assert(Tok.is(tok::l_brace) || assert(Tok.is(tok::l_brace) ||
(getLang().CPlusPlus && Tok.is(tok::colon))); (getLang().CPlusPlus && Tok.is(tok::colon)) ||
isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None);
if (getLang().CPlusPlus) if (getLang().CPlusPlus)
ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
else else
@ -1268,7 +1271,10 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
/// override /// override
/// final /// final
/// new /// new
VirtSpecifiers::VirtSpecifier Parser::isCXX0XVirtSpecifier() const { VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const {
if (!getLang().CPlusPlus0x)
return VirtSpecifiers::VS_None;
if (Tok.is(tok::kw_new)) if (Tok.is(tok::kw_new))
return VirtSpecifiers::VS_New; return VirtSpecifiers::VS_New;
@ -1297,17 +1303,14 @@ VirtSpecifiers::VirtSpecifier Parser::isCXX0XVirtSpecifier() const {
/// virt-specifier /// virt-specifier
/// virt-specifier-seq virt-specifier /// virt-specifier-seq virt-specifier
void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
if (!getLang().CPlusPlus0x)
return;
while (true) { while (true) {
VirtSpecifiers::VirtSpecifier Specifier = isCXX0XVirtSpecifier(); VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier();
if (Specifier == VirtSpecifiers::VS_None) if (Specifier == VirtSpecifiers::VS_None)
return; return;
// C++ [class.mem]p8: // C++ [class.mem]p8:
// A virt-specifier-seq shall contain at most one of each virt-specifier. // A virt-specifier-seq shall contain at most one of each virt-specifier.
const char* PrevSpec = 0; const char *PrevSpec = 0;
if (VS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec)) if (VS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec))
Diag(Tok.getLocation(), diag::err_duplicate_virt_specifier) Diag(Tok.getLocation(), diag::err_duplicate_virt_specifier)
<< PrevSpec << PrevSpec
@ -1317,6 +1320,58 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
} }
} }
/// isCXX0XClassVirtSpecifier - Determine whether the next token is a C++0x
/// class-virt-specifier.
///
/// class-virt-specifier:
/// final
/// explicit
ClassVirtSpecifiers::Specifier Parser::isCXX0XClassVirtSpecifier() const {
if (!getLang().CPlusPlus0x)
return ClassVirtSpecifiers::CVS_None;
if (Tok.is(tok::kw_explicit))
return ClassVirtSpecifiers::CVS_Explicit;
if (Tok.is(tok::identifier)) {
IdentifierInfo *II = Tok.getIdentifierInfo();
// Initialize the contextual keywords.
if (!Ident_final) {
Ident_final = &PP.getIdentifierTable().get("final");
Ident_override = &PP.getIdentifierTable().get("override");
}
if (II == Ident_final)
return ClassVirtSpecifiers::CVS_Final;
}
return ClassVirtSpecifiers::CVS_None;
}
/// ParseOptionalCXX0XClassVirtSpecifierSeq - Parse a class-virt-specifier-seq.
///
/// class-virt-specifier-seq:
/// class-virt-specifier
/// class-virt-specifier-seq class-virt-specifier
void Parser::ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS) {
while (true) {
ClassVirtSpecifiers::Specifier Specifier = isCXX0XClassVirtSpecifier();
if (Specifier == ClassVirtSpecifiers::CVS_None)
return;
// C++ [class]p1:
// A class-virt-specifier-seq shall contain at most one of each
// class-virt-specifier.
const char *PrevSpec = 0;
if (CVS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec))
Diag(Tok.getLocation(), diag::err_duplicate_class_virt_specifier)
<< PrevSpec
<< FixItHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
}
}
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
/// ///
/// member-declaration: /// member-declaration:
@ -1697,6 +1752,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl) if (TagDecl)
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
ClassVirtSpecifiers CVS;
ParseOptionalCXX0XClassVirtSpecifierSeq(CVS);
if (Tok.is(tok::colon)) { if (Tok.is(tok::colon)) {
ParseBaseClause(TagDecl); ParseBaseClause(TagDecl);

View File

@ -669,7 +669,7 @@ void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc,
} }
} }
bool VirtSpecifiers::SetSpecifier(VirtSpecifier VS, SourceLocation Loc, bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc,
const char *&PrevSpec) { const char *&PrevSpec) {
if (Specifiers & VS) { if (Specifiers & VS) {
PrevSpec = getSpecifierName(VS); PrevSpec = getSpecifierName(VS);
@ -688,7 +688,7 @@ bool VirtSpecifiers::SetSpecifier(VirtSpecifier VS, SourceLocation Loc,
return false; return false;
} }
const char *VirtSpecifiers::getSpecifierName(VirtSpecifier VS) { const char *VirtSpecifiers::getSpecifierName(Specifier VS) {
switch (VS) { switch (VS) {
default: assert(0 && "Unknown specifier"); default: assert(0 && "Unknown specifier");
case VS_Override: return "override"; case VS_Override: return "override";
@ -697,8 +697,7 @@ const char *VirtSpecifiers::getSpecifierName(VirtSpecifier VS) {
} }
} }
bool ClassVirtSpecifiers::SetSpecifier(ClassVirtSpecifier CVS, bool ClassVirtSpecifiers::SetSpecifier(Specifier CVS, SourceLocation Loc,
SourceLocation Loc,
const char *&PrevSpec) { const char *&PrevSpec) {
if (Specifiers & CVS) { if (Specifiers & CVS) {
PrevSpec = getSpecifierName(CVS); PrevSpec = getSpecifierName(CVS);
@ -716,7 +715,7 @@ bool ClassVirtSpecifiers::SetSpecifier(ClassVirtSpecifier CVS,
return false; return false;
} }
const char *ClassVirtSpecifiers::getSpecifierName(ClassVirtSpecifier CVS) { const char *ClassVirtSpecifiers::getSpecifierName(Specifier CVS) {
switch (CVS) { switch (CVS) {
default: assert(0 && "Unknown specifier"); default: assert(0 && "Unknown specifier");
case CVS_Final: return "final"; case CVS_Final: return "final";

View File

@ -0,0 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
namespace Test1 {
class A final { };
class B explicit { };
class C final explicit { };
class D final final { }; // expected-error {{class already marked 'final'}}
class E explicit explicit { }; // expected-error {{class already marked 'explicit'}}
}