def ext_enum_base_in_type_specifier : ExtWarn<
"non-defining declaration of enumeration with a fixed underlying type is "
"only permitted as a standalone declaration"
- "%select{|; missing list of enumerators?}0">, InGroup<DiagGroup<"enum-base">>;
+ "%select{|; missing list of enumerators?}0">,
+ InGroup<DiagGroup<"elaborated-enum-base">>, DefaultError;
+def ext_elaborated_enum_class : ExtWarn<
+ "reference to enumeration must use 'enum' not 'enum %select{struct|class}0'">,
+ InGroup<DiagGroup<"elaborated-enum-class">>, DefaultError;
+def err_scoped_enum_missing_identifier : Error<
+ "scoped enumeration requires a name">;
+def ext_scoped_enum : ExtWarn<
+ "scoped enumerations are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_scoped_enum : Warning<
+ "scoped enumerations are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_anonymous_enum_bitfield : Error<
"ISO C++ only allows ':' in member enumeration declaration to introduce "
"a fixed underlying type, not an anonymous bit-field">;
def err_duplicate_virt_specifier : Error<
"class member already marked '%0'">;
-def err_scoped_enum_missing_identifier : Error<
- "scoped enumeration requires a name">;
-def ext_scoped_enum : ExtWarn<
- "scoped enumerations are a C++11 extension">, InGroup<CXX11>;
-def warn_cxx98_compat_scoped_enum : Warning<
- "scoped enumerations are incompatible with C++98">,
- InGroup<CXX98Compat>, DefaultIgnore;
-
def err_expected_parameter_pack : Error<
"expected the name of a parameter pack">;
def err_paren_sizeof_parameter_pack : 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_underlying_type_of_incomplete_enum : Error<
D.takeAttributes(attrs, endLoc);
}
}
- void MaybeParseCXX11Attributes(ParsedAttributes &attrs,
+ bool MaybeParseCXX11Attributes(ParsedAttributes &attrs,
SourceLocation *endLoc = nullptr) {
if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrsWithRange(AttrFactory);
ParseCXX11Attributes(attrsWithRange, endLoc);
attrs.takeAllFrom(attrsWithRange);
+ return true;
}
+ return false;
}
void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc = nullptr,
/// ':' type-specifier-seq
///
/// [C++] elaborated-type-specifier:
-/// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier
+/// [C++] 'enum' nested-name-specifier[opt] identifier
///
void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
TypeResult BaseType;
SourceRange BaseRange;
- bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope;
+ bool CanBeBitfield = (getCurScope()->getFlags() & Scope::ClassScope) &&
+ ScopedEnumKWLoc.isInvalid() && Name;
// Parse the fixed underlying type.
if (Tok.is(tok::colon)) {
// the decl-specifier-seq of a member-declaration is parsed as part of
// an enum-base.
//
- // Other lamguage modes supporting enumerations with fixed underlying types
+ // Other language modes supporting enumerations with fixed underlying types
// do not have clear rules on this, so we disambiguate to determine whether
// the tokens form a bit-field width or an enum-base.
} else if (CanHaveEnumBase || !ColonIsSacred) {
SourceLocation ColonLoc = ConsumeToken();
- BaseType = ParseTypeName(&BaseRange);
- BaseRange.setBegin(ColonLoc);
+ // Parse a type-specifier-seq as a type. We can't just ParseTypeName here,
+ // because under -fms-extensions,
+ // enum E : int *p;
+ // declares 'enum E : int; E *p;' not 'enum E : int*; E p;'.
+ DeclSpec DS(AttrFactory);
+ ParseSpecifierQualifierList(DS, AS, DeclSpecContext::DSC_type_specifier);
+ Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
+ BaseType = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+
+ BaseRange = SourceRange(ColonLoc, DeclaratorInfo.getSourceRange().getEnd());
if (!getLangOpts().ObjC) {
if (getLangOpts().CPlusPlus11)
<< SourceRange(DS.getFriendSpecLoc());
ConsumeBrace();
SkipUntil(tok::r_brace, StopAtSemi);
+ // Discard any other definition-only pieces.
+ attrs.clear();
+ ScopedEnumKWLoc = SourceLocation();
+ IsScopedUsingClassTag = false;
+ BaseType = TypeResult();
TUK = Sema::TUK_Friend;
} else {
TUK = Sema::TUK_Definition;
(Tok.is(tok::semi) ||
(Tok.isAtStartOfLine() &&
!isValidAfterTypeSpecifier(CanBeBitfield)))) {
+ // An opaque-enum-declaration is required to be standalone (no preceding or
+ // following tokens in the declaration). Sema enforces this separately by
+ // diagnosing anything else in the DeclSpec.
TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration;
if (Tok.isNot(tok::semi)) {
// A semicolon was missing after this declaration. Diagnose and recover.
TUK = Sema::TUK_Reference;
}
- // If this is an elaborated type specifier, and we delayed
- // diagnostics before, just merge them into the current pool.
+ bool IsElaboratedTypeSpecifier =
+ TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend;
+
+ // If this is an elaborated type specifier nested in a larger declaration,
+ // and we delayed diagnostics before, just merge them into the current pool.
if (TUK == Sema::TUK_Reference && shouldDelayDiagsInTag) {
diagsFromTag.redelay();
}
- // A C++11 enum-base can only appear as part of an enum definition or an
- // opaque-enum-declaration. MSVC and ObjC permit an enum-base anywhere.
- if (BaseType.isUsable() && TUK != Sema::TUK_Definition &&
- !getLangOpts().ObjC && !getLangOpts().MicrosoftExt &&
- !(CanBeOpaqueEnumDeclaration && Tok.is(tok::semi))) {
- Diag(BaseRange.getBegin(), diag::ext_enum_base_in_type_specifier)
- << (AllowEnumSpecifier == AllowDefiningTypeSpec::Yes) << BaseRange;
- }
-
MultiTemplateParamsArg TParams;
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
TUK != Sema::TUK_Reference) {
TemplateInfo.TemplateParams->size());
}
- if (TUK == Sema::TUK_Reference)
- ProhibitAttributes(attrs);
-
if (!Name && TUK != Sema::TUK_Definition) {
Diag(Tok, diag::err_enumerator_unnamed_no_def);
return;
}
+ // An elaborated-type-specifier has a much more constrained grammar:
+ //
+ // 'enum' nested-name-specifier[opt] identifier
+ //
+ // If we parsed any other bits, reject them now.
+ //
+ // MSVC and (for now at least) Objective-C permit a full enum-specifier
+ // or opaque-enum-declaration anywhere.
+ if (IsElaboratedTypeSpecifier && !getLangOpts().MicrosoftExt &&
+ !getLangOpts().ObjC) {
+ ProhibitAttributes(attrs);
+ if (BaseType.isUsable())
+ Diag(BaseRange.getBegin(), diag::ext_enum_base_in_type_specifier)
+ << (AllowEnumSpecifier == AllowDefiningTypeSpec::Yes) << BaseRange;
+ else if (ScopedEnumKWLoc.isValid())
+ Diag(ScopedEnumKWLoc, diag::ext_elaborated_enum_class)
+ << FixItHint::CreateRemoval(ScopedEnumKWLoc) << IsScopedUsingClassTag;
+ }
+
stripTypeAttributesOffDeclSpec(attrs, DS, TUK);
Sema::SkipBodyInfo SkipBody;
return;
}
- if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
+ if (Tok.is(tok::l_brace) && TUK == Sema::TUK_Definition) {
Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl;
ParseEnumBody(StartLoc, D);
if (SkipBody.CheckSameAsPrevious &&
assert(Tok.is(tok::colon) && "should be looking at the ':'");
RevertingTentativeParsingAction PA(*this);
+ // ':'
ConsumeToken();
+ // type-specifier-seq
bool InvalidAsDeclSpec = false;
+ // FIXME: We could disallow non-type decl-specifiers here, but it makes no
+ // difference: those specifiers are ill-formed regardless of the
+ // interpretation.
TPResult R = isCXXDeclarationSpecifier(/*BracedCastResult*/ TPResult::True,
&InvalidAsDeclSpec);
if (R == TPResult::Ambiguous) {
return true;
// A second decl-specifier unambiguously indicatges an enum-base.
- // The grammar permits an arbitrary type-name here, but we need an
- // integral type, so no declarator pieces could ever work.
R = isCXXDeclarationSpecifier(TPResult::True, &InvalidAsDeclSpec);
}
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);
+ if (TUK == TUK_Reference || TUK == TUK_Friend)
return PrevTagDecl;
- }
QualType EnumUnderlyingTy;
if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
struct A;
void (A::*mp1)(int) __unaligned;
}
+
+namespace enum_class {
+ // MSVC allows opaque-enum-declaration syntax anywhere an
+ // elaborated-type-specifier can appear.
+ // FIXME: Most of these are missing warnings.
+ enum E0 *p0; // expected-warning {{Microsoft extension}}
+ enum class E1 : int *p1;
+ enum E2 : int *p2;
+ enum class E3 *p3;
+ auto f4() -> enum class E4 { return {}; }
+ auto f5() -> enum E5 : int { return {}; } // FIXME: MSVC rejects this and crashes if the body is {}.
+ auto f6() -> enum E6 { return {}; } // expected-warning {{Microsoft extension}}
+}
struct S8 {
enum E : int { a = id(U()) }; // expected-error {{no viable conversion}}
};
+
+ // PR26249: Disambiguate 'enum :' as an enum-base always, even if that would
+ // be ill-formed. It cannot be an elaborated-type-specifier.
+ struct S {
+ enum : undeclared_type { v = 0 }; // expected-error {{unknown type name 'undeclared_type'}}
+ };
}
namespace trailing_return {
int x[sizeof(enum E : int)]; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration}}
namespace PR24297 {
- enum struct E a; // expected-error {{must use 'enum' not 'enum class'}} FIXME: we used 'enum struct'
- enum class F b; // FIXME: invalid, no prior declaration of 'enum F' and in any case we cannot use 'class' here
+ enum struct E a; // expected-error {{must use 'enum' not 'enum struct'}}
+ enum class F b; // expected-error {{must use 'enum' not 'enum class'}}
enum G : int c; // expected-error {{only permitted as a standalone declaration}}
enum struct H : int d; // expected-error {{only permitted as a standalone declaration}}
enum class I : int e; // expected-error {{only permitted as a standalone declaration}}
enum X x; // expected-error {{ISO C++ forbids forward reference}} expected-error {{incomplete}} expected-note {{forward declaration}}
- enum struct E *pa; // expected-error {{must use 'enum' not 'enum class'}} FIXME: we used 'enum struct'
+ enum struct E *pa; // expected-error {{must use 'enum' not 'enum struct'}}
enum class F *pb; // expected-error {{must use 'enum' not 'enum class'}}
- enum G : int *pc; // expected-error {{only permitted as a standalone declaration}} expected-error {{'int *' is an invalid underlying type}}
- enum struct H : int *pd; // expected-error {{only permitted as a standalone declaration}} expected-error {{'int *' is an invalid underlying type}} FIXME: expected-error {{must use 'enum' not 'enum class'}}
- enum class I : int *pe; // expected-error {{only permitted as a standalone declaration}} expected-error {{'int *' is an invalid underlying type}} FIXME: expected-error {{must use 'enum' not 'enum class'}}
+ enum G : int *pc; // expected-error {{only permitted as a standalone declaration}}
+ enum struct H : int *pd; // expected-error {{only permitted as a standalone declaration}}
+ enum class I : int *pe; // expected-error {{only permitted as a standalone declaration}}
enum Y *py; // expected-error {{ISO C++ forbids forward reference}}
}
}
};
enum : long x; // expected-error{{unnamed enumeration must be a definition}} \
-// expected-warning{{only permitted as a standalone declaration}} \
// expected-warning{{declaration does not declare anything}}
void PR9333() {
}
namespace N2764 {
+ enum class E *x0a; // expected-error {{reference to enumeration must use 'enum' not 'enum class'}}
+ enum E2 *x0b; // OK
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 class E x2 = E::a; // expected-error {{reference to 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 E; // expected-error {{reference to 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}}
+ friend enum class H {}; // expected-error {{forward reference}} expected-error {{cannot define a type in a friend declaration}}
+ friend enum I : int {}; // expected-error {{forward reference}} expected-error {{cannot define a type in a friend declaration}}
enum A : int;
A a;
struct X {
enum Color : 4;
enum Color field1: 4;
- enum Other : Integer field2; // c-warning {{only permitted as a standalone}}
- enum Other : Integer field3 : 4; // c-warning {{only permitted as a standalone}}
+ enum Other : Integer field2; // c-error {{only permitted as a standalone}}
+ enum Other : Integer field3 : 4; // c-error {{only permitted as a standalone}}
enum : Integer { Blah, Blarg } field4 : 4;
};
template void f2<int>();
template<typename T> void f3() {
- void g3(enum class x3);
+ enum class x3;
+ void g3(enum x3);
enum class x3 { nothing };
}
template void f3<int>();
template <class T> struct S3 {
void m() {
- f<enum class new_enum>();
+ enum class new_enum;
+ f<enum new_enum>();
}
};
template struct S3<int>;