https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/176150
This only calls `noteStep()` on jump opcodes, so this works for loops. It does not prevent "hangs" when a function is just _very_ long (could be interesting how this interfaces with expand statements?). >From f5c9591995a7146205ef3bcd33ca3b2901d57d8d 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] [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 0205d840fd71e..cff8f6c83cd68 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}} + _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
