diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 762e8133f5d536..b60ca81b046095 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -201,6 +201,14 @@ Improvements to Clang's diagnostics - Added diagnostics for C11 keywords being incompatible with language standards before C11, under a new warning group: ``-Wpre-c11-compat``. +- Now diagnoses an enumeration constant whose value is larger than can be + represented by ``unsigned long long``, which can happen with a large constant + using the ``wb`` or ``uwb`` suffix. The maximal underlying type is currently + ``unsigned long long``, but this behavior may change in the future when Clang + implements + `WG14 N3029 `_. + Fixes `#69352 `_. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0aaaba0e5d15f9..558109dc089150 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -20317,8 +20317,13 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, ? Context.UnsignedLongTy : Context.LongTy; } else { BestWidth = Context.getTargetInfo().getLongLongWidth(); - assert(NumPositiveBits <= BestWidth && - "How could an initializer get larger than ULL?"); + if (NumPositiveBits > BestWidth) { + // This can happen with bit-precise integer types, but those are not + // allowed as the type for an enumerator per C23 6.7.2.2p4 and p12. + // FIXME: GCC uses __int128_t and __uint128_t for cases that fit within + // a 128-bit integer, we should consider doing the same. + Diag(Enum->getLocation(), diag::ext_enum_too_large); + } BestType = Context.UnsignedLongLongTy; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus) diff --git a/clang/test/Sema/enum.c b/clang/test/Sema/enum.c index f8e380bd62d1ea..b0707914c0d852 100644 --- a/clang/test/Sema/enum.c +++ b/clang/test/Sema/enum.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple %itanium_abi_triple %s -fsyntax-only -verify -pedantic +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -fsyntax-only -std=c23 -verify -pedantic enum e {A, B = 42LL << 32, // expected-warning {{ISO C restricts enumerator values to range of 'int'}} C = -4, D = 12456 }; @@ -167,3 +168,27 @@ enum struct GH42372_1 { // expected-error {{expected identifier or '{'}} enum class GH42372_2 { One }; + +#if __STDC_VERSION__ >= 202311L +// FIXME: GCC picks __uint128_t as the underlying type for the enumeration +// value and Clang picks unsigned long long. +// FIXME: Clang does not yet implement WG14 N3029, so the warning about +// restricting enumerator values to 'int' is not correct. +enum GH59352 { // expected-warning {{enumeration values exceed range of largest integer}} + BigVal = 66666666666666666666wb // expected-warning {{ISO C restricts enumerator values to range of 'int' (66666666666666666666 is too large)}} +}; +_Static_assert(BigVal == 66666666666666666666wb); /* expected-error {{static assertion failed due to requirement 'BigVal == 66666666666666666666wb'}} + expected-note {{expression evaluates to '11326434445538011818 == 66666666666666666666'}} + */ +_Static_assert( + _Generic(BigVal, // expected-error {{static assertion failed}} + _BitInt(67) : 0, + __INTMAX_TYPE__ : 0, + __UINTMAX_TYPE__ : 0, + long long : 0, + unsigned long long : 0, + __int128_t : 0, + __uint128_t : 1 + ) +); +#endif // __STDC_VERSION__ >= 202311L