[clang] [llvm] [clang] Use separator for large numeric values in overflow diagnostic (PR #80939)

Atousa Duprat via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 6 23:45:20 PST 2024


https://github.com/Atousa updated https://github.com/llvm/llvm-project/pull/80939

>From c672d736f9cdce9ac9cbbf79df0d5c081d1a0792 Mon Sep 17 00:00:00 2001
From: Atousa Duprat <atousa.p at gmail.com>
Date: Tue, 6 Feb 2024 21:02:05 -0800
Subject: [PATCH] [clang] Use separator for large numeric values in overflow
 diagnostic

Add functionality to APInt::toString() that allows it to insert
separators between groups of digits, using the C++ litteral
separator ' between groups.

Fixes issue #58228
---
 clang/lib/AST/ExprConstant.cpp              |   6 +-
 clang/test/AST/Interp/c.c                   |   4 +-
 clang/test/C/drs/dr0xx.c                    |   2 +-
 clang/test/C/drs/dr2xx.c                    |   2 +-
 clang/test/Sema/integer-overflow.c          | 100 +++++++++---------
 clang/test/Sema/switch-1.c                  |   6 +-
 clang/test/SemaCXX/enum.cpp                 |   4 +-
 clang/test/SemaCXX/integer-overflow.cpp     | 110 ++++++++++----------
 clang/test/SemaObjC/integer-overflow.m      |   4 +-
 clang/test/SemaObjC/objc-literal-nsnumber.m |   2 +-
 llvm/include/llvm/ADT/APInt.h               |   3 +-
 llvm/include/llvm/ADT/StringExtras.h        |  11 +-
 llvm/lib/Support/APInt.cpp                  |  24 ++++-
 llvm/unittests/ADT/APIntTest.cpp            |  35 +++++++
 14 files changed, 188 insertions(+), 125 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 089bc2094567f7..22bc50d25a37a8 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2774,7 +2774,8 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
     if (Info.checkingForUndefinedBehavior())
       Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
                                        diag::warn_integer_constant_overflow)
-          << toString(Result, 10) << E->getType() << E->getSourceRange();
+          << toString(Result, 10, Result.isSigned(), false, true, true)
+          << E->getType() << E->getSourceRange();
     return HandleOverflow(Info, E, Value, E->getType());
   }
   return true;
@@ -13852,7 +13853,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
       if (Info.checkingForUndefinedBehavior())
         Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
                                          diag::warn_integer_constant_overflow)
-            << toString(Value, 10) << E->getType() << E->getSourceRange();
+            << toString(Value, 10, false, true, true)
+            << E->getType() << E->getSourceRange();
 
       if (!HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
                           E->getType()))
diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 9ab271a82aeef9..aa067b0bc74831 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -109,9 +109,9 @@ int somefunc(int i) {
                              // pedantic-expected-warning {{left operand of comma operator has no effect}} \
                              // pedantic-expected-warning {{overflow in expression; result is 131073}} \
                              // ref-warning {{left operand of comma operator has no effect}} \
-                             // ref-warning {{overflow in expression; result is 131073}} \
+                             // ref-warning {{overflow in expression; result is 131'073}} \
                              // pedantic-ref-warning {{left operand of comma operator has no effect}} \
-                             // pedantic-ref-warning {{overflow in expression; result is 131073}}
+                             // pedantic-ref-warning {{overflow in expression; result is 131'073}}
 
 }
 
