Skip to content

[clang][C23] Claim N3030 Enhancements to Enumerations supported #107260

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 18, 2024

Conversation

Fznamznon
Copy link
Contributor

Clang already implemented functionality as an extension.

Clang already implemented functionality as an extension.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 4, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2024

@llvm/pr-subscribers-clang

Author: Mariya Podchishchaeva (Fznamznon)

Changes

Clang already implemented functionality as an extension.


Full diff: https://github.com/llvm/llvm-project/pull/107260.diff

5 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+6-3)
  • (modified) clang/lib/Parse/ParseDecl.cpp (+5-3)
  • (added) clang/test/C/C23/n3030.c (+95)
  • (modified) clang/test/Sema/fixed-enum.c (+17-8)
  • (modified) clang/www/c_status.html (+1-1)
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 0b8ab4bf092509..a1070aceea7572 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -113,9 +113,12 @@ def ext_cxx11_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 ext_c23_enum_fixed_underlying_type : Extension<
+  "enumeration types with a fixed underlying type are a C23 extension">,
+  InGroup<C23>;
+def warn_c17_compat_enum_fixed_underlying_type : Warning<
+  "enumeration types with a fixed underlying type are incompatible with C standards before C23">,
+  DefaultIgnore, InGroup<CPre23Compat>;
 def warn_cxx98_compat_enum_fixed_underlying_type : Warning<
   "enumeration types with a fixed underlying type are incompatible with C++98">,
   InGroup<CXX98Compat>, DefaultIgnore;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 78d729c5ef7d8a..b563f875c663c6 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -5413,18 +5413,20 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
 
       BaseRange = SourceRange(ColonLoc, DeclaratorInfo.getSourceRange().getEnd());
 
-      if (!getLangOpts().ObjC && !getLangOpts().C23) {
+      if (!getLangOpts().ObjC) {
         if (getLangOpts().CPlusPlus11)
           Diag(ColonLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type)
               << BaseRange;
         else if (getLangOpts().CPlusPlus)
           Diag(ColonLoc, diag::ext_cxx11_enum_fixed_underlying_type)
               << BaseRange;
-        else if (getLangOpts().MicrosoftExt)
+        else if (getLangOpts().MicrosoftExt && !getLangOpts().C23)
           Diag(ColonLoc, diag::ext_ms_c_enum_fixed_underlying_type)
               << BaseRange;
         else
-          Diag(ColonLoc, diag::ext_clang_c_enum_fixed_underlying_type)
+          Diag(ColonLoc, (getLangOpts().C23)
+                             ? diag::warn_c17_compat_enum_fixed_underlying_type
+                             : diag::ext_c23_enum_fixed_underlying_type)
               << BaseRange;
       }
     }
