[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