[clang] [Clang] Add thousands-separator to "cannot allocate array; evaluated array bound [...] exceeds the limit" diagnostic (PR #211785)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 24 07:07:14 PDT 2026
https://github.com/VachanVY updated https://github.com/llvm/llvm-project/pull/211785
>From 5116d7949696f434790773fa95831cff75cf4852 Mon Sep 17 00:00:00 2001
From: Vachan V Y <vachanvy05 at gmail.com>
Date: Fri, 24 Jul 2026 18:36:19 +0530
Subject: [PATCH 1/2] [Clang] Add thousands-separator to "cannot allocate
array; evaluated array bound [...] exceeds the limit" diagnostic
---
clang/docs/ReleaseNotes.md | 5 +++++
clang/include/clang/Basic/DiagnosticASTKinds.td | 2 +-
clang/lib/AST/ByteCode/InterpHelpers.h | 17 ++++++++++++++++-
clang/lib/AST/ExprConstant.cpp | 17 ++++++++++++++++-
clang/test/AST/ByteCode/dynalloc-limits.cpp | 4 ++--
.../SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp | 4 ++--
6 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 052838ef0af0d..634adef8a947e 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -123,6 +123,11 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
### Improvements to Clang's diagnostics
+- The diagnostic emitted when a constant-evaluated array allocation exceeds the
+ limit now formats the evaluated bound and the limit with thousands separators
+ and uses the clearer wording "exceeds the limit of" (e.g. "evaluated array
+ bound 1,048,577 exceeds the limit of 1,048,576"). (#GH211770)
+
### Improvements to Clang's time-trace
### Improvements to Coverage Mapping
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index f86f0157b2b1f..658750d25251a 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -355,7 +355,7 @@ def note_constexpr_new_negative : Note<
def note_constexpr_new_too_large : Note<
"cannot allocate array; evaluated array bound %0 is too large">;
def note_constexpr_new_exceeds_limits : Note<
- "cannot allocate array; evaluated array bound %0 exceeds the limit (%1); "
+ "cannot allocate array; evaluated array bound %0 exceeds the limit of %1; "
"use '-fconstexpr-steps' to increase this limit">;
def note_constexpr_new_too_small : Note<
"cannot allocate array; evaluated array bound %0 is too small to hold "
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h
index 4d908d1e44546..960801ad891f1 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -90,12 +90,27 @@ bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
return S.noteUndefinedBehavior();
}
+/// Format an integer with a thousands separator (',') for use in diagnostics,
+inline std::string toStringWithThousandsSeparator(uint64_t Value) {
+ std::string Digits = std::to_string(Value);
+ std::string Result;
+ size_t Len = Digits.size();
+ Result.reserve(Len + (Len - 1) / 3);
+ for (size_t I = 0; I < Len; ++I) {
+ if (I != 0 && (Len - I) % 3 == 0)
+ Result.push_back(',');
+ Result.push_back(Digits[I]);
+ }
+ return Result;
+}
+
inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) {
uint64_t Limit = S.getLangOpts().ConstexprStepLimit;
if (Limit != 0 && NumElems > Limit) {
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_new_exceeds_limits)
- << NumElems << Limit;
+ << toStringWithThousandsSeparator(NumElems)
+ << toStringWithThousandsSeparator(Limit);
return false;
}
return true;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 574dd8b04e779..cebb84965f081 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -79,6 +79,20 @@ using llvm::APSInt;
using llvm::APFloat;
using llvm::FixedPointSemantics;
+/// Format an integer with a thousands separator (',') for use in diagnostics,
+static std::string toStringWithThousandsSeparator(uint64_t Value) {
+ std::string Digits = std::to_string(Value);
+ std::string Result;
+ size_t Len = Digits.size();
+ Result.reserve(Len + (Len - 1) / 3);
+ for (size_t I = 0; I < Len; ++I) {
+ if (I != 0 && (Len - I) % 3 == 0)
+ Result.push_back(',');
+ Result.push_back(Digits[I]);
+ }
+ return Result;
+}
+
namespace {
struct LValue;
class CallStackFrame;
@@ -976,7 +990,8 @@ namespace {
if (Limit != 0 && ElemCount > Limit) {
if (Diag)
FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
- << ElemCount << Limit;
+ << toStringWithThousandsSeparator(ElemCount)
+ << toStringWithThousandsSeparator(Limit);
return false;
}
return true;
diff --git a/clang/test/AST/ByteCode/dynalloc-limits.cpp b/clang/test/AST/ByteCode/dynalloc-limits.cpp
index ed2d4faf974b1..decf1e2b24c3d 100644
--- a/clang/test/AST/ByteCode/dynalloc-limits.cpp
+++ b/clang/test/AST/ByteCode/dynalloc-limits.cpp
@@ -54,7 +54,7 @@ constexpr std::size_t s = S<std::size_t>(~0UL)[42]; // both-error {{constexpr va
constexpr std::size_t ssmall = S<std::size_t>(100)[42];
constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // both-error {{constexpr variable 's5' must be initialized by a constant expression}} \
- // both-note@#alloc {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024); use '-fconstexpr-steps' to increase this limit}} \
+ // both-note@#alloc {{cannot allocate array; evaluated array bound 1,025 exceeds the limit of 1,024; use '-fconstexpr-steps' to increase this limit}} \
// both-note@#call {{in call to 'this->alloc.allocate(1025)'}} \
// both-note {{in call}}
@@ -62,7 +62,7 @@ constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // both-error {{constexpr v
template <auto N>
constexpr int stack_array() {
- [[maybe_unused]] char BIG[N] = {1}; // both-note {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024)}}
+ [[maybe_unused]] char BIG[N] = {1}; // both-note {{cannot allocate array; evaluated array bound 1,025 exceeds the limit of 1,024}}
return BIG[N-1];
}
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
index 8bcb4d45d4af8..dd133ca4b14e0 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
@@ -65,7 +65,7 @@ constexpr std::size_t s4 = S<std::size_t>(1024)[42]; // expected-error {{constex
constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // expected-error{{constexpr variable 's5' must be initialized by a constant expression}} \
- // expected-note@#alloc {{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024); use '-fconstexpr-steps' to increase this limit}} \
+ // expected-note@#alloc {{cannot allocate array; evaluated array bound 1,025 exceeds the limit of 1,024; use '-fconstexpr-steps' to increase this limit}} \
// expected-note@#call {{in call to 'this->alloc.allocate(1025)'}} \
// expected-note {{in call}}
@@ -75,7 +75,7 @@ constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // expected-error{{constexp
template <auto N>
constexpr int stack_array() {
- [[maybe_unused]] char BIG[N] = {1}; // expected-note 3{{cannot allocate array; evaluated array bound 1025 exceeds the limit (1024); use '-fconstexpr-steps' to increase this limit}}
+ [[maybe_unused]] char BIG[N] = {1}; // expected-note 3{{cannot allocate array; evaluated array bound 1,025 exceeds the limit of 1,024; use '-fconstexpr-steps' to increase this limit}}
return BIG[N-1];
}
>From ed9831db0d5cc5b6a3849bfe0090743797884d93 Mon Sep 17 00:00:00 2001
From: Vachan V Y <vachanvy05 at gmail.com>
Date: Fri, 24 Jul 2026 19:30:03 +0530
Subject: [PATCH 2/2] [Clang] use existing facilities to add
thousands-separators
---
clang/docs/ReleaseNotes.md | 7 +++---
clang/lib/AST/ByteCode/InterpHelpers.h | 24 +++++++------------
clang/lib/AST/ExprConstant.cpp | 22 +++++------------
clang/test/AST/ByteCode/dynalloc-limits.cpp | 4 ++--
.../cxx2a-constexpr-dynalloc-limits.cpp | 4 ++--
5 files changed, 21 insertions(+), 40 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 8249e0649d105..04b6dd450541f 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -160,9 +160,9 @@ features cannot lower the translation-unit ABI level;
### Improvements to Clang's diagnostics
- The diagnostic emitted when a constant-evaluated array allocation exceeds the
- limit now formats the evaluated bound and the limit with thousands separators
- and uses the clearer wording "exceeds the limit of" (e.g. "evaluated array
- bound 1,048,577 exceeds the limit of 1,048,576"). (#GH211770)
+ limit now formats the evaluated bound and the limit with digit-group
+ separators and uses the clearer wording "exceeds the limit of" (e.g.
+ "evaluated array bound 1'048'577 exceeds the limit of 1'048'576"). (#GH211770)
- More consistent rendering of Unicode characters in diagnostic messages.
@@ -334,7 +334,6 @@ features cannot lower the translation-unit ABI level;
- Clang now attempts to print enumerator names rather than C-style cast expressions
in more diagnostics.
-
### Improvements to Clang's time-trace
### Improvements to Coverage Mapping
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h
index 960801ad891f1..3b14c3ea862dc 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -12,6 +12,8 @@
#include "DynamicAllocator.h"
#include "InterpState.h"
#include "Pointer.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/StringExtras.h"
namespace clang {
class CallExpr;
@@ -90,27 +92,17 @@ bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
return S.noteUndefinedBehavior();
}
-/// Format an integer with a thousands separator (',') for use in diagnostics,
-inline std::string toStringWithThousandsSeparator(uint64_t Value) {
- std::string Digits = std::to_string(Value);
- std::string Result;
- size_t Len = Digits.size();
- Result.reserve(Len + (Len - 1) / 3);
- for (size_t I = 0; I < Len; ++I) {
- if (I != 0 && (Len - I) % 3 == 0)
- Result.push_back(',');
- Result.push_back(Digits[I]);
- }
- return Result;
-}
-
inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) {
uint64_t Limit = S.getLangOpts().ConstexprStepLimit;
if (Limit != 0 && NumElems > Limit) {
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_new_exceeds_limits)
- << toStringWithThousandsSeparator(NumElems)
- << toStringWithThousandsSeparator(Limit);
+ << llvm::toString(llvm::APInt(64, NumElems), /*Radix=*/10,
+ /*Signed=*/false, /*formatAsCLiteral=*/false,
+ /*UpperCase=*/false, /*InsertSeparators=*/true)
+ << llvm::toString(llvm::APInt(64, Limit), /*Radix=*/10,
+ /*Signed=*/false, /*formatAsCLiteral=*/false,
+ /*UpperCase=*/false, /*InsertSeparators=*/true);
return false;
}
return true;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index cebb84965f081..2845e3a2acff3 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -79,20 +79,6 @@ using llvm::APSInt;
using llvm::APFloat;
using llvm::FixedPointSemantics;
-/// Format an integer with a thousands separator (',') for use in diagnostics,
-static std::string toStringWithThousandsSeparator(uint64_t Value) {
- std::string Digits = std::to_string(Value);
- std::string Result;
- size_t Len = Digits.size();
- Result.reserve(Len + (Len - 1) / 3);
- for (size_t I = 0; I < Len; ++I) {
- if (I != 0 && (Len - I) % 3 == 0)
- Result.push_back(',');
- Result.push_back(Digits[I]);
- }
- return Result;
-}
-
namespace {
struct LValue;
class CallStackFrame;
@@ -990,8 +976,12 @@ namespace {
if (Limit != 0 && ElemCount > Limit) {
if (Diag)
FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
- << toStringWithThousandsSeparator(ElemCount)
- << toStringWithThousandsSeparator(Limit);
+ << toString(APInt(64, ElemCount), /*Radix=*/10, /*Signed=*/false,
+ /*formatAsCLiteral=*/false, /*UpperCase=*/false,
+ /*InsertSeparators=*/true)
+ << toString(APInt(64, Limit), /*Radix=*/10, /*Signed=*/false,
+ /*formatAsCLiteral=*/false, /*UpperCase=*/false,
+ /*InsertSeparators=*/true);
return false;
}
return true;
diff --git a/clang/test/AST/ByteCode/dynalloc-limits.cpp b/clang/test/AST/ByteCode/dynalloc-limits.cpp
index decf1e2b24c3d..0cc2058a779b1 100644
--- a/clang/test/AST/ByteCode/dynalloc-limits.cpp
+++ b/clang/test/AST/ByteCode/dynalloc-limits.cpp
@@ -54,7 +54,7 @@ constexpr std::size_t s = S<std::size_t>(~0UL)[42]; // both-error {{constexpr va
constexpr std::size_t ssmall = S<std::size_t>(100)[42];
constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // both-error {{constexpr variable 's5' must be initialized by a constant expression}} \
- // both-note@#alloc {{cannot allocate array; evaluated array bound 1,025 exceeds the limit of 1,024; use '-fconstexpr-steps' to increase this limit}} \
+ // both-note@#alloc {{cannot allocate array; evaluated array bound 1'025 exceeds the limit of 1'024; use '-fconstexpr-steps' to increase this limit}} \
// both-note@#call {{in call to 'this->alloc.allocate(1025)'}} \
// both-note {{in call}}
@@ -62,7 +62,7 @@ constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // both-error {{constexpr v
template <auto N>
constexpr int stack_array() {
- [[maybe_unused]] char BIG[N] = {1}; // both-note {{cannot allocate array; evaluated array bound 1,025 exceeds the limit of 1,024}}
+ [[maybe_unused]] char BIG[N] = {1}; // both-note {{cannot allocate array; evaluated array bound 1'025 exceeds the limit of 1'024}}
return BIG[N-1];
}
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
index dd133ca4b14e0..cef9e5dcdb65d 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
@@ -65,7 +65,7 @@ constexpr std::size_t s4 = S<std::size_t>(1024)[42]; // expected-error {{constex
constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // expected-error{{constexpr variable 's5' must be initialized by a constant expression}} \
- // expected-note@#alloc {{cannot allocate array; evaluated array bound 1,025 exceeds the limit of 1,024; use '-fconstexpr-steps' to increase this limit}} \
+ // expected-note@#alloc {{cannot allocate array; evaluated array bound 1'025 exceeds the limit of 1'024; use '-fconstexpr-steps' to increase this limit}} \
// expected-note@#call {{in call to 'this->alloc.allocate(1025)'}} \
// expected-note {{in call}}
@@ -75,7 +75,7 @@ constexpr std::size_t s5 = S<std::size_t>(1025)[42]; // expected-error{{constexp
template <auto N>
constexpr int stack_array() {
- [[maybe_unused]] char BIG[N] = {1}; // expected-note 3{{cannot allocate array; evaluated array bound 1,025 exceeds the limit of 1,024; use '-fconstexpr-steps' to increase this limit}}
+ [[maybe_unused]] char BIG[N] = {1}; // expected-note 3{{cannot allocate array; evaluated array bound 1'025 exceeds the limit of 1'024; use '-fconstexpr-steps' to increase this limit}}
return BIG[N-1];
}
More information about the cfe-commits
mailing list