[clang] c90e198 - Fix parsing of enum-base to follow C++11 rules.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri May 8 19:32:13 PDT 2020


Author: Richard Smith
Date: 2020-05-08T19:32:00-07:00
New Revision: c90e198107431f64b73686bdce31c293e3380ac7

URL: https://github.com/llvm/llvm-project/commit/c90e198107431f64b73686bdce31c293e3380ac7
DIFF: https://github.com/llvm/llvm-project/commit/c90e198107431f64b73686bdce31c293e3380ac7.diff

LOG: 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.

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticParseKinds.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Parse/Parser.h
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/lib/Parse/ParseTentative.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/test/CXX/drs/dr15xx.cpp
    clang/test/CXX/drs/dr19xx.cpp
    clang/test/CXX/drs/dr21xx.cpp
    clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
    clang/test/Parser/c1x-generic-selection.c
    clang/test/Parser/cxx0x-ambig.cpp
    clang/test/Parser/cxx0x-decl.cpp
    clang/test/SemaCXX/enum-bitfield.cpp
    clang/test/SemaCXX/enum-scoped.cpp
    clang/test/SemaObjC/enum-fixed-type.m
    clang/www/cxx_dr_status.html

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 552c9187e705..04014780615b 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -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;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b3f6f66a8c56..5ca0982ce5c3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
 

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 4a8acf5cd196..cbdf9fede665 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2181,6 +2181,68 @@ class Parser : public CodeCompletionHandler {
     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 @@ class Parser : public CodeCompletionHandler {
     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,

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index f7d8619ad667..af5493d91deb 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -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;
 
-  // 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);
-
-        // Consume the ':'.
-        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);
+  // Parse the fixed underlying type.
+  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.
+
+    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();
+
+      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) {

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index f8c6379eee91..1a82475117ba 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -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)) ||

diff  --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 61a82664bf71..733d309d5ff2 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -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)

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 5d3314b4f244..3a377adb04f1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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.

diff  --git a/clang/test/CXX/drs/dr15xx.cpp b/clang/test/CXX/drs/dr15xx.cpp
index 55d838e45a57..478a0d7d00dd 100644
--- a/clang/test/CXX/drs/dr15xx.cpp
+++ b/clang/test/CXX/drs/dr15xx.cpp
@@ -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}}

diff  --git a/clang/test/CXX/drs/dr19xx.cpp b/clang/test/CXX/drs/dr19xx.cpp
index 4e359681fa8d..38d3ca589eca 100644
--- a/clang/test/CXX/drs/dr19xx.cpp
+++ b/clang/test/CXX/drs/dr19xx.cpp
@@ -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

diff  --git a/clang/test/CXX/drs/dr21xx.cpp b/clang/test/CXX/drs/dr21xx.cpp
index 7f76440de2e5..7e3ffa057ef7 100644
--- a/clang/test/CXX/drs/dr21xx.cpp
+++ b/clang/test/CXX/drs/dr21xx.cpp
@@ -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() {

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
index b5cd98828cc9..7ab504cbc9e5 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
@@ -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}}
   };
 }

diff  --git a/clang/test/Parser/c1x-generic-selection.c b/clang/test/Parser/c1x-generic-selection.c
index ee23059cc4de..f203a9a5d00a 100644
--- a/clang/test/Parser/c1x-generic-selection.c
+++ b/clang/test/Parser/c1x-generic-selection.c
@@ -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);
+}

diff  --git a/clang/test/Parser/cxx0x-ambig.cpp b/clang/test/Parser/cxx0x-ambig.cpp
index 71d32b8f51d9..60a5c32d319a 100644
--- a/clang/test/Parser/cxx0x-ambig.cpp
+++ b/clang/test/Parser/cxx0x-ambig.cpp
@@ -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}}
   };

diff  --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp
index 3c1c3602691b..de6dfae07941 100644
--- a/clang/test/Parser/cxx0x-decl.cpp
+++ b/clang/test/Parser/cxx0x-decl.cpp
@@ -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 {

diff  --git a/clang/test/SemaCXX/enum-bitfield.cpp b/clang/test/SemaCXX/enum-bitfield.cpp
index 676ae44b37fe..e78ca5dfa2fc 100644
--- a/clang/test/SemaCXX/enum-bitfield.cpp
+++ b/clang/test/SemaCXX/enum-bitfield.cpp
@@ -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 {

diff  --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index 1fcafb1dd0fd..34707b894488 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -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() {

diff  --git a/clang/test/SemaObjC/enum-fixed-type.m b/clang/test/SemaObjC/enum-fixed-type.m
index b4135a555a23..d991ac3e2d08 100644
--- a/clang/test/SemaObjC/enum-fixed-type.m
+++ b/clang/test/SemaObjC/enum-fixed-type.m
@@ -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 @@
 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;
 };
 

diff  --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 3f0102889c67..defdf677ae01 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -8899,7 +8899,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <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 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <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 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <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>


        


More information about the cfe-commits mailing list