forked from OSchip/llvm-project
Update C++11 scoped enumeration support to match the final proposal:
- reject definitions of enums within friend declarations - require 'enum', not 'enum class', for non-declaring references to scoped enumerations llvm-svn: 147824
This commit is contained in:
parent
38ef9a9b94
commit
0f8ee22655
|
@ -535,7 +535,7 @@ def err_ctor_init_missing_comma : Error<
|
|||
"missing ',' between base or member initializers">;
|
||||
|
||||
// C++ declarations
|
||||
def err_friend_decl_defines_class : Error<
|
||||
def err_friend_decl_defines_type : Error<
|
||||
"cannot define a type in a friend declaration">;
|
||||
def err_missing_whitespace_digraph : Error<
|
||||
"found '<::' after a "
|
||||
|
|
|
@ -1228,6 +1228,9 @@ def err_enum_redeclare_fixed_mismatch : Error<
|
|||
"enumeration previously declared with %select{non|}0fixed underlying type">;
|
||||
def err_enum_redeclare_scoped_mismatch : Error<
|
||||
"enumeration previously declared as %select{un|}0scoped">;
|
||||
def err_enum_class_reference : Error<
|
||||
"reference to %select{|scoped }0enumeration must use 'enum' "
|
||||
"not 'enum class'">;
|
||||
def err_only_enums_have_underlying_types : Error<
|
||||
"only enumeration types have underlying types">;
|
||||
def err_incomplete_type_no_underlying_type : Error<
|
||||
|
|
|
@ -1171,7 +1171,8 @@ public:
|
|||
AttributeList *Attr, AccessSpecifier AS,
|
||||
SourceLocation ModulePrivateLoc,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
|
||||
bool &OwnedDecl, bool &IsDependent,
|
||||
SourceLocation ScopedEnumKWLoc,
|
||||
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType);
|
||||
|
||||
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
|
||||
|
|
|
@ -2865,15 +2865,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
return cutOffParsing();
|
||||
}
|
||||
|
||||
bool IsScopedEnum = false;
|
||||
SourceLocation ScopedEnumKWLoc;
|
||||
bool IsScopedUsingClassTag = false;
|
||||
|
||||
if (getLang().CPlusPlus0x &&
|
||||
(Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
|
||||
Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
|
||||
IsScopedEnum = true;
|
||||
IsScopedUsingClassTag = Tok.is(tok::kw_class);
|
||||
ConsumeToken();
|
||||
ScopedEnumKWLoc = ConsumeToken();
|
||||
}
|
||||
|
||||
// If attributes exist after tag, parse them.
|
||||
|
@ -2922,11 +2921,11 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
NameLoc = ConsumeToken();
|
||||
}
|
||||
|
||||
if (!Name && IsScopedEnum) {
|
||||
if (!Name && ScopedEnumKWLoc.isValid()) {
|
||||
// C++0x 7.2p2: The optional identifier shall not be omitted in the
|
||||
// declaration of a scoped enumeration.
|
||||
Diag(Tok, diag::err_scoped_enum_missing_identifier);
|
||||
IsScopedEnum = false;
|
||||
ScopedEnumKWLoc = SourceLocation();
|
||||
IsScopedUsingClassTag = false;
|
||||
}
|
||||
|
||||
|
@ -2993,16 +2992,20 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
}
|
||||
}
|
||||
|
||||
// There are three options here. If we have 'enum foo;', then this is a
|
||||
// forward declaration. If we have 'enum foo {...' then this is a
|
||||
// definition. Otherwise we have something like 'enum foo xyz', a reference.
|
||||
// There are four options here. If we have 'friend enum foo;' then this is a
|
||||
// friend declaration, and cannot have an accompanying definition. If we have
|
||||
// 'enum foo;', then this is a forward declaration. If we have
|
||||
// 'enum foo {...' then this is a definition. Otherwise we have something
|
||||
// like 'enum foo xyz', a reference.
|
||||
//
|
||||
// This is needed to handle stuff like this right (C99 6.7.2.3p11):
|
||||
// enum foo {..}; void bar() { enum foo; } <- new foo in bar.
|
||||
// enum foo {..}; void bar() { enum foo x; } <- use of old foo.
|
||||
//
|
||||
Sema::TagUseKind TUK;
|
||||
if (Tok.is(tok::l_brace))
|
||||
if (DS.isFriendSpecified())
|
||||
TUK = Sema::TUK_Friend;
|
||||
else if (Tok.is(tok::l_brace))
|
||||
TUK = Sema::TUK_Definition;
|
||||
else if (Tok.is(tok::semi))
|
||||
TUK = Sema::TUK_Declaration;
|
||||
|
@ -3036,7 +3039,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
StartLoc, SS, Name, NameLoc, attrs.getList(),
|
||||
AS, DS.getModulePrivateSpecLoc(),
|
||||
MultiTemplateParamsArg(Actions),
|
||||
Owned, IsDependent, IsScopedEnum,
|
||||
Owned, IsDependent, ScopedEnumKWLoc,
|
||||
IsScopedUsingClassTag, BaseType);
|
||||
|
||||
if (IsDependent) {
|
||||
|
@ -3075,9 +3078,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
DS.SetTypeSpecError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Tok.is(tok::l_brace))
|
||||
|
||||
if (Tok.is(tok::l_brace)) {
|
||||
if (TUK == Sema::TUK_Friend)
|
||||
Diag(Tok, diag::err_friend_decl_defines_type)
|
||||
<< SourceRange(DS.getFriendSpecLoc());
|
||||
ParseEnumBody(StartLoc, TagDecl);
|
||||
}
|
||||
|
||||
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
|
||||
NameLoc.isValid() ? NameLoc : StartLoc,
|
||||
|
|
|
@ -1115,7 +1115,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
if (DS.isFriendSpecified()) {
|
||||
// C++ [class.friend]p2:
|
||||
// A class shall not be defined in a friend declaration.
|
||||
Diag(Tok.getLocation(), diag::err_friend_decl_defines_class)
|
||||
Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
|
||||
<< SourceRange(DS.getFriendSpecLoc());
|
||||
|
||||
// Skip everything up to the semicolon, so that this looks like a proper
|
||||
|
@ -1277,8 +1277,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
|
||||
SS, Name, NameLoc, attrs.getList(), AS,
|
||||
DS.getModulePrivateSpecLoc(),
|
||||
TParams, Owned, IsDependent, false,
|
||||
false, clang::TypeResult());
|
||||
TParams, Owned, IsDependent,
|
||||
SourceLocation(), false,
|
||||
clang::TypeResult());
|
||||
|
||||
// If ActOnTag said the type was dependent, try again with the
|
||||
// less common call.
|
||||
|
|
|
@ -7580,7 +7580,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
SourceLocation ModulePrivateLoc,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
bool &OwnedDecl, bool &IsDependent,
|
||||
bool ScopedEnum, bool ScopedEnumUsesClassTag,
|
||||
SourceLocation ScopedEnumKWLoc,
|
||||
bool ScopedEnumUsesClassTag,
|
||||
TypeResult UnderlyingType) {
|
||||
// If this is not a definition, it must have a name.
|
||||
assert((Name != 0 || TUK == TUK_Definition) &&
|
||||
|
@ -7589,6 +7590,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
|
||||
OwnedDecl = false;
|
||||
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
|
||||
bool ScopedEnum = ScopedEnumKWLoc.isValid();
|
||||
|
||||
// FIXME: Check explicit specializations more carefully.
|
||||
bool isExplicitSpecialization = false;
|
||||
|
@ -7919,6 +7921,16 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) {
|
||||
const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl);
|
||||
|
||||
// If this is an elaborated-type-specifier for a scoped enumeration,
|
||||
// the 'class' keyword is not necessary and not permitted.
|
||||
if (TUK == TUK_Reference || TUK == TUK_Friend) {
|
||||
if (ScopedEnum)
|
||||
Diag(ScopedEnumKWLoc, diag::err_enum_class_reference)
|
||||
<< PrevEnum->isScoped()
|
||||
<< FixItHint::CreateRemoval(ScopedEnumKWLoc);
|
||||
return PrevTagDecl;
|
||||
}
|
||||
|
||||
// All conflicts with previous declarations are recovered by
|
||||
// returning the previous declaration.
|
||||
if (ScopedEnum != PrevEnum->isScoped()) {
|
||||
|
|
|
@ -9851,7 +9851,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
|
|||
Attr, AS_public,
|
||||
/*ModulePrivateLoc=*/SourceLocation(),
|
||||
MultiTemplateParamsArg(), Owned, IsDependent,
|
||||
/*ScopedEnum=*/false,
|
||||
/*ScopedEnumKWLoc=*/SourceLocation(),
|
||||
/*ScopedEnumUsesClassTag=*/false,
|
||||
/*UnderlyingType=*/TypeResult());
|
||||
}
|
||||
|
|
|
@ -6070,7 +6070,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
KWLoc, SS, Name, NameLoc, Attr, AS_none,
|
||||
/*ModulePrivateLoc=*/SourceLocation(),
|
||||
MultiTemplateParamsArg(*this, 0, 0),
|
||||
Owned, IsDependent, false, false,
|
||||
Owned, IsDependent, SourceLocation(), false,
|
||||
TypeResult());
|
||||
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
class A {}; // expected-note 3 {{previous use is here}}
|
||||
class A {}; // expected-note 4 {{previous use is here}}
|
||||
enum E {};
|
||||
|
||||
void a1(struct A);
|
||||
void a2(class A);
|
||||
|
@ -12,8 +13,8 @@ class A1 {
|
|||
friend class A;
|
||||
friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
|
||||
|
||||
friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
|
||||
// expected-warning {{cannot be a friend}}
|
||||
friend enum A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
|
||||
friend enum E; // expected-warning {{cannot be a friend}}
|
||||
};
|
||||
|
||||
template <class T> struct B { // expected-note {{previous use is here}}
|
||||
|
|
|
@ -37,3 +37,12 @@ namespace SemiCommaTypo {
|
|||
f3 override, // expected-error {{expected ';' at end of declaration}}
|
||||
};
|
||||
}
|
||||
|
||||
namespace ScopedEnum {
|
||||
enum class E { a };
|
||||
|
||||
enum class E b = E::a; // expected-error {{must use 'enum' not 'enum class'}}
|
||||
struct S {
|
||||
friend enum class E; // expected-error {{must use 'enum' not 'enum class'}}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -147,3 +147,30 @@ namespace PR11484 {
|
|||
const int val = 104;
|
||||
enum class test1 { owner_dead = val, };
|
||||
}
|
||||
|
||||
namespace N2764 {
|
||||
enum class E { a, b };
|
||||
enum E x1 = E::a; // ok
|
||||
enum class E x2 = E::a; // expected-error {{reference to scoped enumeration must use 'enum' not 'enum class'}}
|
||||
|
||||
enum F { a, b };
|
||||
enum F y1 = a; // ok
|
||||
enum class F y2 = a; // expected-error {{reference to enumeration must use 'enum' not 'enum class'}}
|
||||
|
||||
struct S {
|
||||
friend enum class E; // expected-error {{reference to scoped enumeration must use 'enum' not 'enum class'}}
|
||||
friend enum class F; // expected-error {{reference to enumeration must use 'enum' not 'enum class'}}
|
||||
|
||||
friend enum G {}; // expected-error {{forward reference}} expected-error {{cannot define a type in a friend declaration}}
|
||||
friend enum class H {}; // expected-error {{cannot define a type in a friend declaration}}
|
||||
|
||||
enum A : int;
|
||||
A a;
|
||||
} s;
|
||||
|
||||
enum S::A : int {};
|
||||
|
||||
enum class B;
|
||||
}
|
||||
|
||||
enum class N2764::B {};
|
||||
|
|
Loading…
Reference in New Issue