Skip to content
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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 @@ -20813,10 +20813,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 {
Expand All @@ -20836,10 +20838,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.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);
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