r224320 - Improve handling of value dependent expressions in __attribute__((enable_if)), both in the condition expression and at the call site. Fixes PR20988!

Nick Lewycky nicholas at mxc.ca
Mon Dec 15 22:12:02 PST 2014


Author: nicholas
Date: Tue Dec 16 00:12:01 2014
New Revision: 224320

URL: http://llvm.org/viewvc/llvm-project?rev=224320&view=rev
Log:
Improve handling of value dependent expressions in __attribute__((enable_if)), both in the condition expression and at the call site. Fixes PR20988!

Modified:
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/enable_if.cpp

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=224320&r1=224319&r2=224320&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Dec 16 00:12:01 2014
@@ -9088,7 +9088,8 @@ bool Expr::EvaluateWithSubstitution(APVa
   ArgVector ArgValues(Args.size());
   for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
        I != E; ++I) {
-    if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
+    if ((*I)->isValueDependent() ||
+        !Evaluate(ArgValues[I - Args.begin()], Info, *I))
       // If evaluation fails, throw away the argument entirely.
       ArgValues[I - Args.begin()] = APValue();
     if (Info.EvalStatus.HasSideEffects)

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=224320&r1=224319&r2=224320&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Dec 16 00:12:01 2014
@@ -5792,6 +5792,7 @@ EnableIfAttr *Sema::CheckEnableIf(Functi
   // Convert the arguments.
   SmallVector<Expr *, 16> ConvertedArgs;
   bool InitializationFailed = false;
+  bool ContainsValueDependentExpr = false;
   for (unsigned i = 0, e = Args.size(); i != e; ++i) {
     if (i == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) &&
         !cast<CXXMethodDecl>(Function)->isStatic() &&
@@ -5804,6 +5805,7 @@ EnableIfAttr *Sema::CheckEnableIf(Functi
         InitializationFailed = true;
         break;
       }
+      ContainsValueDependentExpr |= R.get()->isValueDependent();
       ConvertedArgs.push_back(R.get());
     } else {
       ExprResult R =
@@ -5816,6 +5818,7 @@ EnableIfAttr *Sema::CheckEnableIf(Functi
         InitializationFailed = true;
         break;
       }
+      ContainsValueDependentExpr |= R.get()->isValueDependent();
       ConvertedArgs.push_back(R.get());
     }
   }
@@ -5826,9 +5829,16 @@ EnableIfAttr *Sema::CheckEnableIf(Functi
   for (AttrVec::iterator I = Attrs.begin(); I != E; ++I) {
     APValue Result;
     EnableIfAttr *EIA = cast<EnableIfAttr>(*I);
+    if (EIA->getCond()->isValueDependent()) {
+      // Don't even try now, we'll examine it after instantiation.
+      continue;
+    }
+
     if (!EIA->getCond()->EvaluateWithSubstitution(
-            Result, Context, Function, llvm::makeArrayRef(ConvertedArgs)) ||
-        !Result.isInt() || !Result.getInt().getBoolValue()) {
+            Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) {
+      if (!ContainsValueDependentExpr)
+        return EIA;
+    } else if (!Result.isInt() || !Result.getInt().getBoolValue()) {
       return EIA;
     }
   }

Modified: cfe/trunk/test/SemaCXX/enable_if.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enable_if.cpp?rev=224320&r1=224319&r2=224320&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/enable_if.cpp (original)
+++ cfe/trunk/test/SemaCXX/enable_if.cpp Tue Dec 16 00:12:01 2014
@@ -77,3 +77,44 @@ void test() {
   typedep(1);
   typedep(n);  // expected-note{{in instantiation of function template specialization 'typedep<Nothing>' requested here}}
 }
+
+template <typename T> class C {
+  void f() __attribute__((enable_if(T::expr == 0, ""))) {}
+  void g() { f(); }
+};
+
+int fn3(bool b) __attribute__((enable_if(b, "")));
+template <class T> void test3() {
+  fn3(sizeof(T) == 1);
+}
+
+// FIXME: issue an error (without instantiation) because ::h(T()) is not
+// convertible to bool, because return types aren't overloadable.
+void h(int);
+template <typename T> void outer() {
+  void local_function() __attribute__((enable_if(::h(T()), "")));
+  local_function();
+};
+
+namespace PR20988 {
+  struct Integer {
+    Integer(int);
+  };
+
+  int fn1(const Integer &) __attribute__((enable_if(true, "")));
+  template <class T> void test1() {
+    int &expr = T::expr();
+    fn1(expr);
+  }
+
+  int fn2(const Integer &) __attribute__((enable_if(false, "")));  // expected-note{{candidate disabled}}
+  template <class T> void test2() {
+    int &expr = T::expr();
+    fn2(expr);  // expected-error{{no matching function for call to 'fn2'}}
+  }
+
+  int fn3(bool b) __attribute__((enable_if(b, "")));
+  template <class T> void test3() {
+    fn3(sizeof(T) == 1);
+  }
+}





More information about the cfe-commits mailing list