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 <[email protected]> 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 <[email protected]> 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]; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
