erik.pilkington created this revision.
erik.pilkington added reviewers: rsmith, rjmccall.
Herald added a subscriber: dexonsmith.

A significant number of internal C users have been complaining about the lack 
of support for fixed enums. We already support this in Objective-C mode, as 
well as in C mode with -fms-extensions. Supporting this in C makes us more 
consistent, and provides a useful feature to C users!

If there is some doubt as to whether we want this, I can start a thread on 
cfe-dev for the wider audience.

rdar://43831380

Thanks for taking a look!


Repository:
  rC Clang

https://reviews.llvm.org/D52339

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Basic/Features.def
  clang/lib/Parse/ParseDecl.cpp
  clang/test/Sema/fixed-enum.c
  clang/test/SemaObjC/enum-fixed-type.m

Index: clang/test/SemaObjC/enum-fixed-type.m
===================================================================
--- clang/test/SemaObjC/enum-fixed-type.m
+++ clang/test/SemaObjC/enum-fixed-type.m
@@ -1,9 +1,14 @@
 // RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -xc %s
 
 #if !__has_feature(objc_fixed_enum)
 #  error Enumerations with a fixed underlying type are not supported
 #endif
 
+#if !__has_extension(cxx_fixed_enum)
+#  error Enumerations with a fixed underlying type are not supported
+#endif
+
 typedef long Integer;
 
 typedef enum : Integer { Enumerator1, Enumerator2 } Enumeration;
Index: clang/test/Sema/fixed-enum.c
===================================================================
--- /dev/null
+++ clang/test/Sema/fixed-enum.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -Weverything -xc++ -std=c++11 -DCXX11 -verify %s
+// RUN: %clang_cc1 -Weverything -xc++ -std=c++03 -DCXX03 -verify %s
+// RUN: %clang_cc1 -Weverything -xobjective-c -DOBJC -verify %s
+// RUN: %clang_cc1 -Weverything -std=c11 -xc -DC11 -verify %s
+// RUN: %clang_cc1 -Weverything -std=c11 -xc -fms-extensions -DMS -verify %s
+
+enum X : int {e};
+#if defined(CXX11)
+// expected-warning@-2{{enumeration types with a fixed underlying type are incompatible with C++98}}
+#elif defined(CXX03)
+// expected-warning@-4{{enumeration types with a fixed underlying type are a C++11 extension}}
+#elif defined(OBJC)
+// expected-no-diagnostics
+#elif defined(C11)
+// expected-warning@-8{{enumeration types with a fixed underlying type are a Clang extension}}
+#elif defined(MS)
+// expected-warning@-10{{enumeration types with a fixed underlying type are a Microsoft extension}}
+#endif
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -4153,15 +4153,11 @@
   // Enum definitions should not be parsed in a trailing-return-type.
   bool AllowDeclaration = DSC != DeclSpecContext::DSC_trailing;
 
-  bool AllowFixedUnderlyingType = AllowDeclaration &&
-    (getLangOpts().CPlusPlus11 || getLangOpts().MicrosoftExt ||
-     getLangOpts().ObjC2);
-
   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, AllowFixedUnderlyingType);
+    ColonProtectionRAIIObject X(*this, AllowDeclaration);
 
     CXXScopeSpec Spec;
     if (ParseOptionalCXXScopeSpecifier(Spec, nullptr,
@@ -4183,7 +4179,7 @@
 
   // Must have either 'enum name' or 'enum {...}'.
   if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
-      !(AllowFixedUnderlyingType && Tok.is(tok::colon))) {
+      !(AllowDeclaration && Tok.is(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.
@@ -4216,7 +4212,7 @@
 
   // Parse the fixed underlying type.
   bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope;
-  if (AllowFixedUnderlyingType && Tok.is(tok::colon)) {
+  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
@@ -4276,13 +4272,15 @@
       SourceRange Range;
       BaseType = ParseTypeName(&Range);
 
-      if (getLangOpts().CPlusPlus11) {
-        Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
-      } else if (!getLangOpts().ObjC2) {
-        if (getLangOpts().CPlusPlus)
-          Diag(StartLoc, diag::ext_cxx11_enum_fixed_underlying_type) << Range;
+      if (!getLangOpts().ObjC2) {
+        if (getLangOpts().CPlusPlus11)
+          Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
+        else if (getLangOpts().CPlusPlus)
+          Diag(StartLoc, diag::ext_cxx11_enum_fixed_underlying_type);
+        else if (getLangOpts().MicrosoftExt)
+          Diag(StartLoc, diag::ext_ms_c_enum_fixed_underlying_type);
         else
-          Diag(StartLoc, diag::ext_c_enum_fixed_underlying_type) << Range;
+          Diag(StartLoc, diag::ext_clang_c_enum_fixed_underlying_type);
       }
     }
   }
Index: clang/include/clang/Basic/Features.def
===================================================================
--- clang/include/clang/Basic/Features.def
+++ clang/include/clang/Basic/Features.def
@@ -87,7 +87,7 @@
 FEATURE(objc_arc_fields, true)
 FEATURE(objc_arc_weak, LangOpts.ObjCWeak)
 FEATURE(objc_default_synthesize_properties, LangOpts.ObjC2)
-FEATURE(objc_fixed_enum, LangOpts.ObjC2)
+FEATURE(objc_fixed_enum, true)
 FEATURE(objc_instancetype, LangOpts.ObjC2)
 FEATURE(objc_kindof, LangOpts.ObjC2)
 FEATURE(objc_modules, LangOpts.ObjC2 &&LangOpts.Modules)
@@ -230,6 +230,7 @@
 EXTENSION(cxx_reference_qualified_functions, LangOpts.CPlusPlus)
 EXTENSION(cxx_rvalue_references, LangOpts.CPlusPlus)
 EXTENSION(cxx_variadic_templates, LangOpts.CPlusPlus)
+EXTENSION(cxx_fixed_enum, true)
 // C++14 features supported by other languages as extensions.
 EXTENSION(cxx_binary_literals, true)
 EXTENSION(cxx_init_captures, LangOpts.CPlusPlus11)
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -88,9 +88,12 @@
 def ext_cxx11_enum_fixed_underlying_type : Extension<
   "enumeration types with a fixed underlying type are a C++11 extension">,
   InGroup<CXX11>;
-def ext_c_enum_fixed_underlying_type : Extension<
+def ext_ms_c_enum_fixed_underlying_type : Extension<
   "enumeration types with a fixed underlying type are a Microsoft extension">,
   InGroup<MicrosoftFixedEnum>;
+def ext_clang_c_enum_fixed_underlying_type : Extension<
+  "enumeration types with a fixed underlying type are a Clang extension">,
+  InGroup<DiagGroup<"fixed-enum-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;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to