[clang] [clang][bytecode] Move frame depth from `InterpFrame` to `InterpState` (PR #233249)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 18 08:42:49 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>

We never need to know the depth of a random frame, only of the current one. Save that information in `InterpState` instead.

---
Full diff: https://github.com/llvm/llvm-project/pull/233249.diff


7 Files Affected:

- (modified) clang/lib/AST/ByteCode/Disasm.cpp (+1-2) 
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+6-6) 
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+1-1) 
- (modified) clang/lib/AST/ByteCode/InterpFrame.cpp (+2-3) 
- (modified) clang/lib/AST/ByteCode/InterpFrame.h (-3) 
- (modified) clang/lib/AST/ByteCode/InterpState.h (+11-4) 
- (modified) clang/test/AST/ByteCode/depth-limit.cpp (+16-30) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index b57ace795fa77f..380c4ca326dcb7 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -541,7 +541,7 @@ LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
     if (getCallee())
       describe(OS);
     else
-      OS << "Frame (Depth: " << getDepth() << ")";
+      OS << "Frame";
     OS << "\n";
   }
   OS.indent(Spaces) << "Function: " << getFunction();
@@ -557,7 +557,6 @@ LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
     OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";
   else
     OS.indent(Spaces) << "RVO: -\n";
-  OS.indent(Spaces) << "Depth: " << Depth << "\n";
   OS.indent(Spaces) << "ArgSize: " << ArgSize << "\n";
   OS.indent(Spaces) << "Args: " << (void *)Args << "\n";
 #ifndef NDEBUG
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index c5cc90f5fdd7f1..4420ee675f2c47 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1242,7 +1242,7 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
 }
 
 static bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
-  if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
+  if ((S.FrameDepth + 1) > S.getLangOpts().ConstexprCallDepth) {
     S.FFDiag(S.Current->getSource(OpPC),
              diag::note_constexpr_depth_limit_exceeded)
         << S.getLangOpts().ConstexprCallDepth;
@@ -1949,7 +1949,7 @@ bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
 
 /// Opcode. Check if the function decl can be called at compile time.
 bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD) {
-  if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)
+  if (S.checkingPotentialConstantExpression() && !S.Current->isBottomFrame())
     return false;
 
   const FunctionDecl *Definition = nullptr;
@@ -2099,11 +2099,11 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
     return false;
 
   InterpFrame *NewFrame = S.allocFrame(Func, S.PC, VarArgSize);
-  S.Current = NewFrame;
+  S.enterFrame(NewFrame);
 
   InterpStateCCOverride CCOverride(S, Func->isImmediate());
   bool Success = Interpret(S);
-  S.resetCurrentFrame();
+  S.exitFrame();
   return Success;
 }
 
@@ -2184,7 +2184,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
     return cleanup();
 
   InterpFrame *NewFrame = S.allocFrame(Func, S.PC, VarArgSize);
-  S.Current = NewFrame;
+  S.enterFrame(NewFrame);
 
   InterpStateCCOverride CCOverride(S, Func->isImmediate());
   bool Success = Interpret(S);
@@ -2192,7 +2192,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
   if (InstancePtrTracked)
     S.InitializingPtrs.pop_back();
 
