tbaeder updated this revision to Diff 526565.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D148614/new/

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
  clang/test/AST/Interp/depth-limit2.cpp

Index: clang/test/AST/Interp/depth-limit2.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/depth-limit2.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fconstexpr-depth 2 -verify %s
+// RUN: %clang_cc1 -fconstexpr-depth 2 -verify=ref %s
+
+
+constexpr int func() {
+  return 12;
+}
+
+constexpr int foo() {
+  return func(); // expected-note {{exceeded maximum depth of 2 calls}} \
+                 // ref-note {{exceeded maximum depth of 2 calls}}
+}
+
+constexpr int bar() {
+  return foo(); // expected-note {{in call to 'foo()'}} \
+                // ref-note {{in call to 'foo()'}}
+}
+
+static_assert(bar() == 12); // expected-error {{not an integral constant expression}} \
+                            // expected-note {{in call to 'bar()'}} \
+                            // ref-error {{not an integral constant expression}} \
+                            // ref-note {{in call to 'bar()'}}
+
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
+
+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 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)'}}
+}
+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) : 1;
+  }
   const Frame *getBottomFrame() const override {
     return Parent.getBottomFrame();
   }
@@ -105,8 +108,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
@@ -88,6 +88,10 @@
 /// Checks if a method can be called.
 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
 
+/// Checks if calling the currently active function would exceed
+/// the allowed call depth.
+bool CheckCallDepth(InterpState &S, CodePtr OpPC);
+
 /// Checks the 'this' pointer.
 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
 
@@ -169,7 +173,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");
@@ -192,8 +195,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();
@@ -1671,6 +1672,9 @@
   if (!CheckCallable(S, OpPC, Func))
     return false;
 
+  if (!CheckCallDepth(S, OpPC))
+    return false;
+
   auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
   InterpFrame *FrameBefore = S.Current;
   S.Current = NewFrame.get();
Index: clang/lib/AST/Interp/Interp.cpp
===================================================================
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -354,6 +354,17 @@
   return true;
 }
 
+bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
+  if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
+    S.FFDiag(S.Current->getSource(OpPC),
+             diag::note_constexpr_depth_limit_exceeded)
+        << S.getLangOpts().ConstexprCallDepth;
+    return false;
+  }
+
+  return true;
+}
+
 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
   if (!This.isZero())
     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