Timm =?utf-8?q?Bäder?= <[email protected]>,
Timm =?utf-8?q?Bäder?= <[email protected]>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/[email protected]>


https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/176150

>From a20121c126bc9da652325c36c4f93cad8ef92674 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Thu, 15 Jan 2026 13:46:23 +0100
Subject: [PATCH 1/3] [clang][bytecode] Implement constexpr step limit

---
 clang/lib/AST/ByteCode/Interp.cpp           |  6 +++---
 clang/lib/AST/ByteCode/InterpState.cpp      | 11 +++++++++++
 clang/lib/AST/ByteCode/InterpState.h        |  5 +++++
 clang/test/AST/ByteCode/constexpr-steps.cpp | 10 ++++++++++
 4 files changed, 29 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/AST/ByteCode/constexpr-steps.cpp

diff --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 2a495a475c378..35890343a3f5c 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -38,21 +38,21 @@ static bool RetValue(InterpState &S, CodePtr &Pt) {
 
 static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
   PC += Offset;
-  return true;
+  return S.noteStep(PC);
 }
 
 static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
   if (S.Stk.pop<bool>()) {
     PC += Offset;
   }
-  return true;
+  return S.noteStep(PC);
 }
 
 static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
   if (!S.Stk.pop<bool>()) {
     PC += Offset;
   }
-  return true;
+  return S.noteStep(PC);
 }
 
 // https://github.com/llvm/llvm-project/issues/102513
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp 
b/clang/lib/AST/ByteCode/InterpState.cpp
index a95916cd63981..20207b9337e02 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -26,6 +26,7 @@ InterpState::InterpState(State &Parent, Program &P, 
InterpStack &Stk,
       Parent.CheckingPotentialConstantExpression;
   CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
   EvalMode = Parent.EvalMode;
+  StepsLeft = Ctx.getLangOpts().ConstexprStepLimit;
 }
 
 InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
@@ -38,6 +39,7 @@ InterpState::InterpState(State &Parent, Program &P, 
InterpStack &Stk,
       Parent.CheckingPotentialConstantExpression;
   CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
   EvalMode = Parent.EvalMode;
+  StepsLeft = Ctx.getLangOpts().ConstexprStepLimit;
 }
 
 bool InterpState::inConstantContext() const {
@@ -153,3 +155,12 @@ StdAllocatorCaller 
InterpState::getStdAllocatorCaller(StringRef Name) const {
 
   return {};
 }
+
+bool InterpState::noteStep(CodePtr OpPC) {
+  --StepsLeft;
+  if (StepsLeft != 0)
+    return true;
+
+  FFDiag(Current->getSource(OpPC), diag::note_constexpr_step_limit_exceeded);
+  return false;
+}
diff --git a/clang/lib/AST/ByteCode/InterpState.h 
b/clang/lib/AST/ByteCode/InterpState.h
index e2e4d5c985f93..197ea2b138e05 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -153,6 +153,10 @@ class InterpState final : public State, public 
SourceMapper {
     return Floating(Mem, llvm::APFloatBase::SemanticsToEnum(Sem));
   }
 
+  /// Note that a step has been executed. If there are no more steps remaining,
+  /// diagnoses and returns \c false.
+  bool noteStep(CodePtr OpPC);
+
 private:
   friend class EvaluationResult;
   friend class InterpStateCCOverride;
@@ -184,6 +188,7 @@ class InterpState final : public State, public SourceMapper 
{
   SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr;
   unsigned SpeculationDepth = 0;
   std::optional<bool> ConstantContextOverride;
+  unsigned StepsLeft;
 
   llvm::SmallVector<
       std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
diff --git a/clang/test/AST/ByteCode/constexpr-steps.cpp 
b/clang/test/AST/ByteCode/constexpr-steps.cpp
new file mode 100644
index 0000000000000..490425107a140
--- /dev/null
+++ b/clang/test/AST/ByteCode/constexpr-steps.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s 
-fconstexpr-steps=100
+
+
+constexpr int foo() { // expected-error {{never produces a constant 
expression}}
+  while (1) {} // expected-note 2{{constexpr evaluation hit maximum step 
limit}}
+  return 0;
+}
+static_assert (foo() == 0, ""); // expected-error {{not an integral constant 
expression}} \
+                                // expected-note {{in call to}}
+

>From 4a82fc01465ed04af340a1ee16b9d22cad84f94e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Tue, 27 Jan 2026 06:59:15 +0100
Subject: [PATCH 2/3] Add InfiniteSteps flag