diff --git a/clang/test/C/drs/dr0xx.c b/clang/test/C/drs/dr0xx.c
index d9c1fbe4ee40ab..c93cfb63d604cf 100644
--- a/clang/test/C/drs/dr0xx.c
+++ b/clang/test/C/drs/dr0xx.c
@@ -214,7 +214,7 @@ _Static_assert(__builtin_types_compatible_p(struct S { int a; }, union U { int a
  */
 void dr031(int i) {
   switch (i) {
-  case __INT_MAX__ + 1: break; /* expected-warning {{overflow in expression; result is -2147483648 with type 'int'}} */
+  case __INT_MAX__ + 1: break; /* expected-warning {{overflow in expression; result is -2'147'483'648 with type 'int'}} */
   #pragma clang diagnostic push
   #pragma clang diagnostic ignored "-Wswitch"
   /* Silence the targets which issue:
diff --git a/clang/test/C/drs/dr2xx.c b/clang/test/C/drs/dr2xx.c
index 9c8d77518ab55e..1b68b65acca6af 100644
--- a/clang/test/C/drs/dr2xx.c
+++ b/clang/test/C/drs/dr2xx.c
@@ -277,7 +277,7 @@ void dr258(void) {
 void dr261(void) {
   /* This is still an integer constant expression despite the overflow. */
   enum e1 {
-    ex1 = __INT_MAX__ + 1  /* expected-warning {{overflow in expression; result is -2147483648 with type 'int'}} */
+    ex1 = __INT_MAX__ + 1  /* expected-warning {{overflow in expression; result is -2'147'483'648 with type 'int'}} */
   };
 
   /* This is not an integer constant expression, because of the comma operator,
diff --git a/clang/test/Sema/integer-overflow.c b/clang/test/Sema/integer-overflow.c
index cf822f346e8b29..220fc1bed515a1 100644
--- a/clang/test/Sema/integer-overflow.c
+++ b/clang/test/Sema/integer-overflow.c
@@ -11,169 +11,169 @@ uint64_t f0(uint64_t);
 uint64_t f1(uint64_t, uint32_t);
 uint64_t f2(uint64_t, ...);
 
-static const uint64_t overflow = 1 * 4608 * 1024 * 1024; // expected-warning {{overflow in expression; result is 536870912 with type 'int'}}
+static const uint64_t overflow = 1 * 4608 * 1024 * 1024; // expected-warning {{overflow in expression; result is 536'870'912 with type 'int'}}
 
 uint64_t check_integer_overflows(int i) {
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   uint64_t overflow = 4608 * 1024 * 1024,
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
            overflow2 = (uint64_t)(4608 * 1024 * 1024),
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
            overflow3 = (uint64_t)(4608 * 1024 * 1024 * i),
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
            overflow4 =  (1ULL * ((4608) * ((1024) * (1024))) + 2ULL),
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
            multi_overflow = (uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow += overflow2 = overflow3 = (uint64_t)(4608 * 1024 * 1024);
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow += overflow2 = overflow3 = 4608 * 1024 * 1024;
 
   uint64_t not_overflow = 4608 * 1024 * 1024ULL;
   uint64_t not_overflow2 = (1ULL * ((uint64_t)(4608) * (1024 * 1024)) + 2ULL);
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow = 4608 * 1024 * 1024 ?  4608 * 1024 * 1024 : 0;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow =  0 ? 0 : 4608 * 1024 * 1024;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if (4608 * 1024 * 1024)
     return 0;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((uint64_t)(4608 * 1024 * 1024))
     return 1;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((uint64_t)(4608 * 1024 * 1024))
     return 2;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((uint64_t)(4608 * 1024 * 1024 * i))
     return 3;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((1ULL * ((4608) * ((1024) * (1024))) + 2ULL))
     return 4;
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024)))
     return 5;
 
   switch (i) {
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   case 4608 * 1024 * 1024:
     return 6;
-// expected-warning at +1 {{overflow in expression; result is 537919488 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 537'919'488 with type 'int'}}
   case (uint64_t)(4609 * 1024 * 1024):
     return 7;
 // expected-error at +1 {{expression is not an integer constant expression}}
   case ((uint64_t)(4608 * 1024 * 1024 * i)):
     return 8;
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   case ((1ULL * ((4608) * ((1024) * (1024))) + 2ULL)):
     return 9;
-// expected-warning at +2 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +2 2{{overflow in expression; result is 536'870'912 with type 'int'}}
 // expected-warning at +1 {{overflow converting case value to switch condition type (288230376151711744 to 0)}}
   case ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024))):
     return 10;
   }
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while (4608 * 1024 * 1024);
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((uint64_t)(4608 * 1024 * 1024 * i));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((1ULL * ((4608) * ((1024) * (1024))) + 2ULL));
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024)));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while (4608 * 1024 * 1024);
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((uint64_t)(4608 * 1024 * 1024 * i));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((1ULL * ((4608) * ((1024) * (1024))) + 2ULL));
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024)));
 
-// expected-warning at +3 {{overflow in expression; result is 536870912 with type 'int'}}
-// expected-warning at +3 {{overflow in expression; result is 536870912 with type 'int'}}
-// expected-warning at +3 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +3 {{overflow in expression; result is 536'870'912 with type 'int'}}
+// expected-warning at +3 {{overflow in expression; result is 536'870'912 with type 'int'}}
+// expected-warning at +3 {{overflow in expression; result is 536'870'912 with type 'int'}}
   for (uint64_t i = 4608 * 1024 * 1024;
        (uint64_t)(4608 * 1024 * 1024);
        i += (uint64_t)(4608 * 1024 * 1024 * i));
 
-// expected-warning at +3 {{overflow in expression; result is 536870912 with type 'int'}}
-// expected-warning at +3 2{{overflow in expression; result is 536870912 with type 'int'}}
-// expected-warning at +3 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +3 {{overflow in expression; result is 536'870'912 with type 'int'}}
+// expected-warning at +3 2{{overflow in expression; result is 536'870'912 with type 'int'}}
+// expected-warning at +3 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   for (uint64_t i = (1ULL * ((4608) * ((1024) * (1024))) + 2ULL);
        ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024)));
        i = ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024))));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   _Complex long long x = 4608 * 1024 * 1024;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (__real__ x) = 4608 * 1024 * 1024;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (__imag__ x) = 4608 * 1024 * 1024;
 
-// expected-warning at +4 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +4 {{overflow in expression; result is 536'870'912 with type 'int'}}
 // expected-warning at +3 {{array index 536870912 is past the end of the array (that has type 'uint64_t[10]' (aka 'unsigned long long[10]'))}}
 // expected-note at +1 {{array 'a' declared here}}
   uint64_t a[10];
   a[4608 * 1024 * 1024] = 1i;
 
-// expected-warning at +2 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +2 {{overflow in expression; result is 536'870'912 with type 'int'}}
   uint64_t *b;
   uint64_t b2 = b[4608 * 1024 * 1024] + 1;
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   (void)((i ? (4608 * 1024 * 1024) : (4608 * 1024 * 1024)) + 1);
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   return ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024)));
 }
 
 void check_integer_overflows_in_function_calls(void) {
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (void)f0(4608 * 1024 * 1024);
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   uint64_t x = f0(4608 * 1024 * 1024);
 
-// expected-warning at +2 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +2 {{overflow in expression; result is 536'870'912 with type 'int'}}
   uint64_t (*f0_ptr)(uint64_t) = &f0;
   (void)(*f0_ptr)(4608 * 1024 * 1024);
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (void)f2(0, f0(4608 * 1024 * 1024));
 }
 void check_integer_overflows_in_array_size(void) {
-  int arr[4608 * 1024 * 1024]; // expected-warning {{overflow in expression; result is 536870912 with type 'int'}}
+  int arr[4608 * 1024 * 1024]; // expected-warning {{overflow in expression; result is 536'870'912 with type 'int'}}
 }
 
 struct s {
diff --git a/clang/test/Sema/switch-1.c b/clang/test/Sema/switch-1.c
index 95e64748fb1fbf..09221990ac11d3 100644
--- a/clang/test/Sema/switch-1.c
+++ b/clang/test/Sema/switch-1.c
@@ -7,7 +7,7 @@ int f(int i) {
   switch (i) {
     case 2147483647 + 2:
 #if (__cplusplus <= 199711L) // C or C++03 or earlier modes
-    // expected-warning at -2 {{overflow in expression; result is -2147483647 with type 'int'}}
+    // expected-warning at -2 {{overflow in expression; result is -2'147'483'647 with type 'int'}}
 #else
     // expected-error at -4 {{case value is not a constant expression}} \
     // expected-note at -4 {{value 2147483649 is outside the range of representable values of type 'int'}}
@@ -23,7 +23,7 @@ int f(int i) {
       return 2;
     case (123456 *789012) + 1:
 #if (__cplusplus <= 199711L)
-    // expected-warning at -2 {{overflow in expression; result is -1375982336 with type 'int'}}
+    // expected-warning at -2 {{overflow in expression; result is -1'375'982'336 with type 'int'}}
 #else
     // expected-error at -4 {{case value is not a constant expression}} \
     // expected-note at -4 {{value 97408265472 is outside the range of representable values of type 'int'}}
@@ -47,7 +47,7 @@ int f(int i) {
     case 2147483647:
       return 0;
   }
-  return (i, 65537) * 65537; // expected-warning {{overflow in expression; result is 131073 with type 'int'}} \
+  return (i, 65537) * 65537; // expected-warning {{overflow in expression; result is 131'073 with type 'int'}} \
 			     // expected-warning {{left operand of comma operator has no effect}}
 }
 
diff --git a/clang/test/SemaCXX/enum.cpp b/clang/test/SemaCXX/enum.cpp
index fc65fd16f8c302..c482b3c571ab4a 100644
--- a/clang/test/SemaCXX/enum.cpp
+++ b/clang/test/SemaCXX/enum.cpp
@@ -103,7 +103,7 @@ enum { overflow = 123456 * 234567 };
 // expected-warning at -2 {{not an integral constant expression}}
 // expected-note at -3 {{value 28958703552 is outside the range of representable values}}
 #else 
-// expected-warning at -5 {{overflow in expression; result is -1106067520 with type 'int'}}
+// expected-warning at -5 {{overflow in expression; result is -1'106'067'520 with type 'int'}}
 #endif
 
 // FIXME: This is not consistent with the above case.
@@ -112,7 +112,7 @@ enum NoFold : int { overflow2 = 123456 * 234567 };
 // expected-error at -2 {{enumerator value is not a constant expression}}
 // expected-note at -3 {{value 28958703552 is outside the range of representable values}}
 #else
-// expected-warning at -5 {{overflow in expression; result is -1106067520 with type 'int'}}
+// expected-warning at -5 {{overflow in expression; result is -1'106'067'520 with type 'int'}}
 // expected-warning at -6 {{extension}}
 #endif
 
diff --git a/clang/test/SemaCXX/integer-overflow.cpp b/clang/test/SemaCXX/integer-overflow.cpp
index 0e8ad050aa14d8..a6c747c2d48c83 100644
--- a/clang/test/SemaCXX/integer-overflow.cpp
+++ b/clang/test/SemaCXX/integer-overflow.cpp
@@ -13,157 +13,157 @@ uint64_t f0(uint64_t);
 uint64_t f1(uint64_t, uint32_t);
 uint64_t f2(uint64_t, ...);
 
-static const uint64_t overflow = 1 * 4608 * 1024 * 1024; // expected-warning {{overflow in expression; result is 536870912 with type 'int'}}
+static const uint64_t overflow = 1 * 4608 * 1024 * 1024; // expected-warning {{overflow in expression; result is 536'870'912 with type 'int'}}
 
 uint64_t check_integer_overflows(int i) { //expected-note 0+{{declared here}}
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   uint64_t overflow = 4608 * 1024 * 1024,
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
            overflow2 = (uint64_t)(4608 * 1024 * 1024),
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
            overflow3 = (uint64_t)(4608 * 1024 * 1024 * i),
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
            overflow4 =  (1ULL * ((4608) * ((1024) * (1024))) + 2ULL),
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
            overflow5 = static_cast<uint64_t>(4608 * 1024 * 1024),
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
            multi_overflow = (uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow += overflow2 = overflow3 = (uint64_t)(4608 * 1024 * 1024);
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow += overflow2 = overflow3 = 4608 * 1024 * 1024;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow += overflow2 = overflow3 = static_cast<uint64_t>(4608 * 1024 * 1024);
 
   uint64_t not_overflow = 4608 * 1024 * 1024ULL;
   uint64_t not_overflow2 = (1ULL * ((uint64_t)(4608) * (1024 * 1024)) + 2ULL);
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow = 4608 * 1024 * 1024 ?  4608 * 1024 * 1024 : 0;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   overflow =  0 ? 0 : 4608 * 1024 * 1024;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if (4608 * 1024 * 1024)
     return 0;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((uint64_t)(4608 * 1024 * 1024))
     return 1;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if (static_cast<uint64_t>(4608 * 1024 * 1024))
     return 1;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((uint64_t)(4608 * 1024 * 1024))
     return 2;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((uint64_t)(4608 * 1024 * 1024 * i))
     return 3;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((1ULL * ((4608) * ((1024) * (1024))) + 2ULL))
     return 4;
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   if ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024)))
     return 5;
 
 #if __cplusplus < 201103L
   switch (i) {
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   case 4608 * 1024 * 1024:
     return 6;
-// expected-warning at +1 {{overflow in expression; result is 537919488 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 537'919'488 with type 'int'}}
   case (uint64_t)(4609 * 1024 * 1024):
     return 7;
-// expected-warning at +1 {{overflow in expression; result is 537919488 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 537'919'488 with type 'int'}}
   case 1 + static_cast<uint64_t>(4609 * 1024 * 1024):
     return 7;
 // expected-error at +1 {{expression is not an integral constant expression}}
   case ((uint64_t)(4608 * 1024 * 1024 * i)):
     return 8;
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   case ((1ULL * ((4608) * ((1024) * (1024))) + 2ULL)):
     return 9;
-// expected-warning at +2 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +2 2{{overflow in expression; result is 536'870'912 with type 'int'}}
 // expected-warning at +1 {{overflow converting case value to switch condition type (288230376151711744 to 0)}}
   case ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024))):
     return 10;
   }
 #endif
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while (4608 * 1024 * 1024);
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while (static_cast<uint64_t>(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((uint64_t)(4608 * 1024 * 1024 * i));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((1ULL * ((4608) * ((1024) * (1024))) + 2ULL));
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   while ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024)));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while (4608 * 1024 * 1024);
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while (static_cast<uint64_t>(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((uint64_t)(4608 * 1024 * 1024));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((uint64_t)(4608 * 1024 * 1024 * i));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((1ULL * ((4608) * ((1024) * (1024))) + 2ULL));
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   do { } while ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024)));
 
-// expected-warning at +3 {{overflow in expression; result is 536870912 with type 'int'}}
-// expected-warning at +3 {{overflow in expression; result is 536870912 with type 'int'}}
-// expected-warning at +3 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +3 {{overflow in expression; result is 536'870'912 with type 'int'}}
+// expected-warning at +3 {{overflow in expression; result is 536'870'912 with type 'int'}}
+// expected-warning at +3 {{overflow in expression; result is 536'870'912 with type 'int'}}
   for (uint64_t i = 4608 * 1024 * 1024;
        (uint64_t)(4608 * 1024 * 1024);
        i += (uint64_t)(4608 * 1024 * 1024 * i));
 
-// expected-warning at +3 {{overflow in expression; result is 536870912 with type 'int'}}
-// expected-warning at +3 2{{overflow in expression; result is 536870912 with type 'int'}}
-// expected-warning at +3 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +3 {{overflow in expression; result is 536'870'912 with type 'int'}}
+// expected-warning at +3 2{{overflow in expression; result is 536'870'912 with type 'int'}}
+// expected-warning at +3 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   for (uint64_t i = (1ULL * ((4608) * ((1024) * (1024))) + 2ULL);
        ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024)));
        i = ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024))));
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   _Complex long long x = 4608 * 1024 * 1024;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (__real__ x) = 4608 * 1024 * 1024;
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (__imag__ x) = 4608 * 1024 * 1024;
 
-// expected-warning at +2 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +2 {{overflow in expression; result is 536'870'912 with type 'int'}}
   uint64_t a[10];
   a[4608 * 1024 * 1024] = 1;
 #if __cplusplus < 201103L
@@ -171,22 +171,22 @@ uint64_t check_integer_overflows(int i) { //expected-note 0+{{declared here}}
 // expected-note at -4 {{array 'a' declared here}}
 #endif
 
-// expected-warning at +1 2{{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 2{{overflow in expression; result is 536'870'912 with type 'int'}}
   return ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024)));
 }
 
 void check_integer_overflows_in_function_calls() {
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (void)f0(4608 * 1024 * 1024);
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   uint64_t x = f0(4608 * 1024 * 1024);
 
-// expected-warning at +2 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +2 {{overflow in expression; result is 536'870'912 with type 'int'}}
   uint64_t (*f0_ptr)(uint64_t) = &f0;
   (void)(*f0_ptr)(4608 * 1024 * 1024);
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (void)f2(0, f0(4608 * 1024 * 1024));
 }
 
@@ -237,8 +237,8 @@ u_ptr<bool> Wrap(int64_t x) {
 int64_t Pass(int64_t x) { return x; }
 
 int m() {
-    int64_t x = Pass(30 * 24 * 60 * 59 * 1000);  // expected-warning {{overflow in expression; result is -1746167296 with type 'int'}}
-    auto r = Wrap(Pass(30 * 24 * 60 * 59 * 1000));  // expected-warning {{overflow in expression; result is -1746167296 with type 'int'}}
+    int64_t x = Pass(30 * 24 * 60 * 59 * 1000);  // expected-warning {{overflow in expression; result is -1'746'167'296 with type 'int'}}
+    auto r = Wrap(Pass(30 * 24 * 60 * 59 * 1000));  // expected-warning {{overflow in expression; result is -1'746'167'296 with type 'int'}}
     return 0;
 }
 }
diff --git a/clang/test/SemaObjC/integer-overflow.m b/clang/test/SemaObjC/integer-overflow.m
index 6d82e2951c1e65..255142729f8d56 100644
--- a/clang/test/SemaObjC/integer-overflow.m
+++ b/clang/test/SemaObjC/integer-overflow.m
@@ -9,10 +9,10 @@ - (int)add:(int)a with:(int)b {
 }
 
 - (void)testIntegerOverflows {
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (void)[self add:0 with:4608 * 1024 * 1024];
 
-// expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-warning at +1 {{overflow in expression; result is 536'870'912 with type 'int'}}
   (void)[self add:0 with:[self add:4608 * 1024 * 1024 with:0]];
 }
 @end
diff --git a/clang/test/SemaObjC/objc-literal-nsnumber.m b/clang/test/SemaObjC/objc-literal-nsnumber.m
index aa7dc955fb5feb..a6c098947b0b2a 100644
--- a/clang/test/SemaObjC/objc-literal-nsnumber.m
+++ b/clang/test/SemaObjC/objc-literal-nsnumber.m
@@ -64,7 +64,7 @@ int main(void) {
   @-five; // expected-error{{@- must be followed by a number to form an NSNumber object}}
   @+five; // expected-error{{@+ must be followed by a number to form an NSNumber object}}
   NSNumber *av = @(1391126400000);
-  NSNumber *bv = @(1391126400 * 1000); // expected-warning {{overflow in expression; result is -443003904 with type 'int'}}
+  NSNumber *bv = @(1391126400 * 1000); // expected-warning {{overflow in expression; result is -443'003'904 with type 'int'}}
   NSNumber *cv = @(big * thousand);
 }
 
diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index 6f2f25548cc84b..dd6d71b93334bb 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1626,7 +1626,8 @@ class [[nodiscard]] APInt {
   /// SmallString. If Radix > 10, UpperCase determine the case of letter
   /// digits.
   void toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed,
-                bool formatAsCLiteral = false, bool UpperCase = true) const;
+                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.
diff --git a/llvm/include/llvm/ADT/StringExtras.h b/llvm/include/llvm/ADT/StringExtras.h
index a24368924bc90a..2e751fbe92a8d3 100644
--- a/llvm/include/llvm/ADT/StringExtras.h
+++ b/llvm/include/llvm/ADT/StringExtras.h
@@ -329,14 +329,17 @@ inline std::string itostr(int64_t X) {
 }
 
 inline std::string toString(const APInt &I, unsigned Radix, bool Signed,
-                            bool formatAsCLiteral = false) {
+                            bool formatAsCLiteral = false,
+                            bool upperCase = true, bool addSeparators = false) {
   SmallString<40> S;
-  I.toString(S, Radix, Signed, formatAsCLiteral);
+  I.toString(S, Radix, Signed, formatAsCLiteral, upperCase, addSeparators);
   return std::string(S);
 }
 
-inline std::string toString(const APSInt &I, unsigned Radix) {
-  return toString(I, Radix, I.isSigned());
+inline std::string toString(const APSInt &I, unsigned Radix,
+                            bool formatAsCLiteral = false,
+                            bool upperCase = true, bool addSeparators = false) {
+  return toString(I, Radix, I.isSigned(), formatAsCLiteral, upperCase, addSeparators);
 }
 
 /// StrInStrNoCase - Portable version of strcasestr.  Locates the first
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 05b1526da95ff7..a186b81bc6797f 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -2161,7 +2161,8 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) {
 }
 
 void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed,
-                     bool formatAsCLiteral, bool UpperCase) const {
+                     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!");
@@ -2187,6 +2188,12 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed,
     }
   }
 
+  // Number of digits in a group between separators
+  int Grouping = 4;
+  if (Radix == 8 || Radix == 10) {
+    Grouping = 3;
+  }
+
   // First, check for a zero value and just short circuit the logic below.
   if (isZero()) {
     while (*Prefix) {
@@ -2223,9 +2230,14 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed,
       ++Prefix;
     };
 
+    int Pos = 0;
     while (N) {
+      if (insertSeparators && Pos % Grouping == 0 && Pos > 0) {
+        *--BufPtr = '\'';
+      }
       *--BufPtr = Digits[N % Radix];
       N /= Radix;
+      Pos++;
     }
     Str.append(BufPtr, std::end(Buffer));
     return;
@@ -2257,17 +2269,27 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed,
     unsigned ShiftAmt = (Radix == 16 ? 4 : (Radix == 8 ? 3 : 1));
     unsigned MaskAmt = Radix - 1;
 
+    int Pos = 0;
     while (Tmp.getBoolValue()) {
       unsigned Digit = unsigned(Tmp.getRawData()[0]) & MaskAmt;
+      if (insertSeparators && Pos % Grouping == 0 && Pos > 0) {
+        Str.push_back('\'');
+      }
       Str.push_back(Digits[Digit]);
       Tmp.lshrInPlace(ShiftAmt);
+      Pos++;
     }
   } else {
+    int Pos = 0;
     while (Tmp.getBoolValue()) {
       uint64_t Digit;
       udivrem(Tmp, Radix, Tmp, Digit);
       assert(Digit < Radix && "divide failed");
+      if (insertSeparators && Pos % Grouping == 0 && Pos > 0) {
+        Str.push_back('\'');
+      }
       Str.push_back(Digits[Digit]);
+      Pos++;
     }
   }
 
diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index 3b909f8f7d14e2..e3e7e1e7bac65d 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -1379,6 +1379,23 @@ TEST(APIntTest, toString) {
   EXPECT_EQ(std::string(S), "0");
   S.clear();
 
+  // with separators
+  APInt(64, 140).toString(S, 2, false, true, false, true);
+  EXPECT_EQ(std::string(S), "0b1000'1100");
+  S.clear();
+  APInt(64, 1024).toString(S, 8, false, true, false, true);
+  EXPECT_EQ(std::string(S), "02'000");
+  S.clear();
+  APInt(64, 1000000).toString(S, 10, false, true, false, true);
+  EXPECT_EQ(std::string(S), "1'000'000");
+  S.clear();
+  APInt(64, 1000000).toString(S, 16, false, true, true, true);
+  EXPECT_EQ(std::string(S), "0xF'4240");
+  S.clear();
+  APInt(64, 1'000'000'000).toString(S, 36, false, false, false, true);
+  EXPECT_EQ(std::string(S), "gj'dgxs");
+  S.clear();
+
   isSigned = false;
   APInt(8, 255, isSigned).toString(S, 2, isSigned, true);
   EXPECT_EQ(std::string(S), "0b11111111");
@@ -1415,6 +1432,24 @@ TEST(APIntTest, toString) {
   APInt(8, 255, isSigned).toString(S, 36, isSigned, false);
   EXPECT_EQ(std::string(S), "-1");
   S.clear();
+
+  // negative with separators
+  APInt(64, -140, isSigned).toString(S, 2, isSigned, true, false, true);
+  EXPECT_EQ(std::string(S), "-0b1000'1100");
+  S.clear();
+  APInt(64, -1024, isSigned).toString(S, 8, isSigned, true, false, true);
+  EXPECT_EQ(std::string(S), "-02'000");
+  S.clear();
+  APInt(64, -1000000, isSigned).toString(S, 10, isSigned, true, false, true);
+  EXPECT_EQ(std::string(S), "-1'000'000");
+  S.clear();
+  APInt(64, -1000000, isSigned).toString(S, 16, isSigned, true, true, true);
+  EXPECT_EQ(std::string(S), "-0xF'4240");
+  S.clear();
+  APInt(64, -1'000'000'000, isSigned)
+      .toString(S, 36, isSigned, false, false, true);
+  EXPECT_EQ(std::string(S), "-gj'dgxs");
+  S.clear();
 }
 
 TEST(APIntTest, Log2) {



More information about the llvm-commits mailing list