Skip to content

Conversation

@a-tarasyuk
Copy link
Member

Fixes #172118


This patch resolves an issue where C23 fixed-underlying enum constants were incorrectly treated as the underlying integer type instead of the enumeration type.

According to C23 6.7.2.2p15:

The enumeration member type of an enumerated type with a fixed underlying type is the same as the type itself.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Dec 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 14, 2025

@llvm/pr-subscribers-clang

Author: Oleksandr T. (a-tarasyuk)

Changes

Fixes #172118


This patch resolves an issue where C23 fixed-underlying enum constants were incorrectly treated as the underlying integer type instead of the enumeration type.

According to C23 6.7.2.2p15:

> The enumeration member type of an enumerated type with a fixed underlying type is the same as the type itself.


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

4 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+6-2)
  • (added) clang/test/Sema/c23-switch.c (+20)
  • (modified) clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp (+3-3)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index feaf92ad4415f..66ec693e69826 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -534,6 +534,7 @@ Bug Fixes in This Version
 - Fixed false-positive shadow diagnostics for lambdas in explicit object member functions. (#GH163731)
 - Fix an assertion failure when a ``target_clones`` attribute is only on the
   forward declaration of a multiversioned function. (#GH165517) (#GH129483)
+- Clang now treats enumeration constants of fixed-underlying enums as the enumerated type. (#GH172118)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index db711ee08c8da..7dbce349d48af 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20814,10 +20814,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
       NewSign = true;
     } else if (ECD->getType() == BestType) {
       // Already the right type!
-      if (getLangOpts().CPlusPlus)
+      if (getLangOpts().CPlusPlus || (getLangOpts().C23 && Enum->isFixed()))
         // C++ [dcl.enum]p4: Following the closing brace of an
         // enum-specifier, each enumerator has the type of its
         // enumeration.
+        // C23 6.7.2.2p15: For an enumerated type with fixed underlying type,
+        // the enumeration member type is the enumerated type.
         ECD->setType(EnumType);
       continue;
     } else {
@@ -20837,10 +20839,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
       ECD->setInitExpr(ImplicitCastExpr::Create(
           Context, NewTy, CK_IntegralCast, ECD->getInitExpr(),
           /*base paths*/ nullptr, VK_PRValue, FPOptionsOverride()));
-    if (getLangOpts().CPlusPlus)
+    if (getLangOpts().CPlusPlus || (getLangOpts().C23 && Enum->isFixed()))
       // C++ [dcl.enum]p4: Following the closing brace of an
       // enum-specifier, each enumerator has the type of its
       // enumeration.
+      // C23 6.7.2.2p15: For an enumerated type with fixed underlying type, the
+      // enumeration member type is the enumerated type.
       ECD->setType(EnumType);
     else
       ECD->setType(NewTy);
diff --git a/clang/test/Sema/c23-switch.c b/clang/test/Sema/c23-switch.c
new file mode 100644
index 0000000000000..32be0bb8e6a48
--- /dev/null
+++ b/clang/test/Sema/c23-switch.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify -Wswitch %s
+
+typedef enum : long { E0 } E;
+void test1(E e) {
+  auto v = E0;
+  switch (v) { } // expected-warning {{enumeration value 'E0' not handled in switch}}
+}
+
+void test2(E e) {
+  __auto_type v = E0;
+  switch (v) { } // expected-warning {{enumeration value 'E0' not handled in switch}}
+}
+
+void test3(_Bool b, E e) {
+  __auto_type v = E0;
+  if (b) {
+    v = e;
+  }
+  switch (v) { } // expected-warning {{enumeration value 'E0' not handled in switch}}
+}
diff --git a/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp b/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
index 5eaa3eb2d85e3..71367cfc7ec4d 100644
--- a/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
+++ b/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
@@ -377,9 +377,9 @@ void write_high_constantA(S_A *s) {
 void write_high_constantB(S_B *s) {
   s->field1 = ENUM_CLASS_REF(B, B_d);
   // cpp-warning@-1 {{implicit truncation from 'B' to bit-field changes value from 3 to 1}}
-  // c-warning@-2 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+  // c-warning@-2 {{implicit truncation from 'enum B' to bit-field changes value from 3 to -1}}
   s->field2 = ENUM_CLASS_REF(B, B_d);
-  // c-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+  // c-warning@-1 {{implicit truncation from 'enum B' to bit-field changes value from 3 to -1}}
   s->field3 = ENUM_CLASS_REF(B, B_d);
   s->field4 = (unsigned)ENUM_CLASS_REF(B, B_d);
   // expected-warning@-1 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
@@ -396,7 +396,7 @@ void write_high_constantB(S_B *s) {
 void write_high_constantC(S_C *s) {
   s->field1 = ENUM_CLASS_REF(C, C_d);
   // cpp-warning@-1 {{implicit truncation from 'C' to bit-field changes value from 3 to 1}}
-  // c-warning@-2 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
+  // c-warning@-2 {{implicit truncation from 'enum C' to bit-field changes value from 3 to 1}}
   s->field2 = ENUM_CLASS_REF(C, C_d);
   s->field3 = ENUM_CLASS_REF(C, C_d);
   s->field4 = (unsigned)ENUM_CLASS_REF(C, C_d);

Copy link
Contributor

@Fznamznon Fznamznon left a comment

Choose a reason for hiding this comment

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

Hi, thanks for the patch, does that also fix #147370 ? I think we could reuse some test cases from there as well.

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.

[C23] Type of enumeration constants having enumerated type wrong in C

3 participants