---
 clang/lib/AST/ByteCode/InterpState.cpp | 5 +++++
 clang/lib/AST/ByteCode/InterpState.h   | 7 ++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ByteCode/InterpState.cpp 
b/clang/lib/AST/ByteCode/InterpState.cpp
index 20207b9337e02..0d6b8cbfe0841 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -27,6 +27,7 @@ InterpState::InterpState(State &Parent, Program &P, 
InterpStack &Stk,
   CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
   EvalMode = Parent.EvalMode;
   StepsLeft = Ctx.getLangOpts().ConstexprStepLimit;
+  InfiniteSteps = StepsLeft == 0;
 }
 
 InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
@@ -40,6 +41,7 @@ InterpState::InterpState(State &Parent, Program &P, 
InterpStack &Stk,
   CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
   EvalMode = Parent.EvalMode;
   StepsLeft = Ctx.getLangOpts().ConstexprStepLimit;
+  InfiniteSteps = StepsLeft == 0;
 }
 
 bool InterpState::inConstantContext() const {
@@ -157,6 +159,9 @@ StdAllocatorCaller 
InterpState::getStdAllocatorCaller(StringRef Name) const {
 }
 
 bool InterpState::noteStep(CodePtr OpPC) {
+  if (InfiniteSteps)
+    return true;
+
   --StepsLeft;
   if (StepsLeft != 0)
     return true;
diff --git a/clang/lib/AST/ByteCode/InterpState.h 
b/clang/lib/AST/ByteCode/InterpState.h
index 197ea2b138e05..df9551d23a04e 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -184,11 +184,16 @@ class InterpState final : public State, public 
SourceMapper {
   SourceLocation EvalLocation;
   /// Declaration we're initializing/evaluting, if any.
   const VarDecl *EvaluatingDecl = nullptr;
+  /// Steps left during evaluation.
+  unsigned StepsLeft = 0;
+  /// Whether infinite evaluation steps have been requested. If this is false,
+  /// we use the StepsLeft value above.
+  bool InfiniteSteps = false;
+
   /// Things needed to do speculative execution.
   SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr;
   unsigned SpeculationDepth = 0;
   std::optional<bool> ConstantContextOverride;
-  unsigned StepsLeft;
 
   llvm::SmallVector<
       std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>

>From bb2983e9cc265407406f41d85a653d3b62470dbb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Tue, 27 Jan 2026 07:53:29 +0100
Subject: [PATCH 3/3] Make InfiniteSteps const

So it must be initialized in the constructors
---
 clang/lib/AST/ByteCode/InterpState.cpp | 10 ++++------
 clang/lib/AST/ByteCode/InterpState.h   |  2 +-
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpState.cpp 
b/clang/lib/AST/ByteCode/InterpState.cpp
index 0d6b8cbfe0841..dec91af17df75 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -20,28 +20,26 @@ using namespace clang::interp;
 InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, SourceMapper *M)
     : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
-      Current(&BottomFrame) {
+      Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
+      InfiniteSteps(StepsLeft == 0) {
   InConstantContext = Parent.InConstantContext;
   CheckingPotentialConstantExpression =
       Parent.CheckingPotentialConstantExpression;
   CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
   EvalMode = Parent.EvalMode;
-  StepsLeft = Ctx.getLangOpts().ConstexprStepLimit;
-  InfiniteSteps = StepsLeft == 0;
 }
 
 InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, const Function *Func)
     : Parent(Parent), M(nullptr), P(P), Stk(Stk), Ctx(Ctx),
       BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
-      Current(&BottomFrame) {
+      Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
+      InfiniteSteps(StepsLeft == 0) {
   InConstantContext = Parent.InConstantContext;
   CheckingPotentialConstantExpression =
       Parent.CheckingPotentialConstantExpression;
   CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
   EvalMode = Parent.EvalMode;
-  StepsLeft = Ctx.getLangOpts().ConstexprStepLimit;
-  InfiniteSteps = StepsLeft == 0;
 }
 
 bool InterpState::inConstantContext() const {
diff --git a/clang/lib/AST/ByteCode/InterpState.h 
b/clang/lib/AST/ByteCode/InterpState.h
index df9551d23a04e..1bbbfabd37186 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -188,7 +188,7 @@ class InterpState final : public State, public SourceMapper 
{
   unsigned StepsLeft = 0;
   /// Whether infinite evaluation steps have been requested. If this is false,
   /// we use the StepsLeft value above.
-  bool InfiniteSteps = false;
+  const bool InfiniteSteps = false;
 
   /// Things needed to do speculative execution.
   SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr;

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

Reply via email to