[clang] [C23] No longer assert on huge enumerator values (PR #81760)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 14 08:39:45 PST 2024


https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/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

>From 274e3f733f1a383650771b051fa71a8fea279a9a Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Wed, 14 Feb 2024 11:34:30 -0500
Subject: [PATCH] [C23] No longer assert on huge enumerator values

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
---
 clang/docs/ReleaseNotes.rst |  8 ++++++++
 clang/lib/Sema/SemaDecl.cpp |  9 +++++++--
 clang/test/Sema/enum.c      | 23 +++++++++++++++++++++++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6cf48d63dd512e..31fd161c65fc32 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -169,6 +169,14 @@ Improvements to Clang's diagnostics
 
 - Clang now diagnoses friend declarations with an ``enum`` elaborated-type-specifier in language modes after C++98.
 
+- 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 09a35fddba1954..52cb2c838c6e47 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..c5255dfdf16faf 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 %itanium_abi_triple %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,25 @@ 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,
+    __int128_t : 0,
+    __uint128_t : 1
+    )
+);
+#endif // __STDC_VERSION__ >= 202311L



More information about the cfe-commits mailing list