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
