[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
Sun Aug 2 08:02:57 PDT 2026
https://github.com/VachanVY updated https://github.com/llvm/llvm-project/pull/211785
>From f2f3a679bb89cdab7070e607507c1e70ca8c456c Mon Sep 17 00:00:00 2001
From: Vachan V Y <vachanvy05 at gmail.com>
Date: Mon, 27 Jul 2026 22:37:27 +0530
Subject: [PATCH] [Clang] Add thousands-separator to large integers; change the
diagnostics engine
---
clang/include/clang/AST/OptionalDiagnostic.h | 5 ++--
clang/include/clang/Basic/Diagnostic.h | 26 ++++++++++++++-----
.../include/clang/Basic/DiagnosticASTKinds.td | 2 +-
clang/lib/AST/ByteCode/Interp.h | 24 +++++++----------
clang/lib/AST/ByteCode/InterpHelpers.h | 4 +--
clang/lib/AST/ExprConstant.cpp | 10 +++----
clang/lib/Basic/Diagnostic.cpp | 21 +++++++++++++--
clang/lib/Sema/SemaDecl.cpp | 5 ++--
clang/lib/Sema/SemaExprCXX.cpp | 4 +--
clang/lib/Sema/SemaType.cpp | 4 +--
10 files changed, 61 insertions(+), 44 deletions(-)
diff --git a/clang/include/clang/AST/OptionalDiagnostic.h b/clang/include/clang/AST/OptionalDiagnostic.h
index c9a2d19f4ebce..b21955bf0088b 100644
--- a/clang/include/clang/AST/OptionalDiagnostic.h
+++ b/clang/include/clang/AST/OptionalDiagnostic.h
@@ -39,9 +39,8 @@ class OptionalDiagnostic {
OptionalDiagnostic &operator<<(const llvm::APSInt &I) {
if (Diag) {
- SmallVector<char, 32> Buffer;
- I.toString(Buffer);
- *Diag << StringRef(Buffer.data(), Buffer.size());
+ std::string Str = formatDiagnosticInteger(I, I.isSigned());
+ *Diag << StringRef(Str);
}
return *this;
}
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index 66e79e3b4300b..82285d2bac1aa 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -1402,19 +1402,33 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
return DB;
}
+inline constexpr uint64_t DiagnosticIntegerSeparatorThreshold = 100'000;
+
+inline std::string formatDiagnosticInteger(const llvm::APInt &Val,
+ bool Signed) {
+ bool Small = false;
+ if (Signed) {
+ if (Val.getSignificantBits() <= 64) {
+ int64_t S = Val.getSExtValue();
+ uint64_t Magnitude = S < 0 ? -static_cast<uint64_t>(S) : uint64_t(S);
+ Small = Magnitude < DiagnosticIntegerSeparatorThreshold;
+ }
+ } else if (Val.getActiveBits() <= 64) {
+ Small = Val.getZExtValue() < DiagnosticIntegerSeparatorThreshold;
+ }
+ return toString(Val, /*Radix=*/10, Signed, /*formatAsCLiteral=*/false,
+ /*UpperCase=*/true, /*InsertSeparators=*/!Small);
+}
+
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
const llvm::APSInt &Int) {
- DB.AddString(toString(Int, /*Radix=*/10, Int.isSigned(),
- /*formatAsCLiteral=*/false,
- /*UpperCase=*/true, /*InsertSeparators=*/true));
+ DB.AddString(formatDiagnosticInteger(Int, Int.isSigned()));
return DB;
}
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
const llvm::APInt &Int) {
- DB.AddString(toString(Int, /*Radix=*/10, /*Signed=*/false,
- /*formatAsCLiteral=*/false,
- /*UpperCase=*/true, /*InsertSeparators=*/true));
+ DB.AddString(formatDiagnosticInteger(Int, /*Signed=*/false));
return DB;
}
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/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 405f4a29ec982..cc57ddb61d1e5 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -356,12 +356,10 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
if (S.checkingForUndefinedBehavior()) {
const Expr *E = S.Current->getExpr(OpPC);
QualType Type = E->getType();
- SmallString<32> Trunc;
- Value.trunc(Result.bitWidth())
- .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
- /*UpperCase=*/true, /*InsertSeparators=*/true);
S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
- << Trunc << Type << E->getSourceRange();
+ << formatDiagnosticInteger(Value.trunc(Result.bitWidth()),
+ Result.isSigned())
+ << Type << E->getSourceRange();
}
if (!handleOverflow(S, OpPC, Value)) {
@@ -867,12 +865,10 @@ bool Neg(InterpState &S, CodePtr OpPC) {
if (S.checkingForUndefinedBehavior()) {
const Expr *E = S.Current->getExpr(OpPC);
QualType Type = E->getType();
- SmallString<32> Trunc;
- NegatedValue.trunc(Result.bitWidth())
- .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
- /*UpperCase=*/true, /*InsertSeparators=*/true);
S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
- << Trunc << Type << E->getSourceRange();
+ << formatDiagnosticInteger(NegatedValue.trunc(Result.bitWidth()),
+ Result.isSigned())
+ << Type << E->getSourceRange();
return true;
}
@@ -956,12 +952,10 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if (S.checkingForUndefinedBehavior()) {
const Expr *E = S.Current->getExpr(OpPC);
QualType Type = E->getType();
- SmallString<32> Trunc;
- APResult.trunc(Result.bitWidth())
- .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
- /*UpperCase=*/true, /*InsertSeparators=*/true);
S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
- << Trunc << Type << E->getSourceRange();
+ << formatDiagnosticInteger(APResult.trunc(Result.bitWidth()),
+ Result.isSigned())
+ << Type << E->getSourceRange();
return true;
}
return handleOverflow(S, OpPC, APResult);
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h
index 4d908d1e44546..00136add4433f 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -145,10 +145,10 @@ bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
if (NumElements->isSigned() && NumElements->isNegative()) {
S.FFDiag(Loc, diag::note_constexpr_new_negative)
- << NumElements->toDiagnosticString(S.getASTContext());
+ << NumElements->toAPSInt();
} else {
S.FFDiag(Loc, diag::note_constexpr_new_too_large)
- << NumElements->toDiagnosticString(S.getASTContext());
+ << NumElements->toAPSInt();
}
}
return false;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 574dd8b04e779..f07f7d4c1e70c 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2819,9 +2819,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, Result.isSigned(), /*formatAsCLiteral=*/false,
- /*UpperCase=*/true, /*InsertSeparators=*/true)
- << E->getType() << E->getSourceRange();
+ << formatDiagnosticInteger(Result, Result.isSigned()) << E->getType()
+ << E->getSourceRange();
return HandleOverflow(Info, E, Value, E->getType());
}
return true;
@@ -19857,9 +19856,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_integer_constant_overflow)
- << toString(Value, 10, Value.isSigned(), /*formatAsCLiteral=*/false,
- /*UpperCase=*/true, /*InsertSeparators=*/true)
- << E->getType() << E->getSourceRange();
+ << formatDiagnosticInteger(Value, Value.isSigned()) << E->getType()
+ << E->getSourceRange();
if (!HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
E->getType()))
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index 4c63e54964ed6..7e7f261a4a5d7 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -22,6 +22,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TokenKinds.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -895,6 +896,22 @@ static void HandleIntegerHumanModifier(int64_t ValNo,
Out << ValNo;
}
+static void HandleIntegerDefaultModifier(int64_t Val,
+ SmallVectorImpl<char> &OutStr) {
+ std::string Str = formatDiagnosticInteger(
+ llvm::APInt(64, static_cast<uint64_t>(Val), /*isSigned=*/true),
+ /*Signed=*/true);
+ OutStr.append(Str.begin(), Str.end());
+}
+
+static void
+HandleUnsignedIntegerDefaultModifier(uint64_t Val,
+ SmallVectorImpl<char> &OutStr) {
+ std::string Str =
+ formatDiagnosticInteger(llvm::APInt(64, Val), /*Signed=*/false);
+ OutStr.append(Str.begin(), Str.end());
+}
+
/// PluralNumber - Parse an unsigned integer and advance Start.
static unsigned PluralNumber(const char *&Start, const char *End) {
// Programming 101: Parse a decimal number :-)
@@ -1279,7 +1296,7 @@ void Diagnostic::FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
HandleIntegerHumanModifier(Val, OutStr);
} else {
assert(ModifierLen == 0 && "Unknown integer modifier");
- llvm::raw_svector_ostream(OutStr) << Val;
+ HandleIntegerDefaultModifier(Val, OutStr);
}
break;
}
@@ -1299,7 +1316,7 @@ void Diagnostic::FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
HandleIntegerHumanModifier(Val, OutStr);
} else {
assert(ModifierLen == 0 && "Unknown integer modifier");
- llvm::raw_svector_ostream(OutStr) << Val;
+ HandleUnsignedIntegerDefaultModifier(Val, OutStr);
}
break;
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c5920f03ed6e1..40491bf996bed 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -6860,9 +6860,8 @@ bool Sema::tryToFixVariablyModifiedVarType(TypeSourceInfo *&TInfo,
if (SizeIsNegative)
Diag(Loc, diag::err_typecheck_negative_array_size);
else if (Oversized.getBoolValue())
- Diag(Loc, diag::err_array_too_large) << toString(
- Oversized, 10, Oversized.isSigned(), /*formatAsCLiteral=*/false,
- /*UpperCase=*/false, /*InsertSeparators=*/true);
+ Diag(Loc, diag::err_array_too_large)
+ << formatDiagnosticInteger(Oversized, Oversized.isSigned());
else if (FailedFoldDiagID)
Diag(Loc, FailedFoldDiagID);
return false;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 538604aa2e64b..7a9e8d1a51b18 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2415,9 +2415,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
return ExprError(
Diag((*ArraySize)->getBeginLoc(), diag::err_array_too_large)
- << toString(*Value, 10, Value->isSigned(),
- /*formatAsCLiteral=*/false, /*UpperCase=*/false,
- /*InsertSeparators=*/true)
+ << formatDiagnosticInteger(*Value, Value->isSigned())
<< (*ArraySize)->getSourceRange());
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 5161db6ac1a99..595b238a5fbcd 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2307,9 +2307,7 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM,
: ConstVal.getActiveBits();
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
Diag(ArraySize->getBeginLoc(), diag::err_array_too_large)
- << toString(ConstVal, 10, ConstVal.isSigned(),
- /*formatAsCLiteral=*/false, /*UpperCase=*/false,
- /*InsertSeparators=*/true)
+ << formatDiagnosticInteger(ConstVal, ConstVal.isSigned())
<< ArraySize->getSourceRange();
return QualType();
}
More information about the cfe-commits
mailing list