Skip to content

[Clang] treat fixed-underlying enum constants as the enumerated type in C23 to follow the spec#172211

Merged
a-tarasyuk merged 17 commits intollvm:mainfrom
a-tarasyuk:fix/172118
Jan 6, 2026
Merged

[Clang] treat fixed-underlying enum constants as the enumerated type in C23 to follow the spec#172211
a-tarasyuk merged 17 commits intollvm:mainfrom
a-tarasyuk:fix/172118

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.

@github-actions
Copy link

github-actions bot commented Dec 16, 2025

🪟 Windows x64 Test Results

  • 53348 tests passed
  • 2212 tests skipped

✅ The build succeeded and all tests passed.

@a-tarasyuk
Copy link
Member Author

@Fznamznon, thank you for your feedback. I have added more tests based on the issue you pointed out.

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.

LGTM

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.

LGTM!

@a-tarasyuk a-tarasyuk merged commit 08215e5 into llvm:main Jan 6, 2026
11 checks passed
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

4 participants