-  S.resetCurrentFrame();
+  S.exitFrame();
   return Success;
 }
 
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index d73ad308b0c0f0..86c66f708309d9 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -260,7 +260,7 @@ static bool convertDoubleToFloatStrict(const APFloat &Src, Floating &Dst,
 static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,
                                                   const InterpFrame *Frame,
                                                   const CallExpr *Call) {
-  unsigned Depth = S.Current->getDepth();
+  unsigned Depth = S.FrameDepth;
   auto isStdCall = [](const FunctionDecl *F) -> bool {
     return F && F->isInStdNamespace() && F->getIdentifier() &&
            F->getIdentifier()->isStr("is_constant_evaluated");
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp
index c04a70cc49f7c7..b5f621eee9b0ac 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -24,13 +24,12 @@ using namespace clang::interp;
 
 InterpFrame::InterpFrame(InterpState &S)
     : Caller(nullptr), S(S), Func(nullptr), RetPC(CodePtr()), Args(nullptr),
-      ArgSize(0), Depth(0) {}
+      ArgSize(0) {}
 
 InterpFrame::InterpFrame(InterpState &S, const Function *Func,
                          InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize)
     : Caller(Caller), S(S), Func(Func), RetPC(RetPC),
-      Args(static_cast<char *>(S.Stk.top())), ArgSize(ArgSize),
-      Depth(Caller ? Caller->Depth + 1 : 0) {
+      Args(static_cast<char *>(S.Stk.top())), ArgSize(ArgSize) {
   assert(Func);
 #ifndef NDEBUG
   FrameOffset = S.Stk.size();
diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h
index acc9c337bfb1b2..606ae145dc6885 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.h
+++ b/clang/lib/AST/ByteCode/InterpFrame.h
@@ -150,7 +150,6 @@ class InterpFrame final : public Frame {
   }
   SourceRange getRange(CodePtr PC) const { return getSource(PC).getRange(); }
 
-  unsigned getDepth() const { return Depth; }
   unsigned getArgSize() const { return ArgSize; }
 
   bool isStdFunction() const;
@@ -222,8 +221,6 @@ class InterpFrame final : public Frame {
 #endif
   /// The size of all the arguments.
   const unsigned ArgSize;
-  /// Depth of this frame.
-  unsigned Depth;
 
 public:
   unsigned MSVCConstexprAllowed = 0;
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index eb290584285db6..f423ea56024a9d 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -67,9 +67,7 @@ class InterpState final : public State {
 
   // Stack frame accessors.
   const Frame *getCurrentFrame() override;
-  unsigned getCallStackDepth() override {
-    return Current ? (Current->getDepth() + 1) : 1;
-  }
+  unsigned getCallStackDepth() override { return FrameDepth + 1; }
   bool stepsLeft() const override { return true; }
   bool inConstantContext() const;
 
@@ -212,15 +210,23 @@ class InterpState final : public State {
     return NewFrame;
   }
 
+  /// Set the given frame as the current one.
+  void enterFrame(InterpFrame *F) {
+    Current = F;
+    ++FrameDepth;
+  }
+
   /// Free resources associated with the current frame and set the caller to be
   /// the new current frame.
-  void resetCurrentFrame() {
+  void exitFrame() {
     assert(Current);
+    assert(FrameDepth > 0);
     unsigned CurrentSize = InterpFrame::allocSize(Current->getFunction());
     InterpFrame *Caller = Current->Caller;
     Current->~InterpFrame();
     FrameAlloc.pop(CurrentSize);
     Current = Caller;
+    --FrameDepth;
   }
 
 private:
@@ -262,6 +268,7 @@ class InterpState final : public State {
   const bool InfiniteSteps = false;
   /// ID identifying this evaluation.
   const unsigned EvalID;
+  unsigned FrameDepth = 0;
 
   unsigned StringID = 0;
 
diff --git a/clang/test/AST/ByteCode/depth-limit.cpp b/clang/test/AST/ByteCode/depth-limit.cpp
index 6c21e5e65f0e03..099576d0e7e413 100644
--- a/clang/test/AST/ByteCode/depth-limit.cpp
+++ b/clang/test/AST/ByteCode/depth-limit.cpp
@@ -1,35 +1,21 @@
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fconstexpr-depth=100 -verify %s
-// RUN: %clang_cc1 -fconstexpr-depth=100 -verify=ref %s
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fconstexpr-depth=100 -verify=expected,both %s
+// RUN: %clang_cc1                                         -fconstexpr-depth=100 -verify=ref,both      %s
 
 constexpr int f(int a) {
   if (a == 100)
-    return 1 / 0; // expected-warning {{division by zero is undefined}} \
-                  // ref-warning {{division by zero is undefined}}
+    return 1 / 0; // both-warning {{division by zero is undefined}}
 
-  return f(a + 1); // ref-note {{exceeded maximum depth of 100 calls}} \
-                   // ref-note {{in call to 'f(99)'}} \
-                   // ref-note {{in call to 'f(98)'}} \
-                   // ref-note {{in call to 'f(97)'}} \
-                   // ref-note {{in call to 'f(96)'}} \
-                   // ref-note {{in call to 'f(95)'}} \
-                   // ref-note {{skipping 90 calls in backtrace}} \
-                   // ref-note {{in call to 'f(4)'}} \
-                   // ref-note {{in call to 'f(3)'}} \
-                   // ref-note {{in call to 'f(2)'}} \
-                   // ref-note {{in call to 'f(1)'}} \
-                   // expected-note {{exceeded maximum depth of 100 calls}} \
-                   // expected-note {{in call to 'f(99)'}} \
-                   // expected-note {{in call to 'f(98)'}} \
-                   // expected-note {{in call to 'f(97)'}} \
-                   // expected-note {{in call to 'f(96)'}} \
-                   // expected-note {{in call to 'f(95)'}} \
-                   // expected-note {{skipping 90 calls in backtrace}} \
-                   // expected-note {{in call to 'f(4)'}} \
-                   // expected-note {{in call to 'f(3)'}} \
-                   // expected-note {{in call to 'f(2)'}} \
-                   // expected-note {{in call to 'f(1)'}}
+  return f(a + 1); // both-note {{exceeded maximum depth of 100 calls}} \
+                   // both-note {{in call to 'f(99)'}} \
+                   // both-note {{in call to 'f(98)'}} \
+                   // both-note {{in call to 'f(97)'}} \
+                   // both-note {{in call to 'f(96)'}} \
+                   // both-note {{in call to 'f(95)'}} \
+                   // both-note {{skipping 90 calls in backtrace}} \
+                   // both-note {{in call to 'f(4)'}} \
+                   // both-note {{in call to 'f(3)'}} \
+                   // both-note {{in call to 'f(2)'}} \
+                   // both-note {{in call to 'f(1)'}}
 }
-static_assert(f(0) == 100, ""); // ref-error {{not an integral constant expression}} \
-                                // ref-note {{in call to 'f(0)'}} \
-                                // expected-error {{not an integral constant expression}} \
-                                // expected-note {{in call to 'f(0)'}}
+static_assert(f(0) == 100, ""); // both-error {{not an integral constant expression}} \
+                                // both-note {{in call to 'f(0)'}}

``````````

</details>


https://github.com/llvm/llvm-project/pull/233249


More information about the cfe-commits mailing list