Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
9d82454
[Clang] treat fixed-underlying enum constants as the enumerated type …
a-tarasyuk Dec 14, 2025
cef3ccf
add tests to cover c23 underlying enum member types
a-tarasyuk Dec 16, 2025
bf444ff
Merge branch 'main' of https://github.com/llvm/llvm-project into fix/…
a-tarasyuk Dec 16, 2025
594ccfe
Merge branch 'main' into fix/172118
a-tarasyuk Dec 16, 2025
89159d8
Merge branch 'main' into fix/172118
a-tarasyuk Dec 16, 2025
709e669
update tests
a-tarasyuk Dec 16, 2025
42e297b
Merge branch 'fix/172118' of https://github.com/a-tarasyuk/llvm-proje…
a-tarasyuk Dec 16, 2025
b3dad82
Merge branch 'main' of https://github.com/llvm/llvm-project into fix/…
a-tarasyuk Dec 16, 2025
2209e17
Merge branch 'main' into fix/172118
a-tarasyuk Dec 17, 2025
4b85604
Merge branch 'main' into fix/172118
a-tarasyuk Dec 24, 2025
8b93e79
Merge branch 'main' into fix/172118
a-tarasyuk Dec 28, 2025
43801fc
Merge branch 'main' into fix/172118
a-tarasyuk Jan 5, 2026
073a22c
Merge branch 'main' into fix/172118
a-tarasyuk Jan 6, 2026
6ef734a
Merge branch 'main' into fix/172118
a-tarasyuk Jan 6, 2026
ea07531
update comments to reference the appropriate specification item
a-tarasyuk Jan 6, 2026
06bfd27
Merge branch 'fix/172118' of https://github.com/a-tarasyuk/llvm-proje…
a-tarasyuk Jan 6, 2026
f89402b
Merge branch 'main' of https://github.com/llvm/llvm-project into fix/…
a-tarasyuk Jan 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ Bug Fixes in This Version
containing a single colon. (#GH167905)
- Fixed a crash when parsing malformed #pragma clang loop vectorize_width(4,8,16)
by diagnosing invalid comma-separated argument lists. (#GH166325)
- Clang now treats enumeration constants of fixed-underlying enums as the enumerated type. (#GH172118)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
9 changes: 7 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20822,10 +20822,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.3.3p16: The enumeration member type for an enumerated type
// with fixed underlying type is the enumerated type.
ECD->setType(EnumType);
continue;
} else {
Expand All @@ -20845,10 +20847,13 @@ 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() || !MembersRepresentableByInt)))
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
// enumeration.
// C23 6.7.3.3p16: The enumeration member type for an enumerated type
// with fixed underlying type is the enumerated type.
ECD->setType(EnumType);
else
ECD->setType(NewTy);
Expand Down
3 changes: 2 additions & 1 deletion clang/test/C/C23/n3029.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
59 changes: 59 additions & 0 deletions clang/test/Sema/c23-fixed-underlying-enum.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// RUN: %clang_cc1 -triple x86_64-linux -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, "");
}
20 changes: 20 additions & 0 deletions clang/test/Sema/c23-switch.c
Original file line number Diff line number Diff line change
@@ -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}}
}
6 changes: 3 additions & 3 deletions clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand All @@ -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);
Expand Down