diff --git a/clang/test/C/C23/n3030.c b/clang/test/C/C23/n3030.c
new file mode 100644
index 00000000000000..82e50484fd7ebc
--- /dev/null
+++ b/clang/test/C/C23/n3030.c
@@ -0,0 +1,95 @@
+// RUN: %clang_cc1 -verify -triple x86_64-unknown-linux-gnu -fsyntax-only --embed-dir=%S/Inputs -std=c23 %s -pedantic -Wall
+
+#include <limits.h>
+
+enum us : unsigned short {
+  us_max = USHRT_MAX,
+  us_violation,  // expected-error {{enumerator value 65536 is not representable in the underlying type 'unsigned short'}}
+                 // expected-warning@-1 {{overflow}}
+  us_violation_2 = us_max + 1, // expected-error {{enumerator value is not representable in the underlying type 'unsigned short'}}
+  us_wrap_around_to_zero = (unsigned short)(USHRT_MAX + 1) /* Okay: conversion
+                            done in constant expression before conversion to
+                            underlying type: unsigned semantics okay. */
+};
+
+enum ui : unsigned int {
+  ui_max = UINT_MAX,
+  ui_violation,  // expected-error {{enumerator value 4294967296 is not representable in the underlying type 'unsigned int'}}
+                 // expected-warning@-1 {{overflow}}
+  ui_no_violation = ui_max + 1,
+  ui_wrap_around_to_zero = (unsigned int)(UINT_MAX + 1)
+};
+
+enum E1 : short;
+enum E2 : short; // expected-note {{previous}}
+enum E3; // expected-warning {{ISO C forbids forward references to 'enum' types}}
+enum E4 : unsigned long long;
+
+enum E1 : short { m11, m12 };
+enum E1 x = m11;
+
+enum E2 : long { // expected-error {{enumeration redeclared with different underlying type 'long' (was 'short')}}
+  m21,
+  m22
+};
+
+enum E3 { // expected-note {{definition of 'enum E3' is not complete until the closing '}'}}
+          // expected-note@-1 {{previous}}
+  m31,
+  m32,
+  m33 = sizeof(enum E3) // expected-error {{invalid application of 'sizeof' to an incomplete type 'enum E3'}}
+};
+enum E3 : int; // expected-error {{enumeration previously declared with nonfixed underlying type}}
+
+enum E4 : unsigned long long {
+  m40 = sizeof(enum E4),
+  m41 = ULLONG_MAX,
+  m42 // expected-error {{enumerator value 18446744073709551616 is not representable in the underlying type 'unsigned long long'}}
+};
+
+enum E5 y; // expected-error {{tentative definition has type 'enum E5' that is never completed}}
+           // expected-warning@-1 {{ISO C forbids forward references to 'enum' types}}
+           // expected-note@-2 {{forward declaration of 'enum E5'}}
+enum E6 : long int z;   // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}
+enum E7 : long int = 0;  // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}
+                         // expected-error@-1 {{expected identifier or '('}}
+
+enum underlying : unsigned char { b0 };
+
+constexpr int a = _Generic(b0, int: 2, unsigned char: 1, default: 0);
+constexpr int b = _Generic((enum underlying)b0, int: 2, unsigned char: 1, default: 0);
+static_assert(a == 1);
+static_assert(b == 1);
+
+void f1(enum a : long b); // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}
+                          // expected-warning@-1 {{declaration of 'enum a' will not be visible outside of this function}}
+void f2(enum c : long{x} d); // expected-warning {{declaration of 'enum c' will not be visible outside of this function}}
+enum e : int f3(); // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}
+
+typedef enum t u; // expected-warning {{ISO C forbids forward references to 'enum' types}}
+typedef enum v : short W; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}
+typedef enum q : short { s } R;
+
+struct s1 {
+  int x;
+  enum e:int : 1; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}
+  int y;
+};
+
+enum forward; // expected-warning {{ISO C forbids forward references to 'enum' types}}
+extern enum forward fwd_val0;  /* Constraint violation: incomplete type */
+extern enum forward *fwd_ptr0; // expected-note {{previous}}
+extern int
+    *fwd_ptr0; // expected-error {{redeclaration of 'fwd_ptr0' with a different type: 'int *' vs 'enum forward *'}}
+
+enum forward1 : int;
+extern enum forward1 fwd_val1;
+extern int fwd_val1;
+extern enum forward1 *fwd_ptr1;
+extern int *fwd_ptr1;
+
+enum ee1 : short;
+enum e : short f = 0; // expected-error {{non-defining declaration of enumeration with a fixed underlying type is only permitted as a standalone declaration; missing list of enumerators?}}
+enum g : short { yyy } h = yyy;
+
+enum ee2 : typeof ((enum ee3 : short { A })0, (short)0);
diff --git a/clang/test/Sema/fixed-enum.c b/clang/test/Sema/fixed-enum.c
index 954ff8c452b80c..2b02def0e1788d 100644
--- a/clang/test/Sema/fixed-enum.c
+++ b/clang/test/Sema/fixed-enum.c
@@ -5,9 +5,9 @@
 // RUN: %clang_cc1 -pedantic    -std=c11 -xc -DC11 -verify %s
 // RUN: %clang_cc1 -Weverything -std=c11 -xc -fms-extensions -DMS -verify %s
 // RUN: %clang_cc1 -Weverything -std=c2x -xc -DC23 -verify %s
-// RUN: %clang_cc1 -pedantic    -std=c2x -xc -DC23 -verify %s
+// RUN: %clang_cc1 -pedantic    -std=c2x -xc -DC23 -verify -Wpre-c23-compat %s
 // RUN: %clang_cc1 -Weverything -std=c23 -xc -DC23 -verify %s
-// RUN: %clang_cc1 -pedantic    -std=c23 -xc -DC23 -verify %s
+// RUN: %clang_cc1 -pedantic    -std=c23 -xc -DC23 -verify -Wpre-c23-compat %s
 // RUN: %clang_cc1 -Weverything -std=c23 -xc -fms-extensions -DC23 -verify %s
 
 enum X : int {e};
@@ -15,12 +15,14 @@ enum X : int {e};
 // 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) || defined(C23)
