[clang] 3b7ba24 - [C23] No longer assert on huge enumerator values (#81760)

via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 20 08:58:08 PST 2024


Author: Aaron Ballman
Date: 2024-02-20T11:58:03-05:00
New Revision: 3b7ba2482e2c1b9b240664a247db55d253a3e1f5

URL: https://github.com/llvm/llvm-project/commit/3b7ba2482e2c1b9b240664a247db55d253a3e1f5
DIFF: https://github.com/llvm/llvm-project/commit/3b7ba2482e2c1b9b240664a247db55d253a3e1f5.diff

LOG: [C23] No longer assert on huge enumerator values (#81760)

C23 added the wb and uwb suffixes to generate a bit-precise integer
value. These values can be larger than what is representable in intmax_t
or uintmax_t.

We were asserting that an enumerator constant could not have a value
larger than unsigned long long but that's now a possibility. This patch
turns the assertion into a "value too large" diagnostic.

Note, we do not yet implement WG14 N3029 and so the behavior of this
patch will cause the enumerator to be cast to unsigned long long, but
this behavior may change in the future. GCC selects __uint128_t as the
underlying type for such an enumeration and we may want to match that
behavior in the future. This patch has several FIXME comments related to
this and the release notes call out the possibility of a change in
behavior in the future.

Fixes https://github.com/llvm/llvm-project/issues/69352

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaDecl.cpp
    clang/test/Sema/enum.c

Removed: 
    


################################################################################
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 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3029.htm>`_.
+  Fixes `#69352 <https://github.com/llvm/llvm-project/issues/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


        


More information about the cfe-commits mailing list