faisalv created this revision.
faisalv added reviewers: rsmith, hans.
faisalv added a subscriber: cfe-commits.
faisalv set the repository for this revision to rL LLVM.

Fix the following Bug:
https://llvm.org/bugs/show_bug.cgi?id=28366

This patch teaches the constant expression evaluator to search the frame stack 
for a local variable (instead of assuming a local variable is on the current 
frame).  

This has the following benefits:
  - if the local variable from an enclosing scope was an error during 
parsing/instantiation - it remains an error (instead of a compiler crash) 
during constant expression evaluation
  - a local variable that is a constant expression from an enclosing scope is 
now evaluatable

Additionally, fix SemaTemplateInstantiateDecl so that when it instantiates the 
enable_if attribute it uses the instantiated declaration (instead of the 
template) when evaluating the condition (so that the instantiated param's decl 
context is correctly found).  This was done to fix the following regression:

template <typename T> T templatedBar(T m) __attribute__((enable_if(m > 0, ""))) 
{ return T(); }


  
 

Repository:
  rL LLVM

https://reviews.llvm.org/D23493

Files:
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/constant-expression-cxx11.cpp

Index: test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- test/SemaCXX/constant-expression-cxx11.cpp
+++ test/SemaCXX/constant-expression-cxx11.cpp
@@ -2066,3 +2066,33 @@
   constexpr Z z(1);
   static_assert(z.w == 1 && z.x == 2 && z.y == 3 && z.z == 4, "");
 }
+
+
+namespace PR28366 {
+namespace ns1 {
+
+void f(char c) { //expected-note2{{declared here}}
+  struct X {
+    static constexpr char f() { //expected-error{{never produces a constant 
expression}}
+      return c; //expected-error{{reference to local}} 
expected-note{{non-const variable}}
+    }
+  };
+  int I = X::f();
+}
+
+void g() {
+  const int c = 'c';
+  static const int d = 'd';
+  struct X {
+    static constexpr int f() {
+      return c + d;
+    }
+  };
+  constexpr int CD = X::f();
+}
+
+
+} // end ns1
+
+} //end ns PR28366
+
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -187,7 +187,7 @@
 
   SmallVector<PartialDiagnosticAt, 8> Diags;
   if (A->getCond()->isValueDependent() && !Cond->isValueDependent() &&
-      !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(Tmpl),
+      !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(New),
                                                 Diags)) {
     S.Diag(A->getLocation(), diag::err_enable_if_never_constant_expr);
     for (int I = 0, N = Diags.size(); I != N; ++I)
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -4788,10 +4788,24 @@
   return Error(E);
 }
 
+CallStackFrame *getNearestContainingCallFrame(CallStackFrame *CurFrame,
+                                              const VarDecl *VD) {
+  if (auto *FD =
+            dyn_cast<FunctionDecl>(VD->getDeclContext()->getRedeclContext())) {
+    FD = FD->getFirstDecl();
+    for (CallStackFrame *It = CurFrame; It; It = It->Caller) {
+      if (It->Callee && FD == It->Callee->getFirstDecl())
+        return It;
+    }
+  }
+  return nullptr;
+}
+
 bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
   CallStackFrame *Frame = nullptr;
-  if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1)
-    Frame = Info.CurrentCall;
+  if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) {
+    Frame = getNearestContainingCallFrame(Info.CurrentCall, VD);
+  }
 
   if (!VD->getType()->isReferenceType()) {
     if (Frame) {


Index: test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- test/SemaCXX/constant-expression-cxx11.cpp
+++ test/SemaCXX/constant-expression-cxx11.cpp
@@ -2066,3 +2066,33 @@
   constexpr Z z(1);
   static_assert(z.w == 1 && z.x == 2 && z.y == 3 && z.z == 4, "");
 }
+
+
+namespace PR28366 {
+namespace ns1 {
+
+void f(char c) { //expected-note2{{declared here}}
+  struct X {
+    static constexpr char f() { //expected-error{{never produces a constant expression}}
+      return c; //expected-error{{reference to local}} expected-note{{non-const variable}}
+    }
+  };
+  int I = X::f();
+}
+
+void g() {
+  const int c = 'c';
+  static const int d = 'd';
+  struct X {
+    static constexpr int f() {
+      return c + d;
+    }
+  };
+  constexpr int CD = X::f();
+}
+
+
+} // end ns1
+
+} //end ns PR28366
+
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -187,7 +187,7 @@
 
   SmallVector<PartialDiagnosticAt, 8> Diags;
   if (A->getCond()->isValueDependent() && !Cond->isValueDependent() &&
-      !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(Tmpl),
+      !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(New),
                                                 Diags)) {
     S.Diag(A->getLocation(), diag::err_enable_if_never_constant_expr);
     for (int I = 0, N = Diags.size(); I != N; ++I)
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -4788,10 +4788,24 @@
   return Error(E);
 }
 
+CallStackFrame *getNearestContainingCallFrame(CallStackFrame *CurFrame,
+                                              const VarDecl *VD) {
+  if (auto *FD =
+            dyn_cast<FunctionDecl>(VD->getDeclContext()->getRedeclContext())) {
+    FD = FD->getFirstDecl();
+    for (CallStackFrame *It = CurFrame; It; It = It->Caller) {
+      if (It->Callee && FD == It->Callee->getFirstDecl())
+        return It;
+    }
+  }
+  return nullptr;
+}
+
 bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
   CallStackFrame *Frame = nullptr;
-  if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1)
-    Frame = Info.CurrentCall;
+  if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) {
+    Frame = getNearestContainingCallFrame(Info.CurrentCall, VD);
+  }
 
   if (!VD->getType()->isReferenceType()) {
     if (Frame) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to