https://github.com/maramatias updated 
https://github.com/llvm/llvm-project/pull/145053

>From f58ea201585cb1b0128f97b9edb07f35621d81b0 Mon Sep 17 00:00:00 2001
From: Mara Matias <mara.mati...@gmail.com>
Date: Wed, 18 Jun 2025 09:06:10 -0700
Subject: [PATCH 1/2] [clang] Avoid printing overly large integer/_BitInt
 numbers in static assertion failure diagnostics #71675

---
 clang/docs/ReleaseNotes.rst          |  6 +++++-
 clang/lib/Sema/SemaDeclCXX.cpp       | 17 ++++++++++++++++-
 clang/test/AST/ByteCode/intap.cpp    |  8 ++++----
 clang/test/Sema/enum.c               |  2 +-
 clang/test/SemaCXX/static-assert.cpp |  6 ++++++
 5 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bc8e157e2b1c0..9e48175700613 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -647,7 +647,11 @@ Improvements to Clang's diagnostics
   #GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490,
   #GH36703, #GH32903, #GH23312, #GH69874.
 
-  
+- Improved the performance of static assertions envolving large integers by
+  using hex format instead of string.
+
+  Fixes #GH71675
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 16645ecf411e5..71bf5f60d6e1b 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -47,6 +47,7 @@
 #include "clang/Sema/SemaOpenMP.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateDeduction.h"
+#include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
@@ -17575,7 +17576,21 @@ static bool ConvertAPValueToString(const APValue &V, 
QualType T,
           break;
         }
       }
-      V.getInt().toString(Str);
+
+      llvm::APSInt vInt = V.getInt();
+      if (llvm::APSInt::compareValues(
+              vInt, llvm::APSInt::getUnsigned(
+                        std::numeric_limits<uint64_t>::max())) >= 0 ||
+          vInt < std::numeric_limits<int64_t>::min()) {
+        // The value of cutSize is not special, it is just a number of
+        // characters that gives us enough info without losing readability.
+        const int cutSize = 20;
+        vInt.toString(Str, 16);
+        Str.erase(Str.begin() + cutSize, Str.end() - cutSize);
+        Str.insert(Str.begin() + cutSize, 3, '.');
+      } else {
+        vInt.toString(Str);
+      }
     }
 
     break;
diff --git a/clang/test/AST/ByteCode/intap.cpp 
b/clang/test/AST/ByteCode/intap.cpp
index 68883871ffd26..1381bba5050a2 100644
--- a/clang/test/AST/ByteCode/intap.cpp
+++ b/clang/test/AST/ByteCode/intap.cpp
@@ -87,12 +87,12 @@ typedef unsigned __int128 uint128_t;
 static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L));
 static_assert(UINT128_MAX == -1, "");
 static_assert(UINT128_MAX == 1, ""); // both-error {{static assertion failed}} 
\
-                                     // both-note 
{{'340282366920938463463374607431768211455 == 1'}}
+                                     // both-note 
{{'FFFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 1'}}
 
 static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1;
 static_assert(INT128_MAX != 0, "");
 static_assert(INT128_MAX == 0, ""); // both-error {{failed}} \
-                                    // both-note {{evaluates to 
'170141183460469231731687303715884105727 == 0'}}
+                                    // both-note {{evaluates to 
'7FFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 0'}}
 static const __int128_t INT128_MIN = -INT128_MAX - 1;
 
 
@@ -113,14 +113,14 @@ namespace i128 {
   static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L));
   static_assert(UINT128_MAX == -1, "");
   static_assert(UINT128_MAX == 1, ""); // both-error {{static assertion 
failed}} \
-                                       // both-note 
{{'340282366920938463463374607431768211455 == 1'}}
+                                       // both-note 
{{'FFFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 1'}}
 
   constexpr uint128_t TooMuch = UINT128_MAX * 2;
 
   static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1;
   static_assert(INT128_MAX != 0, "");
   static_assert(INT128_MAX == 0, ""); // both-error {{failed}} \
-                                      // both-note {{evaluates to 
'170141183460469231731687303715884105727 == 0'}}
+                                      // both-note {{evaluates to 
'7FFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 0'}}
 
   constexpr int128_t TooMuch2 = INT128_MAX * INT128_MAX; // both-error {{must 
be initialized by a constant expression}} \
                                                          // both-note {{value 
