Author: Timm Baeder
Date: 2026-10-19T10:15:03+02:00
New Revision: dc47ad399a95be93e2214e5a44c21d00361d0c9b

URL: 
https://github.com/llvm/llvm-project/commit/dc47ad399a95be93e2214e5a44c21d00361d0c9b
DIFF: 
https://github.com/llvm/llvm-project/commit/dc47ad399a95be93e2214e5a44c21d00361d0c9b.diff

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

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

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Disasm.cpp
    clang/lib/AST/ByteCode/Interp.cpp
    clang/lib/AST/ByteCode/InterpBuiltin.cpp
    clang/lib/AST/ByteCode/InterpFrame.cpp
    clang/lib/AST/ByteCode/InterpFrame.h
    clang/lib/AST/ByteCode/InterpState.h
    clang/test/AST/ByteCode/depth-limit.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Disasm.cpp 
b/clang/lib/AST/ByteCode/Disasm.cpp
index b57ace795fa77..380c4ca326dcb 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 c5cc90f5fdd7f..4420ee675f2c4 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 d73ad308b0c0f..86c66f708309d 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 c04a70cc49f7c..b5f621eee9b0a 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 acc9c337bfb1b..606ae145dc688 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 eb290584285db..f423ea56024a9 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 6c21e5e65f0e0..099576d0e7e41 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)'}}


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

Reply via email to