tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, tahonermann, erichkeane, shafik.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

There was already //some// form of this, but it wasn't working. I moved the 
depth tracking from `InterpState` to `InterpFrame` so remove some of the magic 
from the `Ret` instructions.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D148614

Files:
  clang/lib/AST/Interp/Interp.cpp
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/InterpFrame.cpp
  clang/lib/AST/Interp/InterpFrame.h
  clang/lib/AST/Interp/InterpState.cpp
  clang/lib/AST/Interp/InterpState.h
  clang/test/AST/Interp/depth-limit.cpp

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)'}}
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/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 <cstdint>
 #include <vector>
 
@@ -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 <typename T> 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<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
   if (!Func)
     return;
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -158,7 +158,6 @@
 template <PrimType Name, bool Builtin = false,
           class T = typename PrimConv<Name>::T>
 bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
-  S.CallStackDepth--;
   const T &Ret = S.Stk.pop<T>();
 
   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
@@ -181,8 +180,6 @@
 
 template <bool Builtin = false>
 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;
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to