28948022309329048855892746252171976962977213799489202546401021394546514198529 
is outside the range of representable}}
diff --git a/clang/test/Sema/enum.c b/clang/test/Sema/enum.c
index 01e41d4ebe956..80315a0c29b6a 100644
--- a/clang/test/Sema/enum.c
+++ b/clang/test/Sema/enum.c
@@ -196,7 +196,7 @@ enum GH59352 { // expected-warning {{enumeration values 
exceed range of largest
  BigVal = 66666666666666666666wb
 };
 _Static_assert(BigVal == 66666666666666666666wb); /* expected-error {{static 
assertion failed due to requirement 'BigVal == 66666666666666666666wb'}}
-                                                     expected-note 
{{expression evaluates to '11326434445538011818 == 66666666666666666666'}}
+                                                     expected-note 
{{expression evaluates to '11326434445538011818 == 
39D2F941E420AAAAA<U+0000><U+0000><U+0000>...<U+0000><U+0000><U+0000>39D2F941E420AAAAA'}}
                                                    */
 _Static_assert(
     _Generic(BigVal,                             // expected-error {{static 
assertion failed}}
diff --git a/clang/test/SemaCXX/static-assert.cpp 
b/clang/test/SemaCXX/static-assert.cpp
index bf6a2eeb432a3..4b9d23cb8c808 100644
--- a/clang/test/SemaCXX/static-assert.cpp
+++ b/clang/test/SemaCXX/static-assert.cpp
@@ -255,6 +255,12 @@ int f() {
 }
 }
 
+namespace GH71675 {
+constexpr unsigned _BitInt(__BITINT_MAXWIDTH__ >> 6) F = ~0; // 
expected-warning {{Clang extension}}
+static_assert(F == 1,""); // expected-error {{static assertion failed due to 
requirement 'F == 1'}} \
+                          // expected-note {{expression evaluates to 
'FFFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 1'}}
+} // namespace GH71675
+
 namespace Diagnostics {
   /// No notes for literals.
   static_assert(false, ""); // expected-error {{failed}}

>From c60c2bf0be937d64e83da993a83e0aa4fc3f1bdb Mon Sep 17 00:00:00 2001
From: Mara Matias <mara.mati...@gmail.com>
Date: Fri, 4 Jul 2025 16:19:32 -0700
Subject: [PATCH 2/2] fixup! [clang] Avoid printing overly large
 integer/_BitInt numbers in static assertion failure diagnostics #71675

---
 clang/docs/ReleaseNotes.rst          |  4 ++--
 clang/lib/Sema/SemaDeclCXX.cpp       | 15 +--------------
 clang/test/Sema/enum.c               |  2 +-
 clang/test/SemaCXX/static-assert.cpp |  6 +++++-
 llvm/include/llvm/ADT/APInt.h        | 11 +++++++++++
 llvm/include/llvm/ADT/APSInt.h       |  6 ++++++
 llvm/lib/Support/APInt.cpp           | 27 +++++++++++++++++++++++++++
 7 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9e48175700613..8b069a1f7fe36 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -647,8 +647,8 @@ Improvements to Clang's diagnostics
   #GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490,
   #GH36703, #GH32903, #GH23312, #GH69874.
 
-- Improved the performance of static assertions envolving large integers by
-  using hex format instead of string.
+- Improved the performance of static assertions involving large integers by
+  using hex format instead of string for particularly large values.
 
   Fixes #GH71675
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 71bf5f60d6e1b..218d50994ed86 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17577,20 +17577,7 @@ static bool ConvertAPValueToString(const APValue &V, 
QualType T,
         }
       }
 
-      llvm::APSInt vInt = V.getInt();
-      if (llvm::APSInt::compareValues(
-              vInt, llvm::APSInt::getUnsigned(
-                        std::numeric_limits<uint64_t>::max())) >= 0 ||
-          vInt < std::numeric_limits<int64_t>::min()) {
-        // The value of cutSize is not special, it is just a number of
-        // characters that gives us enough info without losing readability.
-        const int cutSize = 20;
-        vInt.toString(Str, 16);
-        Str.erase(Str.begin() + cutSize, Str.end() - cutSize);
-        Str.insert(Str.begin() + cutSize, 3, '.');
-      } else {
-        vInt.toString(Str);
-      }
+      V.getInt().toStringTruncated(Str);
     }
 
     break;
