https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/212091

 1) Mention the limit in the "constexpr evaluation hit maximum step limit" 
diagnostic as well
 2) Move the "use -fconstexpr-steps" instruction to its own note so we can 
reuse it for two different diagnostics

For
`c++
struct S {
  constexpr S() {}
};
constexpr S foo[1'500'000] = {};
```
we used to emit
```console
array.cpp:1028:13: error: constexpr variable 'foo' must be initialized by a 
constant expression
 1028 | constexpr S foo[1'500'000] = {};
      |             ^                ~~
array.cpp:1026:17: note: constexpr evaluation hit maximum step limit; possible 
infinite loop?
 1026 |   constexpr S() {}
      |                 ^
array.cpp:1028:31: note: in call to 'S()'
 1028 | constexpr S foo[1'500'000] = {};
      |                               ^
```

and now we emit
```
array.cpp:1028:13: error: constexpr variable 'foo' must be initialized by a 
constant expression
 1028 | constexpr S foo[1'500'000] = {};
      |             ^                ~~
array.cpp:1026:17: note: constexpr evaluation hit maximum step limit of 
1048576; possible infinite loop?
 1026 |   constexpr S() {}
      |                 ^
array.cpp:1028:31: note: in call to 'S()'
 1028 | constexpr S foo[1'500'000] = {};
      |                               ^
array.cpp:1026:17: note: use -fconstexpr-steps= to increase this limit (=0 will 
remove the limit)
 1026 |   constexpr S() {}
```

>From 40fba4d3c0b109e29e60f494f211799fa31d81be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Sun, 26 Jul 2026 07:15:52 +0200
Subject: [PATCH] diags

---
 clang/include/clang/Basic/DiagnosticASTKinds.td   |  7 ++++---
 clang/lib/AST/ByteCode/InterpHelpers.h            |  3 ++-
 clang/lib/AST/ByteCode/InterpState.cpp            |  4 +++-
 clang/lib/AST/ByteCode/State.cpp                  |  6 ++++++
 clang/lib/AST/ByteCode/State.h                    |  1 +
 clang/lib/AST/ExprConstant.cpp                    | 10 +++++++---
 clang/test/AST/ByteCode/constexpr-steps.cpp       |  6 ++++--
 clang/test/AST/ByteCode/dynalloc-limits.cpp       |  6 ++++--
 .../SemaCXX/constexpr-function-recovery-crash.cpp | 15 ++++++++++-----
 .../SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp   |  9 ++++++---
 clang/test/SemaCXX/cxx2c-expansion-stmts.cpp      |  1 +
 11 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td 
b/clang/include/clang/Basic/DiagnosticASTKinds.td
index f86f0157b2b1f..c4582a3a9d641 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -170,7 +170,7 @@ def note_constexpr_depth_limit_exceeded : Note<
 def note_constexpr_call_limit_exceeded : Note<
   "constexpr evaluation hit maximum call limit">;
 def note_constexpr_step_limit_exceeded : Note<
-  "constexpr evaluation hit maximum step limit; possible infinite loop?">;
+  "constexpr evaluation hit maximum step limit of %0; possible infinite 
loop?">;
 def note_constexpr_heap_alloc_limit_exceeded : Note<
   "constexpr evaluation hit maximum heap allocation limit">;
 def note_constexpr_this : Note<
@@ -355,8 +355,9 @@ 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); "
-  "use '-fconstexpr-steps' to increase this limit">;
+  "cannot allocate array; evaluated array bound %0 exceeds the limit (%1)">;
+def note_constexpr_steps : Note<
+  "use -fconstexpr-steps= to increase this limit (=0 will remove the limit)">;
 def note_constexpr_new_too_small : Note<
   "cannot allocate array; evaluated array bound %0 is too small to hold "
   "%1 explicitly initialized elements">;
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h 
b/clang/lib/AST/ByteCode/InterpHelpers.h
index 4d908d1e44546..1df570ac971c4 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -94,8 +94,9 @@ 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)
+             diag::note_constexpr_new_exceeds_limits, 1)
         << NumElems << Limit;
+    S.Note(S.Current->getSource(OpPC), diag::note_constexpr_steps);
     return false;
   }
   return true;
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp 
b/clang/lib/AST/ByteCode/InterpState.cpp
index f6338cda56e34..6ac1b2610dd09 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -165,6 +165,8 @@ bool InterpState::noteStep(CodePtr OpPC) {
   if (StepsLeft != 0)
     return true;
 
-  FFDiag(Current->getSource(OpPC), diag::note_constexpr_step_limit_exceeded);
+  FFDiag(Current->getSource(OpPC), diag::note_constexpr_step_limit_exceeded, 1)
+      << getLangOpts().ConstexprStepLimit;
+  Note(Current->getSource(OpPC), diag::note_constexpr_steps);
   return false;
 }
