forked from OSchip/llvm-project
Fix parsing of enum-base to follow C++11 rules.
Previously we implemented non-standard disambiguation rules to distinguish an enum-base from a bit-field but otherwise treated a : after an elaborated-enum-specifier as introducing an enum-base. That misparses various examples (anywhere an elaborated-type-specifier can appear followed by a colon, such as within a ternary operator or _Generic). We now implement the C++11 rules, with the old cases accepted as extensions where that seemed reasonable. These amount to: * an enum-base must always be accompanied by an enum definition (except in a standalone declaration of the form 'enum E : T;') * in a member-declaration, 'enum E :' always introduces an enum-base, never a bit-field * in a type-specifier (or similar context), 'enum E :' is not permitted; the colon means whatever else it would mean in that context. Fixed underlying types for enums are also permitted in Objective-C and under MS extensions, plus as a language extension in all other modes. The behavior in ObjC and MS extensions modes is unchanged (but the bit-field disambiguation is a bit better); remaining language modes follow the C++11 rules. Fixes PR45726, PR39979, PR19810, PR44941, and most of PR24297, plus C++ core issues 1514 and 1966.
This commit is contained in:
parent
49b32d8041
commit
c90e198107
|
@ -105,6 +105,14 @@ def ext_clang_c_enum_fixed_underlying_type : Extension<
|
|||
def warn_cxx98_compat_enum_fixed_underlying_type : Warning<
|
||||
"enumeration types with a fixed underlying type are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
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">>;
|
||||
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 warn_cxx98_compat_alignof : Warning<
|
||||
"alignof expressions are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
|
|
|
@ -5484,6 +5484,8 @@ def err_bitfield_width_exceeds_type_width : Error<
|
|||
def err_anon_bitfield_width_exceeds_type_width : Error<
|
||||
"width of anonymous bit-field (%0 bits) exceeds %select{width|size}1 "
|
||||
"of its type (%2 bit%s2)">;
|
||||
def err_anon_bitfield_init : Error<
|
||||
"anonymous bit-field cannot have a default member initializer">;
|
||||
def err_incorrect_number_of_vector_initializers : Error<
|
||||
"number of elements must be either one or match the size of the vector">;
|
||||
|
||||
|
|
|
@ -2181,6 +2181,68 @@ private:
|
|||
llvm_unreachable("Missing DeclSpecContext case");
|
||||
}
|
||||
|
||||
/// Whether a defining-type-specifier is permitted in a given context.
|
||||
enum class AllowDefiningTypeSpec {
|
||||
/// The grammar doesn't allow a defining-type-specifier here, and we must
|
||||
/// not parse one (eg, because a '{' could mean something else).
|
||||
No,
|
||||
/// The grammar doesn't allow a defining-type-specifier here, but we permit
|
||||
/// one for error recovery purposes. Sema will reject.
|
||||
NoButErrorRecovery,
|
||||
/// The grammar allows a defining-type-specifier here, even though it's
|
||||
/// always invalid. Sema will reject.
|
||||
YesButInvalid,
|
||||
/// The grammar allows a defining-type-specifier here, and one can be valid.
|
||||
Yes
|
||||
};
|
||||
|
||||
/// Is this a context in which we are parsing defining-type-specifiers (and
|
||||
/// so permit class and enum definitions in addition to non-defining class and
|
||||
/// enum elaborated-type-specifiers)?
|
||||
static AllowDefiningTypeSpec
|
||||
isDefiningTypeSpecifierContext(DeclSpecContext DSC) {
|
||||
switch (DSC) {
|
||||
case DeclSpecContext::DSC_normal:
|
||||
case DeclSpecContext::DSC_class:
|
||||
case DeclSpecContext::DSC_top_level:
|
||||
case DeclSpecContext::DSC_alias_declaration:
|
||||
case DeclSpecContext::DSC_objc_method_result:
|
||||
return AllowDefiningTypeSpec::Yes;
|
||||
|
||||
case DeclSpecContext::DSC_condition:
|
||||
case DeclSpecContext::DSC_template_param:
|
||||
return AllowDefiningTypeSpec::YesButInvalid;
|
||||
|
||||
case DeclSpecContext::DSC_template_type_arg:
|
||||
case DeclSpecContext::DSC_type_specifier:
|
||||
return AllowDefiningTypeSpec::NoButErrorRecovery;
|
||||
|
||||
case DeclSpecContext::DSC_trailing:
|
||||
return AllowDefiningTypeSpec::No;
|
||||
}
|
||||
llvm_unreachable("Missing DeclSpecContext case");
|
||||
}
|
||||
|
||||
/// Is this a context in which an opaque-enum-declaration can appear?
|
||||
static bool isOpaqueEnumDeclarationContext(DeclSpecContext DSC) {
|
||||
switch (DSC) {
|
||||
case DeclSpecContext::DSC_normal:
|
||||
case DeclSpecContext::DSC_class:
|
||||
case DeclSpecContext::DSC_top_level:
|
||||
return true;
|
||||
|
||||
case DeclSpecContext::DSC_alias_declaration:
|
||||
case DeclSpecContext::DSC_objc_method_result:
|
||||
case DeclSpecContext::DSC_condition:
|
||||
case DeclSpecContext::DSC_template_param:
|
||||
case DeclSpecContext::DSC_template_type_arg:
|
||||
case DeclSpecContext::DSC_type_specifier:
|
||||
case DeclSpecContext::DSC_trailing:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("Missing DeclSpecContext case");
|
||||
}
|
||||
|
||||
/// Is this a context in which we can perform class template argument
|
||||
/// deduction?
|
||||
static bool isClassTemplateDeductionContext(DeclSpecContext DSC) {
|
||||
|
@ -2408,17 +2470,14 @@ private:
|
|||
True, False, Ambiguous, Error
|
||||
};
|
||||
|
||||
/// Based only on the given token kind, determine whether we know that
|
||||
/// we're at the start of an expression or a type-specifier-seq (which may
|
||||
/// be an expression, in C++).
|
||||
/// Determine whether we could have an enum-base.
|
||||
///
|
||||
/// This routine does not attempt to resolve any of the trick cases, e.g.,
|
||||
/// those involving lookup of identifiers.
|
||||
/// \p AllowSemi If \c true, then allow a ';' after the enum-base; otherwise
|
||||
/// only consider this to be an enum-base if the next token is a '{'.
|
||||
///
|
||||
/// \returns \c TPR_true if this token starts an expression, \c TPR_false if
|
||||
/// this token starts a type-specifier-seq, or \c TPR_ambiguous if it cannot
|
||||
/// tell.
|
||||
TPResult isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind);
|
||||
/// \return \c false if this cannot possibly be an enum base; \c true
|
||||
/// otherwise.
|
||||
bool isEnumBase(bool AllowSemi);
|
||||
|
||||
/// isCXXDeclarationSpecifier - Returns TPResult::True if it is a
|
||||
/// declaration specifier, TPResult::False if it is not,
|
||||
|
|
|
@ -4443,14 +4443,20 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
|
||||
SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag);
|
||||
|
||||
// Enum definitions should not be parsed in a trailing-return-type.
|
||||
bool AllowDeclaration = DSC != DeclSpecContext::DSC_trailing;
|
||||
// Determine whether this declaration is permitted to have an enum-base.
|
||||
AllowDefiningTypeSpec AllowEnumSpecifier =
|
||||
isDefiningTypeSpecifierContext(DSC);
|
||||
bool CanBeOpaqueEnumDeclaration =
|
||||
DS.isEmpty() && isOpaqueEnumDeclarationContext(DSC);
|
||||
bool CanHaveEnumBase = (getLangOpts().CPlusPlus11 || getLangOpts().ObjC ||
|
||||
getLangOpts().MicrosoftExt) &&
|
||||
(AllowEnumSpecifier == AllowDefiningTypeSpec::Yes ||
|
||||
CanBeOpaqueEnumDeclaration);
|
||||
|
||||
CXXScopeSpec &SS = DS.getTypeSpecScope();
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
// "enum foo : bar;" is not a potential typo for "enum foo::bar;"
|
||||
// if a fixed underlying type is allowed.
|
||||
ColonProtectionRAIIObject X(*this, AllowDeclaration);
|
||||
// "enum foo : bar;" is not a potential typo for "enum foo::bar;".
|
||||
ColonProtectionRAIIObject X(*this);
|
||||
|
||||
CXXScopeSpec Spec;
|
||||
if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr,
|
||||
|
@ -4471,9 +4477,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
SS = Spec;
|
||||
}
|
||||
|
||||
// Must have either 'enum name' or 'enum {...}'.
|
||||
// Must have either 'enum name' or 'enum {...}' or (rarely) 'enum : T { ... }'.
|
||||
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
|
||||
!(AllowDeclaration && Tok.is(tok::colon))) {
|
||||
Tok.isNot(tok::colon)) {
|
||||
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
|
||||
|
||||
// Skip the rest of this declarator, up until the comma or semicolon.
|
||||
|
@ -4503,78 +4509,61 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
diagsFromTag.done();
|
||||
|
||||
TypeResult BaseType;
|
||||
SourceRange BaseRange;
|
||||
|
||||
bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope;
|
||||
|
||||
// Parse the fixed underlying type.
|
||||
bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope;
|
||||
if (AllowDeclaration && Tok.is(tok::colon)) {
|
||||
bool PossibleBitfield = false;
|
||||
if (CanBeBitfield) {
|
||||
// If we're in class scope, this can either be an enum declaration with
|
||||
// an underlying type, or a declaration of a bitfield member. We try to
|
||||
// use a simple disambiguation scheme first to catch the common cases
|
||||
// (integer literal, sizeof); if it's still ambiguous, we then consider
|
||||
// anything that's a simple-type-specifier followed by '(' as an
|
||||
// expression. This suffices because function types are not valid
|
||||
// underlying types anyway.
|
||||
EnterExpressionEvaluationContext Unevaluated(
|
||||
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
||||
TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
|
||||
// If the next token starts an expression, we know we're parsing a
|
||||
// bit-field. This is the common case.
|
||||
if (TPR == TPResult::True)
|
||||
PossibleBitfield = true;
|
||||
// If the next token starts a type-specifier-seq, it may be either a
|
||||
// a fixed underlying type or the start of a function-style cast in C++;
|
||||
// lookahead one more token to see if it's obvious that we have a
|
||||
// fixed underlying type.
|
||||
else if (TPR == TPResult::False &&
|
||||
GetLookAheadToken(2).getKind() == tok::semi) {
|
||||
// Consume the ':'.
|
||||
ConsumeToken();
|
||||
} else {
|
||||
// We have the start of a type-specifier-seq, so we have to perform
|
||||
// tentative parsing to determine whether we have an expression or a
|
||||
// type.
|
||||
TentativeParsingAction TPA(*this);
|
||||
if (Tok.is(tok::colon)) {
|
||||
// This might be an enum-base or part of some unrelated enclosing context.
|
||||
//
|
||||
// 'enum E : base' is permitted in two circumstances:
|
||||
//
|
||||
// 1) As a defining-type-specifier, when followed by '{'.
|
||||
// 2) As the sole constituent of a complete declaration -- when DS is empty
|
||||
// and the next token is ';'.
|
||||
//
|
||||
// The restriction to defining-type-specifiers is important to allow parsing
|
||||
// a ? new enum E : int{}
|
||||
// _Generic(a, enum E : int{})
|
||||
// properly.
|
||||
//
|
||||
// One additional consideration applies:
|
||||
//
|
||||
// C++ [dcl.enum]p1:
|
||||
// A ':' following "enum nested-name-specifier[opt] identifier" within
|
||||
// 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
|
||||
// do not have clear rules on this, so we disambiguate to determine whether
|
||||
// the tokens form a bit-field width or an enum-base.
|
||||
|
||||
// Consume the ':'.
|
||||
ConsumeToken();
|
||||
if (CanBeBitfield && !isEnumBase(CanBeOpaqueEnumDeclaration)) {
|
||||
// Outside C++11, do not interpret the tokens as an enum-base if they do
|
||||
// not make sense as one. In C++11, it's an error if this happens.
|
||||
if (getLangOpts().CPlusPlus11 && !getLangOpts().ObjC &&
|
||||
!getLangOpts().MicrosoftExt)
|
||||
Diag(Tok.getLocation(), diag::err_anonymous_enum_bitfield);
|
||||
} else if (CanHaveEnumBase || !ColonIsSacred) {
|
||||
SourceLocation ColonLoc = ConsumeToken();
|
||||
|
||||
// If we see a type specifier followed by an open-brace, we have an
|
||||
// ambiguity between an underlying type and a C++11 braced
|
||||
// function-style cast. Resolve this by always treating it as an
|
||||
// underlying type.
|
||||
// FIXME: The standard is not entirely clear on how to disambiguate in
|
||||
// this case.
|
||||
if ((getLangOpts().CPlusPlus &&
|
||||
isCXXDeclarationSpecifier(TPResult::True) != TPResult::True) ||
|
||||
(!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) {
|
||||
// We'll parse this as a bitfield later.
|
||||
PossibleBitfield = true;
|
||||
TPA.Revert();
|
||||
} else {
|
||||
// We have a type-specifier-seq.
|
||||
TPA.Commit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Consume the ':'.
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
if (!PossibleBitfield) {
|
||||
SourceRange Range;
|
||||
BaseType = ParseTypeName(&Range);
|
||||
BaseType = ParseTypeName(&BaseRange);
|
||||
BaseRange.setBegin(ColonLoc);
|
||||
|
||||
if (!getLangOpts().ObjC) {
|
||||
if (getLangOpts().CPlusPlus11)
|
||||
Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
|
||||
Diag(ColonLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type)
|
||||
<< BaseRange;
|
||||
else if (getLangOpts().CPlusPlus)
|
||||
Diag(StartLoc, diag::ext_cxx11_enum_fixed_underlying_type);
|
||||
Diag(ColonLoc, diag::ext_cxx11_enum_fixed_underlying_type)
|
||||
<< BaseRange;
|
||||
else if (getLangOpts().MicrosoftExt)
|
||||
Diag(StartLoc, diag::ext_ms_c_enum_fixed_underlying_type);
|
||||
Diag(ColonLoc, diag::ext_ms_c_enum_fixed_underlying_type)
|
||||
<< BaseRange;
|
||||
else
|
||||
Diag(StartLoc, diag::ext_clang_c_enum_fixed_underlying_type);
|
||||
Diag(ColonLoc, diag::ext_clang_c_enum_fixed_underlying_type)
|
||||
<< BaseRange;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4590,9 +4579,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
// enum foo {..}; void bar() { enum foo x; } <- use of old foo.
|
||||
//
|
||||
Sema::TagUseKind TUK;
|
||||
if (!AllowDeclaration) {
|
||||
if (AllowEnumSpecifier == AllowDefiningTypeSpec::No)
|
||||
TUK = Sema::TUK_Reference;
|
||||
} else if (Tok.is(tok::l_brace)) {
|
||||
else if (Tok.is(tok::l_brace)) {
|
||||
if (DS.isFriendSpecified()) {
|
||||
Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
|
||||
<< SourceRange(DS.getFriendSpecLoc());
|
||||
|
@ -4623,6 +4612,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
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) {
|
||||
|
|
|
@ -1283,7 +1283,8 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
|
|||
case tok::annot_pragma_ms_pointers_to_members:
|
||||
return true;
|
||||
case tok::colon:
|
||||
return CouldBeBitfield; // enum E { ... } : 2;
|
||||
return CouldBeBitfield || // enum E { ... } : 2;
|
||||
ColonIsSacred; // _Generic(..., enum E : 2);
|
||||
// Microsoft compatibility
|
||||
case tok::kw___cdecl: // struct foo {...} __cdecl x;
|
||||
case tok::kw___fastcall: // struct foo {...} __fastcall x;
|
||||
|
@ -1680,7 +1681,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
|
||||
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
|
||||
Sema::TagUseKind TUK;
|
||||
if (DSC == DeclSpecContext::DSC_trailing)
|
||||
if (isDefiningTypeSpecifierContext(DSC) == AllowDefiningTypeSpec::No)
|
||||
TUK = Sema::TUK_Reference;
|
||||
else if (Tok.is(tok::l_brace) ||
|
||||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
|
||||
|
|
|
@ -428,6 +428,35 @@ struct Parser::ConditionDeclarationOrInitStatementState {
|
|||
}
|
||||
};
|
||||
|
||||
bool Parser::isEnumBase(bool AllowSemi) {
|
||||
assert(Tok.is(tok::colon) && "should be looking at the ':'");
|
||||
|
||||
RevertingTentativeParsingAction PA(*this);
|
||||
ConsumeToken();
|
||||
|
||||
bool InvalidAsDeclSpec = false;
|
||||
TPResult R = isCXXDeclarationSpecifier(/*BracedCastResult*/ TPResult::True,
|
||||
&InvalidAsDeclSpec);
|
||||
if (R == TPResult::Ambiguous) {
|
||||
// We either have a decl-specifier followed by '(' or an undeclared
|
||||
// identifier.
|
||||
if (TryConsumeDeclarationSpecifier() == TPResult::Error)
|
||||
return true;
|
||||
|
||||
// If we get to the end of the enum-base, we hit either a '{' or a ';'.
|
||||
// Don't bother checking the enumerator-list.
|
||||
if (Tok.is(tok::colon) || (AllowSemi && Tok.is(tok::semi)))
|
||||
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);
|
||||
}
|
||||
|
||||
return R != TPResult::False;
|
||||
}
|
||||
|
||||
/// Disambiguates between a declaration in a condition, a
|
||||
/// simple-declaration in an init-statement, and an expression for
|
||||
/// a condition of a if/switch statement.
|
||||
|
@ -1067,132 +1096,6 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
|
|||
return TPResult::Ambiguous;
|
||||
}
|
||||
|
||||
Parser::TPResult
|
||||
Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
|
||||
switch (Kind) {
|
||||
// Obviously starts an expression.
|
||||
case tok::numeric_constant:
|
||||
case tok::char_constant:
|
||||
case tok::wide_char_constant:
|
||||
case tok::utf8_char_constant:
|
||||
case tok::utf16_char_constant:
|
||||
case tok::utf32_char_constant:
|
||||
case tok::string_literal:
|
||||
case tok::wide_string_literal:
|
||||
case tok::utf8_string_literal:
|
||||
case tok::utf16_string_literal:
|
||||
case tok::utf32_string_literal:
|
||||
case tok::l_square:
|
||||
case tok::l_paren:
|
||||
case tok::amp:
|
||||
case tok::ampamp:
|
||||
case tok::star:
|
||||
case tok::plus:
|
||||
case tok::plusplus:
|
||||
case tok::minus:
|
||||
case tok::minusminus:
|
||||
case tok::tilde:
|
||||
case tok::exclaim:
|
||||
case tok::kw_sizeof:
|
||||
case tok::kw___func__:
|
||||
case tok::kw_const_cast:
|
||||
case tok::kw_delete:
|
||||
case tok::kw_dynamic_cast:
|
||||
case tok::kw_false:
|
||||
case tok::kw_new:
|
||||
case tok::kw_operator:
|
||||
case tok::kw_reinterpret_cast:
|
||||
case tok::kw_static_cast:
|
||||
case tok::kw_this:
|
||||
case tok::kw_throw:
|
||||
case tok::kw_true:
|
||||
case tok::kw_typeid:
|
||||
case tok::kw_alignof:
|
||||
case tok::kw_noexcept:
|
||||
case tok::kw_nullptr:
|
||||
case tok::kw__Alignof:
|
||||
case tok::kw___null:
|
||||
case tok::kw___alignof:
|
||||
case tok::kw___builtin_choose_expr:
|
||||
case tok::kw___builtin_offsetof:
|
||||
case tok::kw___builtin_va_arg:
|
||||
case tok::kw___imag:
|
||||
case tok::kw___real:
|
||||
case tok::kw___FUNCTION__:
|
||||
case tok::kw___FUNCDNAME__:
|
||||
case tok::kw___FUNCSIG__:
|
||||
case tok::kw_L__FUNCTION__:
|
||||
case tok::kw_L__FUNCSIG__:
|
||||
case tok::kw___PRETTY_FUNCTION__:
|
||||
case tok::kw___uuidof:
|
||||
case tok::kw___builtin_unique_stable_name:
|
||||
#define TYPE_TRAIT(N,Spelling,K) \
|
||||
case tok::kw_##Spelling:
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
return TPResult::True;
|
||||
|
||||
// Obviously starts a type-specifier-seq:
|
||||
case tok::kw_char:
|
||||
case tok::kw_const:
|
||||
case tok::kw_double:
|
||||
case tok::kw__Float16:
|
||||
case tok::kw___float128:
|
||||
case tok::kw_enum:
|
||||
case tok::kw_half:
|
||||
case tok::kw_float:
|
||||
case tok::kw_int:
|
||||
case tok::kw__ExtInt:
|
||||
case tok::kw_long:
|
||||
case tok::kw___int64:
|
||||
case tok::kw___int128:
|
||||
case tok::kw_restrict:
|
||||
case tok::kw_short:
|
||||
case tok::kw_signed:
|
||||
case tok::kw_struct:
|
||||
case tok::kw_union:
|
||||
case tok::kw_unsigned:
|
||||
case tok::kw_void:
|
||||
case tok::kw_volatile:
|
||||
case tok::kw__Bool:
|
||||
case tok::kw__Complex:
|
||||
case tok::kw_class:
|
||||
case tok::kw_typename:
|
||||
case tok::kw_wchar_t:
|
||||
case tok::kw_char8_t:
|
||||
case tok::kw_char16_t:
|
||||
case tok::kw_char32_t:
|
||||
case tok::kw__Decimal32:
|
||||
case tok::kw__Decimal64:
|
||||
case tok::kw__Decimal128:
|
||||
case tok::kw___interface:
|
||||
case tok::kw___thread:
|
||||
case tok::kw_thread_local:
|
||||
case tok::kw__Thread_local:
|
||||
case tok::kw_typeof:
|
||||
case tok::kw___underlying_type:
|
||||
case tok::kw___cdecl:
|
||||
case tok::kw___stdcall:
|
||||
case tok::kw___fastcall:
|
||||
case tok::kw___thiscall:
|
||||
case tok::kw___regcall:
|
||||
case tok::kw___vectorcall:
|
||||
case tok::kw___unaligned:
|
||||
case tok::kw___vector:
|
||||
case tok::kw___pixel:
|
||||
case tok::kw___bool:
|
||||
case tok::kw__Atomic:
|
||||
#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
|
||||
#include "clang/Basic/OpenCLImageTypes.def"
|
||||
case tok::kw___unknown_anytype:
|
||||
return TPResult::False;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TPResult::Ambiguous;
|
||||
}
|
||||
|
||||
bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
|
||||
return std::find(TentativelyDeclaredIdentifiers.begin(),
|
||||
TentativelyDeclaredIdentifiers.end(), II)
|
||||
|
|
|
@ -16525,6 +16525,14 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
|
|||
BitWidth = nullptr;
|
||||
ZeroWidth = false;
|
||||
}
|
||||
|
||||
// Only data members can have in-class initializers.
|
||||
if (BitWidth && !II && InitStyle) {
|
||||
Diag(Loc, diag::err_anon_bitfield_init);
|
||||
InvalidDecl = true;
|
||||
BitWidth = nullptr;
|
||||
ZeroWidth = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that 'mutable' is consistent with the type of the declaration.
|
||||
|
|
|
@ -135,6 +135,18 @@ namespace dr1512 { // dr1512: 4
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace dr1514 { // dr1514: 11
|
||||
#if __cplusplus >= 201103L
|
||||
struct S {
|
||||
enum E : int {}; // expected-note {{previous}}
|
||||
enum E : int {}; // expected-error {{redefinition}}
|
||||
};
|
||||
S::E se; // OK, complete type, not zero-width bitfield.
|
||||
|
||||
// The behavior in other contexts is superseded by DR1966.
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace dr1518 { // dr1518: 4
|
||||
#if __cplusplus >= 201103L
|
||||
struct Z0 { // expected-note 0+ {{candidate}}
|
||||
|
|
|
@ -167,6 +167,23 @@ namespace dr1959 { // dr1959: 3.9
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace dr1966 { // dr1966: 11
|
||||
#if __cplusplus >= 201103L
|
||||
struct A {
|
||||
enum E : int {1}; // expected-error {{expected identifier}} (not bit-field)
|
||||
};
|
||||
auto *p1 = new enum E : int; // expected-error {{only permitted as a standalone declaration}}
|
||||
auto *p2 = new enum F : int {}; // expected-error {{cannot be defined in a type specifier}}
|
||||
auto *p3 = true ? new enum G : int {}; // expected-error {{forward reference}} expected-error {{incomplete}} expected-note {{declaration}}
|
||||
auto h() -> enum E : int {}; // expected-error {{only permitted as a standalone declaration}}
|
||||
|
||||
enum X : enum Y : int {} {}; // expected-error {{cannot be defined in a type specifier}}
|
||||
struct Q {
|
||||
enum X : enum Y : int {} {}; // expected-error +{{}}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace dr1968 { // dr1968: no
|
||||
#if __cplusplus >= 201103L
|
||||
// FIXME: According to DR1968, both of these should be considered
|
||||
|
|
|
@ -42,6 +42,15 @@ namespace dr2140 { // dr2140: 9
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace dr2157 { // dr2157: 11
|
||||
#if __cplusplus >= 201103L
|
||||
enum E : int;
|
||||
struct X {
|
||||
enum dr2157::E : int(); // expected-error {{only allows ':' in member enumeration declaration to introduce a fixed underlying type}}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace dr2170 { // dr2170: 9
|
||||
#if __cplusplus >= 201103L
|
||||
void f() {
|
||||
|
|
|
@ -68,11 +68,12 @@ namespace PR10127 {
|
|||
|
||||
foo m = decltype(foo::bar)::baz;
|
||||
|
||||
enum E {
|
||||
};
|
||||
enum E {};
|
||||
enum H {};
|
||||
struct bar {
|
||||
enum E : decltype(outer())::td_int(4);
|
||||
enum E : decltype(outer())::td_int(4); // expected-error{{anonymous bit-field}}
|
||||
enum F : decltype(outer())::td_int;
|
||||
enum G : decltype; // expected-error{{expected '(' after 'decltype'}}
|
||||
enum H : 4; // expected-error {{anonymous bit-field}}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,3 +8,14 @@ void foo(void) {
|
|||
default: 0, // expected-note {{previous default generic association is here}}
|
||||
default: 0); // expected-error {{duplicate default generic association}}
|
||||
}
|
||||
|
||||
enum E { e };
|
||||
int bar(int n) {
|
||||
// PR45726
|
||||
return _Generic(0, enum E: n, default: 0);
|
||||
}
|
||||
|
||||
int baz(int n) {
|
||||
// PR39979
|
||||
return _Generic(0, enum { e }: n, default: 0);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace final {
|
|||
struct U final _Alignas(4) {}; // expected-error 3{{}} expected-note {{}}
|
||||
}
|
||||
|
||||
// enum versus bitfield mess.
|
||||
// enum versus bitfield. These are always required to be treated as an
|
||||
// enum-base, but we disambiguate anyway for better error recovery.
|
||||
namespace bitfield {
|
||||
enum E {};
|
||||
|
||||
|
@ -44,9 +45,9 @@ namespace bitfield {
|
|||
constexpr T a, b, c, d;
|
||||
|
||||
struct S1 {
|
||||
enum E : T ( a = 1, b = 2, c = 3, 4 ); // ok, declares a bitfield
|
||||
enum E : T ( a = 1, b = 2, c = 3, 4 ); // expected-error {{ISO C++ only allows ':' in member enumeration declaration to introduce a fixed underlying type, not an anonymous bit-field}}
|
||||
};
|
||||
// This could be a bit-field.
|
||||
// Enum definition, not a bit-field.
|
||||
struct S2 {
|
||||
enum E : T { a = 1, b = 2, c = 3, 4 }; // expected-error {{non-integral type}} expected-error {{expected identifier}}
|
||||
};
|
||||
|
|
|
@ -17,6 +17,49 @@ auto g() -> enum E {
|
|||
return E();
|
||||
}
|
||||
|
||||
namespace EnumBase {
|
||||
enum E {};
|
||||
// PR19810: The ': E' here is not an enum-base, and the ':' is not a typo for '::'.
|
||||
E e = true ? *new enum E : E {};
|
||||
// PR45726: This ':' is not an enum-base.
|
||||
static_assert(_Generic(e, enum E : int{}, int: 1) == 0); // expected-error {{C11 extension}}
|
||||
static_assert(_Generic(1, enum E : int{}, int: 1) == 1); // expected-error {{C11 extension}}
|
||||
}
|
||||
|
||||
namespace OpaqueEnumDecl {
|
||||
enum E : int; // ok
|
||||
|
||||
// PR44941
|
||||
enum E : int n; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration}}
|
||||
typedef enum E : int T; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration}}
|
||||
typedef enum E : int T; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration}}
|
||||
namespace Inner {
|
||||
typedef enum E : int T; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration}}
|
||||
}
|
||||
|
||||
// GCC incorrectly accepts this one
|
||||
using T = enum E : int; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration}}
|
||||
|
||||
// PR19810 comment#2
|
||||
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 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 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 Y *py; // expected-error {{ISO C++ forbids forward reference}}
|
||||
}
|
||||
}
|
||||
|
||||
int decltype(f())::*ptr_mem_decltype;
|
||||
|
||||
class ExtraSemiAfterMemFn {
|
||||
|
|
|
@ -6,15 +6,15 @@ struct Z {};
|
|||
typedef int Integer;
|
||||
|
||||
struct X {
|
||||
enum E : 1;
|
||||
enum E : 1; // expected-error{{anonymous bit-field}}
|
||||
enum E : Z; // expected-error{{invalid underlying type}}
|
||||
enum E2 : int;
|
||||
enum E3 : Integer;
|
||||
};
|
||||
|
||||
struct Y {
|
||||
enum E : int(2);
|
||||
enum E : Z(); // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'Z'}}
|
||||
enum E : int(2); // expected-error{{anonymous bit-field}}
|
||||
enum E : Z(); // expected-error{{anonymous bit-field}} expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'Z'}}
|
||||
};
|
||||
|
||||
namespace pr18587 {
|
||||
|
|
|
@ -102,6 +102,7 @@ enum : long {
|
|||
};
|
||||
|
||||
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() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -xc %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=expected,c -xc %s
|
||||
|
||||
#ifdef __OBJC__
|
||||
#if !__has_feature(objc_fixed_enum)
|
||||
|
@ -23,8 +23,8 @@ enum Color { Red, Green, Blue };
|
|||
struct X {
|
||||
enum Color : 4;
|
||||
enum Color field1: 4;
|
||||
enum Other : Integer field2;
|
||||
enum Other : Integer field3 : 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 : Integer { Blah, Blarg } field4 : 4;
|
||||
};
|
||||
|
||||
|
|
|
@ -8899,7 +8899,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg1514">1514</a></td>
|
||||
<td>C++14</td>
|
||||
<td>Ambiguity between enumeration definition and zero-length bit-field</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
</tr>
|
||||
<tr id="1515">
|
||||
<td><a href="https://wg21.link/cwg1515">1515</a></td>
|
||||
|
@ -11611,7 +11611,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg1966">1966</a></td>
|
||||
<td>CD4</td>
|
||||
<td>Colon following enumeration <I>elaborated-type-specifier</I></td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
</tr>
|
||||
<tr id="1967">
|
||||
<td><a href="https://wg21.link/cwg1967">1967</a></td>
|
||||
|
@ -12757,7 +12757,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg2157">2157</a></td>
|
||||
<td>CD4</td>
|
||||
<td>Further disambiguation of enumeration <I>elaborated-type-specifier</I></td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
</tr>
|
||||
<tr class="open" id="2158">
|
||||
<td><a href="https://wg21.link/cwg2158">2158</a></td>
|
||||
|
|
Loading…
Reference in New Issue