[clang] [Clang] treat fixed-underlying enum constants as the enumerated type in C23 to follow the spec (PR #172211)
Oleksandr T. via cfe-commits
cfe-commits at lists.llvm.org
Sun Dec 28 09:22:47 PST 2025
https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/172211
>From 9d82454fd919d5686d9da7c9cfdee954c4073b5c Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Sun, 14 Dec 2025 15:30:56 +0200
Subject: [PATCH 1/3] [Clang] treat fixed-underlying enum constants as the
enumerated type in C23 to follow the spec
---
clang/docs/ReleaseNotes.rst | 1 +
clang/lib/Sema/SemaDecl.cpp | 8 ++++++--
clang/test/Sema/c23-switch.c | 20 +++++++++++++++++++
.../bitfield-preferred-type-sizing.cpp | 6 +++---
4 files changed, 30 insertions(+), 5 deletions(-)
create mode 100644 clang/test/Sema/c23-switch.c
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 at -1 {{implicit truncation from 'B' to bit-field changes value from 3 to 1}}
- // c-warning at -2 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+ // c-warning at -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 at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+ // c-warning at -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 at -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 at -1 {{implicit truncation from 'C' to bit-field changes value from 3 to 1}}
- // c-warning at -2 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
+ // c-warning at -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);
>From cef3ccf9a1b5e3aeca65388607655a764e1cba22 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Tue, 16 Dec 2025 17:44:28 +0200
Subject: [PATCH 2/3] add tests to cover c23 underlying enum member types
---
clang/lib/Sema/SemaDecl.cpp | 3 +-
clang/test/C/C23/n3029.c | 3 +-
clang/test/Sema/c23-fixed-underlying-enum.c | 59 +++++++++++++++++++++
3 files changed, 63 insertions(+), 2 deletions(-)
create mode 100644 clang/test/Sema/c23-fixed-underlying-enum.c
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7dbce349d48af..529b7179ad9d3 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20839,7 +20839,8 @@ 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 || (getLangOpts().C23 && Enum->isFixed()))
+ if (getLangOpts().CPlusPlus ||
+ (getLangOpts().C23 && (Enum->isFixed() || !MembersRepresentableByInt)))
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
// enumeration.
diff --git a/clang/test/C/C23/n3029.c b/clang/test/C/C23/n3029.c
index 26d6dfdcc6046..ef8dd77fd4fc5 100644
--- a/clang/test/C/C23/n3029.c
+++ b/clang/test/C/C23/n3029.c
@@ -42,7 +42,8 @@ _Bool e (void) {
}
int f (void) {
- return a0; // all-warning {{implicit conversion from 'unsigned long' to 'int' changes value from 18446744073709551615 to -1}}
+ return a0; // expected-warning {{implicit conversion from 'enum a' to 'int' changes value from 18446744073709551615 to -1}}
+ // pedantic-warning at -1 {{implicit conversion from 'unsigned long' to 'int' changes value from 18446744073709551615 to -1}}
}
unsigned long g (void) {
diff --git a/clang/test/Sema/c23-fixed-underlying-enum.c b/clang/test/Sema/c23-fixed-underlying-enum.c
new file mode 100644
index 0000000000000..4a625ee2a1484
--- /dev/null
+++ b/clang/test/Sema/c23-fixed-underlying-enum.c
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+#define INT64_MIN (-9223372036854775807LL - 1)
+
+void t1() {
+ {
+ enum { A };
+ enum { B };
+
+ _Static_assert(_Generic(A, typeof(B): 1, default: 0) == 1, "");
+ _Static_assert(_Generic(typeof(A), typeof(B): 1, default: 0) == 1, "");
+ }
+
+ {
+ _Static_assert(
+ _Generic(typeof(enum {A}), typeof(enum {B}): 1, default: 0) == 0, "");
+ }
+}
+
+void t2() {
+ {
+ enum : int { A };
+ enum : int { B };
+
+ _Static_assert(_Generic(A, typeof(B): 1, default: 0) == 0, "");
+ _Static_assert(_Generic(typeof(A), typeof(B): 1, default: 0) == 0, "");
+ }
+
+ {
+ _Static_assert(
+ _Generic(typeof(enum : int{A}), typeof(enum : int{B}): 1, default: 0) == 0, "");
+ }
+}
+
+void t3() {
+ {
+ enum { A = INT64_MIN };
+ enum { B = INT64_MIN };
+
+ _Static_assert(_Generic(A, __typeof__(B): 1, default: 0) == 0, "");
+ _Static_assert(_Generic(__typeof__(A), __typeof__(B): 1, default: 0) == 0, "");
+ }
+
+ {
+ enum : long long { A = INT64_MIN };
+ enum : long long { B = INT64_MIN };
+
+ _Static_assert(_Generic(A, __typeof__(B): 1, default: 0) == 0, "");
+ _Static_assert(_Generic(__typeof__(A), __typeof__(B): 1, default: 0) == 0, "");
+ }
+}
+
+void t4() {
+ enum : int { A };
+ enum : int { B };
+
+ _Static_assert(_Generic(A, typeof(B): 1, typeof(A): 2, default: 0) == 2, "");
+}
>From 709e669437f73dcb783aed4b55905f834cf89c15 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Tue, 16 Dec 2025 20:23:30 +0200
Subject: [PATCH 3/3] update tests
---
clang/test/Sema/c23-fixed-underlying-enum.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Sema/c23-fixed-underlying-enum.c b/clang/test/Sema/c23-fixed-underlying-enum.c
index 4a625ee2a1484..1e0d7b4a70985 100644
--- a/clang/test/Sema/c23-fixed-underlying-enum.c
+++ b/clang/test/Sema/c23-fixed-underlying-enum.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux -std=c23 -fsyntax-only -verify %s
// expected-no-diagnostics
#define INT64_MIN (-9223372036854775807LL - 1)
More information about the cfe-commits
mailing list