diff --git a/clang/lib/AST/ByteCode/State.cpp b/clang/lib/AST/ByteCode/State.cpp
index e62b77272046c..38384bae23f57 100644
--- a/clang/lib/AST/ByteCode/State.cpp
+++ b/clang/lib/AST/ByteCode/State.cpp
@@ -69,6 +69,12 @@ OptionalDiagnostic State::Note(SourceLocation Loc, 
diag::kind DiagId) {
   return OptionalDiagnostic(&addDiag(Loc, DiagId));
 }
 
+OptionalDiagnostic State::Note(SourceInfo SI, diag::kind DiagId) {
+  if (!hasActiveDiagnostic())
+    return OptionalDiagnostic();
+  return OptionalDiagnostic(&addDiag(SI.getLoc(), DiagId));
+}
+
 void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
   if (hasActiveDiagnostic())
     llvm::append_range(*EvalStatus.Diag, Diags);
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index df3afdf8cbc24..df91132c48472 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -162,6 +162,7 @@ class State {
 
   /// Add a note to a prior diagnostic.
   OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId);
+  OptionalDiagnostic Note(SourceInfo Loc, diag::kind DiagId);
 
   /// Add a stack of notes to a prior diagnostic.
   void addNotes(ArrayRef<PartialDiagnosticAt> Diags);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 574dd8b04e779..3c715d80bb691 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -974,9 +974,11 @@ namespace {
       // of each element is likely to take some number of steps anyway.
       uint64_t Limit = getLangOpts().ConstexprStepLimit;
       if (Limit != 0 && ElemCount > Limit) {
-        if (Diag)
-          FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
+        if (Diag) {
+          FFDiag(Loc, diag::note_constexpr_new_exceeds_limits, 1)
               << ElemCount << Limit;
+          Note(Loc, diag::note_constexpr_steps);
+        }
         return false;
       }
       return true;
@@ -1003,7 +1005,9 @@ namespace {
         return true;
 
       if (!StepsLeft) {
-        FFDiag(S->getBeginLoc(), diag::note_constexpr_step_limit_exceeded);
+        FFDiag(S->getBeginLoc(), diag::note_constexpr_step_limit_exceeded, 1)
+            << getLangOpts().ConstexprStepLimit;
+        Note(S->getBeginLoc(), diag::note_constexpr_steps);
         return false;
       }
       --StepsLeft;
diff --git a/clang/test/AST/ByteCode/constexpr-steps.cpp 
b/clang/test/AST/ByteCode/constexpr-steps.cpp
index bd461547032a9..3ba6b1cb3adcd 100644
--- a/clang/test/AST/ByteCode/constexpr-steps.cpp
+++ b/clang/test/AST/ByteCode/constexpr-steps.cpp
@@ -2,14 +2,16 @@
 
 
 constexpr int foo() { // expected-error {{never produces a constant 
expression}}
-  while (1) {} // expected-note 2{{constexpr evaluation hit maximum step 
limit}}
+  while (1) {} // expected-note 2{{constexpr evaluation hit maximum step 
limit}} \
+               // expected-note 2{{use -fconstexpr-steps}}
   return 0;
 }
 static_assert (foo() == 0, ""); // expected-error {{not an integral constant 
expression}} \
                                 // expected-note {{in call to}}
 
 constexpr void addr() { // expected-error {{never produces a constant 
expression}}
-  for (;;) // expected-note 2{{constexpr evaluation hit maximum step limit}}
+  for (;;) // expected-note 2{{constexpr evaluation hit maximum step limit}} \
+           // expected-note 2{{use -fconstexpr-steps}}
     ;
 }
 static_assert((addr(), 1) == 1); // expected-error {{not an integral constant 
expression}} \
diff --git a/clang/test/AST/ByteCode/dynalloc-limits.cpp 
b/clang/test/AST/ByteCode/dynalloc-limits.cpp
index ed2d4faf974b1..85d66ac88ee2c 100644
--- a/clang/test/AST/ByteCode/dynalloc-limits.cpp
+++ b/clang/test/AST/ByteCode/dynalloc-limits.cpp
@@ -54,7 +54,8 @@ 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 1025 exceeds the limit (1024)}} \
+                                   // both-note@#alloc {{use 
-fconstexpr-steps}} \
                                    // both-note@#call {{in call to 
'this->alloc.allocate(1025)'}} \
                                    // both-note {{in call}}
 
@@ -62,7 +63,8 @@ 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 1025 exceeds the limit (1024)}} \
+                                         // both-note {{use -fconstexpr-steps}}
     return BIG[N-1];
 }
 