diff --git a/clang/test/Sema/enum.c b/clang/test/Sema/enum.c
index 80315a0c29b6a..01e41d4ebe956 100644
--- a/clang/test/Sema/enum.c
+++ b/clang/test/Sema/enum.c
@@ -196,7 +196,7 @@ enum GH59352 { // expected-warning {{enumeration values 
exceed range of largest
  BigVal = 66666666666666666666wb
 };
 _Static_assert(BigVal == 66666666666666666666wb); /* expected-error {{static 
assertion failed due to requirement 'BigVal == 66666666666666666666wb'}}
-                                                     expected-note 
{{expression evaluates to '11326434445538011818 == 
39D2F941E420AAAAA<U+0000><U+0000><U+0000>...<U+0000><U+0000><U+0000>39D2F941E420AAAAA'}}
+                                                     expected-note 
{{expression evaluates to '11326434445538011818 == 66666666666666666666'}}
                                                    */
 _Static_assert(
     _Generic(BigVal,                             // expected-error {{static 
assertion failed}}
diff --git a/clang/test/SemaCXX/static-assert.cpp 
b/clang/test/SemaCXX/static-assert.cpp
index 4b9d23cb8c808..2488e235d7f7e 100644
--- a/clang/test/SemaCXX/static-assert.cpp
+++ b/clang/test/SemaCXX/static-assert.cpp
@@ -258,7 +258,11 @@ int f() {
 namespace GH71675 {
 constexpr unsigned _BitInt(__BITINT_MAXWIDTH__ >> 6) F = ~0; // 
expected-warning {{Clang extension}}
 static_assert(F == 1,""); // expected-error {{static assertion failed due to 
requirement 'F == 1'}} \
-                          // expected-note {{expression evaluates to 
'FFFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 1'}}
+                          // expected-note {{expression evaluates to 
'40141321820360630391...65812318570934173695 == 1'}}
+
+constexpr unsigned _BitInt(__BITINT_MAXWIDTH__) G = ~0; // expected-warning 
{{Clang extension}}
+static_assert(G == 1,""); // expected-error {{static assertion failed due to 
requirement 'G == 1'}} \
+                          // expected-note {{expression evaluates to 
'...85551374411818336255 == 1'}}
 } // namespace GH71675
 
 namespace Diagnostics {
diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index 295506393a1c4..8cc8747bbedcd 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1686,6 +1686,17 @@ class [[nodiscard]] APInt {
                          bool UpperCase = true,
                          bool InsertSeparators = false) const;
 
+  /// Converts an APInt to a string and append it to Str.  Str is commonly a
+  /// SmallString. If Radix > 10, UpperCase determine the case of letter
+  /// digits.
+  /// Very large numbers ar truncated and only the first and last 20 digits 
will
+  /// be added with an elipsis separating them.
+  LLVM_ABI void toStringTruncated(SmallVectorImpl<char> &Str, unsigned Radix,
+                                  bool Signed, bool truncate = true,
+                                  bool formatAsCLiteral = false,
+                                  bool UpperCase = true,
+                                  bool InsertSeparators = false) const;
+
   /// Considers the APInt to be unsigned and converts it into a string in the
   /// radix given. The radix can be 2, 8, 10 16, or 36.
   void toStringUnsigned(SmallVectorImpl<char> &Str, unsigned Radix = 10) const 
{
diff --git a/llvm/include/llvm/ADT/APSInt.h b/llvm/include/llvm/ADT/APSInt.h
index 88a7a6e71c817..f3b5c79569301 100644
--- a/llvm/include/llvm/ADT/APSInt.h
+++ b/llvm/include/llvm/ADT/APSInt.h
@@ -86,6 +86,12 @@ class [[nodiscard]] APSInt : public APInt {
   }
   using APInt::toString;
 
+  void toStringTruncated(SmallVectorImpl<char> &Str,
+                         unsigned Radix = 10) const {
+    APInt::toStringTruncated(Str, Radix, isSigned());
+  }
+  using APInt::toStringTruncated;
+
   /// If this int is representable using an int64_t.
   bool isRepresentableByInt64() const {
     // For unsigned values with 64 active bits, they technically fit into a
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 954af7fff92a8..37e625c946f9d 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -2164,6 +2164,13 @@ void APInt::fromString(unsigned numbits, StringRef str, 
uint8_t radix) {
 void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed,
                      bool formatAsCLiteral, bool UpperCase,
                      bool InsertSeparators) const {
+  toStringTruncated(Str, Radix, Signed, false, formatAsCLiteral, UpperCase,
+                    InsertSeparators);
+}
+
+void APInt::toStringTruncated(SmallVectorImpl<char> &Str, unsigned Radix,
+                              bool Signed, bool truncate, bool 
formatAsCLiteral,
+                              bool UpperCase, bool InsertSeparators) const {
   assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2 ||
           Radix == 36) &&
          "Radix should be 2, 8, 10, 16, or 36!");
@@ -2278,8 +2285,28 @@ void APInt::toString(SmallVectorImpl<char> &Str, 
unsigned Radix, bool Signed,
     }
   } else {
     int Pos = 0;
+    // The value of cutOffSize is not special, it is just a number of
+    // characters that gives us enough info without losing readability.
+    constexpr int cutOffSize = 20;
     while (Tmp.getBoolValue()) {
       uint64_t Digit;
+      if (truncate && Pos == cutOffSize) {
+        unsigned numDigits = (int32_t)(Tmp.logBase2()/log2(Radix))+1;
+        if(numDigits-cutOffSize > 0) {
+          // Calculating pow of exponents over 300000 takes a long time.
+          // To keep note printing time short(under 3s), values with more 
digits
+          // will only return the last 20 digits.
+          if(numDigits < 300000) {
+            APInt divider = 
APIntOps::pow(APInt(Tmp.getBitWidth(),Radix),numDigits-cutOffSize);
+            Tmp = Tmp.udiv(divider);
+            Str.append(3,'.');
+          }
+          else {
+            Str.append(3,'.');
+            break;
+          }
+        }
+      }
       udivrem(Tmp, Radix, Tmp, Digit);
       assert(Digit < Radix && "divide failed");
       if (InsertSeparators && Pos % Grouping == 0 && Pos > 0)

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to