Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -158,7 +158,6 @@ template ::T> bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { - S.CallStackDepth--; const T &Ret = S.Stk.pop(); assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); @@ -181,8 +180,6 @@ template inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) { - S.CallStackDepth--; - assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); if (Builtin || !S.checkingPotentialConstantExpression()) S.Current->popArgs(); Index: clang/lib/AST/Interp/Interp.cpp =================================================================== --- clang/lib/AST/Interp/Interp.cpp +++ clang/lib/AST/Interp/Interp.cpp @@ -338,6 +338,14 @@ return false; } + // Check if calling the function would exceed our call depth limit. + if (S.Current->getDepth() > S.getLangOpts().ConstexprCallDepth) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_depth_limit_exceeded) + << S.getLangOpts().ConstexprCallDepth; + return false; + } + return true; } Index: clang/lib/AST/Interp/InterpFrame.h =================================================================== --- clang/lib/AST/Interp/InterpFrame.h +++ clang/lib/AST/Interp/InterpFrame.h @@ -15,7 +15,6 @@ #include "Frame.h" #include "Program.h" -#include "State.h" #include #include @@ -120,6 +119,8 @@ const Expr *getExpr(CodePtr PC) const; SourceLocation getLocation(CodePtr PC) const; + unsigned getDepth() const { return Depth; } + private: /// Returns an original argument from the stack. template const T &stackRef(unsigned Offset) const { @@ -145,6 +146,8 @@ private: /// Reference to the interpreter state. InterpState &S; + /// Depth of this frame. + unsigned Depth; /// Reference to the function being executed. const Function *Func; /// Current object pointer for methods. Index: clang/lib/AST/Interp/InterpFrame.cpp =================================================================== --- clang/lib/AST/Interp/InterpFrame.cpp +++ clang/lib/AST/Interp/InterpFrame.cpp @@ -23,8 +23,8 @@ InterpFrame::InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller, CodePtr RetPC) - : Caller(Caller), S(S), Func(Func), RetPC(RetPC), - ArgSize(Func ? Func->getArgSize() : 0), + : Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func), + RetPC(RetPC), ArgSize(Func ? Func->getArgSize() : 0), Args(static_cast(S.Stk.top())), FrameOffset(S.Stk.size()) { if (!Func) return; Index: clang/lib/AST/Interp/InterpState.h =================================================================== --- clang/lib/AST/Interp/InterpState.h +++ clang/lib/AST/Interp/InterpState.h @@ -15,6 +15,7 @@ #include "Context.h" #include "Function.h" +#include "InterpFrame.h" #include "InterpStack.h" #include "State.h" #include "clang/AST/APValue.h" @@ -41,7 +42,9 @@ // Stack frame accessors. Frame *getSplitFrame() { return Parent.getCurrentFrame(); } Frame *getCurrentFrame() override; - unsigned getCallStackDepth() override { return CallStackDepth; } + unsigned getCallStackDepth() override { + return Current ? Current->getDepth() : 1; + } const Frame *getBottomFrame() const override { return Parent.getBottomFrame(); } @@ -103,8 +106,6 @@ Context &Ctx; /// The current frame. InterpFrame *Current = nullptr; - /// Call stack depth. - unsigned CallStackDepth; }; } // namespace interp Index: clang/lib/AST/Interp/InterpState.cpp =================================================================== --- clang/lib/AST/Interp/InterpState.cpp +++ clang/lib/AST/Interp/InterpState.cpp @@ -17,8 +17,7 @@ InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx, SourceMapper *M) - : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr), - CallStackDepth(Parent.getCallStackDepth() + 1) {} + : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr) {} InterpState::~InterpState() { while (Current) { Index: clang/test/AST/Interp/depth-limit.cpp =================================================================== --- /dev/null +++ clang/test/AST/Interp/depth-limit.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fconstexpr-depth 100 -verify %s +// RUN: %clang_cc1 -fconstexpr-depth 100 -verify=ref %s + + +/// Note that the diagnostics are slightly different. + +constexpr int f(int a) { + 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(100)'}} \ + // 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 {{skipping 90 calls in backtrace}} \ + // expected-note {{in call to 'f(5)'}} \ + // 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)'}} +} +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)'}}