diff --git a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp 
b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
index de8fe057893d5..016bd188ac9f7 100644
--- a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -36,7 +36,8 @@ constexpr int test4() {
 
 constexpr int test5() { // expected-error {{constexpr function never produce}}
   for (;; a++); // expected-error {{use of undeclared identifier}}  \
-                   expected-note {{constexpr evaluation hit maximum step 
limit; possible infinite loop?}}
+                   expected-note {{constexpr evaluation hit maximum step limit 
of 1048576; possible infinite loop?}} \
+                   expected-note {{use -fconstexpr-steps}}
   return 1;
 }
 
@@ -44,7 +45,8 @@ constexpr int test6() { // expected-error {{constexpr 
function never produce}}
   int n = 0;
   switch (n) {
     for (;; a++) { // expected-error {{use of undeclared identifier}}
-    case 0:; // expected-note {{constexpr evaluation hit maximum step limit; 
possible infinite loop?}}
+    case 0:; // expected-note {{constexpr evaluation hit maximum step limit of 
1048576; possible infinite loop?}} \
+             // expected-note {{use -fconstexpr-steps}}
     }
   }
   return 0;
@@ -91,7 +93,8 @@ TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { 
default: break; });
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
                                 // FIXME: should bail out instead of looping.
                                 // expected-note@-2 + {{infinite loop}}
-                                // expected-note@-3 {{in call}}
+                                // expected-note@-3 + {{use -fconstexpr-steps}}
+                                // expected-note@-4 {{in call}}
 TEST_EVALUATE(ForRange, for (auto x : !!){}); // expected-error + {{}}
 TEST_EVALUATE(While, while (!!){});           // expected-error + {{}}
 TEST_EVALUATE(DoWhile, do {} while (!!););    // expected-error + {{}}
@@ -101,9 +104,11 @@ TEST_EVALUATE(If, if (!!){};);                // 
expected-error + {{}}
 TEST_EVALUATE(IfInit, if (auto x = !!; 1){};);// expected-error + {{}}
 TEST_EVALUATE(ForInit, for (!!;;){};);// expected-error + {{}}
                                       // expected-note@-1 + {{infinite loop}}
-                                      // expected-note@-2 {{in call}}
+                                      // expected-note@-2 + {{use 
-fconstexpr-steps}}
+                                      // expected-note@-3 {{in call}}
 TEST_EVALUATE(ForCond, for (; !!;){};);// expected-error + {{}}
 TEST_EVALUATE(ForInc, for (;; !!){};);// expected-error + {{}}
                                       // expected-note@-1 + {{infinite loop}}
-                                      // expected-note@-2 {{in call}}
+                                      // expected-note@-2 + {{use 
-fconstexpr-steps}}
+                                      // expected-note@-3 {{in call}}
 TEST_EVALUATE(ForCondUnDef, for (;some_cond;){};);        // expected-error + 
{{}}
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp 
b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
index 8bcb4d45d4af8..7537b47780aeb 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc-limits.cpp
@@ -58,14 +58,16 @@ constexpr std::size_t ssmall = S<std::size_t>(100)[42];
 
 // We can allocate this array but we hikt the number of steps
 constexpr std::size_t s4 = S<std::size_t>(1024)[42]; // expected-error 
{{constexpr variable 's4' must be initialized by a constant expression}} \
-                                   // expected-note@#construct {{constexpr 
evaluation hit maximum step limit; possible infinite loop?}} \
+                                   // expected-note@#construct {{constexpr 
evaluation hit maximum step limit of 1024; possible infinite loop?}} \
+                                   // expected-note@#construct {{use 
-fconstexpr-steps}} \
                                    // expected-note@#construct_call {{in 
call}} \
                                    // expected-note {{in call}}
 
 
 
 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 1025 exceeds the limit (1024)}} \
+                                   // expected-note@#alloc {{use 
-fconstexpr-steps}} \
                                    // expected-note@#call {{in call to 
'this->alloc.allocate(1025)'}} \
                                    // expected-note {{in call}}
 
@@ -75,7 +77,8 @@ 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 1025 exceeds the limit (1024)}} \
+                                         // expected-note 3{{use 
-fconstexpr-steps}}
     return BIG[N-1];
 }
 
diff --git a/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp 
b/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
index fb93cdf588f6c..dd450a8f1b76c 100644
--- a/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
+++ b/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
@@ -177,6 +177,7 @@ void negative_size() {
   static constexpr NegativeSize n;
   template for (auto x : n) g(x); // expected-error {{expansion statement size 
is not a constant expression}} \
                                      old-interp-note {{constexpr evaluation 
hit maximum step limit}} \
+                                     old-interp-note {{use -fconstexpr-steps}} 
\
                                      new-interp-note {{cannot refer to element 
5 of array of 4 elements in a constant expression}} \
                                      expected-note {{in call to}}
   template for (constexpr auto x : n) g(x); // expected-error {{expansion 
statement size is not a constant expression}} \

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to