-// No diagnostic
+#elif defined(OBJC)
+// diagnostic
+#elif defined(C23)
+// expected-warning@-8{{enumeration types with a fixed underlying type are incompatible with C standards before C23}}
 #elif defined(C11)
-// expected-warning@-8{{enumeration types with a fixed underlying type are a Clang extension}}
+// expected-warning@-10{{enumeration types with a fixed underlying type are a C23 extension}}
 #elif defined(MS)
-// expected-warning@-10{{enumeration types with a fixed underlying type are a Microsoft extension}}
+// expected-warning@-12{{enumeration types with a fixed underlying type are a Microsoft extension}}
 #endif
 
 // Don't warn about the forward declaration in any language mode.
@@ -29,16 +31,23 @@ enum Fwd : int { e2 };
 #if !defined(OBJC) && !defined(C23)
 // expected-warning@-3 {{enumeration types with a fixed underlying type}}
 // expected-warning@-3 {{enumeration types with a fixed underlying type}}
+#elif defined(C23)
+// expected-warning@-6 {{enumeration types with a fixed underlying type are incompatible with C standards before C23}}
+// expected-warning@-6 {{enumeration types with a fixed underlying type are incompatible with C standards before C23}}
 #endif
 
 // Always error on the incompatible redeclaration.
 enum BadFwd : int;
 #if !defined(OBJC) && !defined(C23)
 // expected-warning@-2 {{enumeration types with a fixed underlying type}}
+#elif defined(C23)
+// expected-warning@-4 {{enumeration types with a fixed underlying type are incompatible with C standards before C23}}
 #endif
-// expected-note@-4 {{previous declaration is here}}
+// expected-note@-6 {{previous declaration is here}}
 enum BadFwd : char { e3 };
 #if !defined(OBJC) && !defined(C23)
 // expected-warning@-2 {{enumeration types with a fixed underlying type}}
+#elif defined(C23)
+// expected-warning@-4 {{enumeration types with a fixed underlying type are incompatible with C standards before C23}}
 #endif
-// expected-error@-4 {{enumeration redeclared with different underlying type 'char' (was 'int')}}
+// expected-error@-6 {{enumeration redeclared with different underlying type 'char' (was 'int')}}
diff --git a/clang/www/c_status.html b/clang/www/c_status.html
index 255690cd6d34e2..47124bd91f846f 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -697,7 +697,7 @@ <h2 id="c2x">C23 implementation status</h2>
     <tr>
       <td>Enhanced enumerations</td>
       <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3030.htm">N3030</a></td>
-      <td class="unknown" align="center">Unknown</td>
+      <td class="unreleased" align="center">Clang 20</td>
     </tr>
     <tr>
       <td>Freestanding C and IEC 60559 conformance scope reduction</td>

Comment on lines +79 to +80
enum forward; // expected-warning {{ISO C forbids forward references to 'enum' types}}
extern enum forward fwd_val0; /* Constraint violation: incomplete type */
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is taken directly from the paper. gcc gives the same set of diagnostics here. The paper says there should be errors, however the area is covered with lots of extensions, so I'm not sure if I'm missing some historical context here.
Please let me know what you think.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM, just some minor nits.

};

enum forward; // expected-warning {{ISO C forbids forward references to 'enum' types}}
extern enum forward fwd_val0; /* Constraint violation: incomplete type */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should get the same pedantic diagnostic as the line above, I believe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AaronBallman , after looking into this, I noticed that we emit this pedantic warning only for a first met declaration. So if I do

extern enum forward fwd_val0; 
extern enum forward *fwd_ptr0;

The warning appears. Demo https://godbolt.org/z/saPEcPKs8

We don't enter the code emitting the diagnostic if there was a previous declaration.
It is emitted here:

Diag(Loc, DiagID);

I wonder if that is still a problem and we need to change anything?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, that's interesting! I think we may do that to reduce chattiness given how often C code uses elaborated type specifiers: https://godbolt.org/z/v1ob54G5o -- but git blame on GitHub is utterly useless and I'm struggling to see why we ended up doing what we did.

I think for now we can leave it as-is; we still handle strict conformance properly because we only need to emit one diagnostic for the entire TU. We can revisit later if we think that's worth it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG!

@Fznamznon Fznamznon merged commit a9d9b0a into llvm:main Sep 18, 2024
8 checks passed
tmsri pushed a commit to tmsri/llvm-project that referenced this pull request Sep 19, 2024
…#107260)

Clang already implemented functionality as an extension.
Groverkss pushed a commit to iree-org/llvm-project that referenced this pull request Nov 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants