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 <[email protected]> Date: Sun, 14 Dec 2025 15:30:56 +0200 Subject: [PATCH 1/2] [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@-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); >From cef3ccf9a1b5e3aeca65388607655a764e1cba22 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <[email protected]> Date: Tue, 16 Dec 2025 17:44:28 +0200 Subject: [PATCH 2/2] 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@-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, ""); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
