[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 09:35:48 PST 2024


https://github.com/AaronBallman updated https://github.com/llvm/llvm-project/pull/81760

>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 1/2] [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

>From 59daffc901698d1c4004b65250f93f4771e0b4fe Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Wed, 14 Feb 2024 12:35:01 -0500
Subject: [PATCH 2/2] Correct issues found by precommit CI

This adds an explicit triple to ensure we don't run into problems with
intmax_t and long long being the same type (etc).
---
 clang/test/Sema/enum.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/test/Sema/enum.c b/clang/test/Sema/enum.c
index c5255dfdf16faf..b0707914c0d852 100644
--- a/clang/test/Sema/enum.c
+++ b/clang/test/Sema/enum.c
@@ -1,5 +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
+// 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 };
@@ -185,6 +185,8 @@ _Static_assert(
     _BitInt(67) : 0,
     __INTMAX_TYPE__ : 0,
     __UINTMAX_TYPE__ : 0,
+    long long : 0,
+    unsigned long long : 0,
     __int128_t : 0,
     __uint128_t : 1
     )



More information about the cfe-commits mailing list