]> granicus.if.org Git - clang/commitdiff
Improve handling of value dependent expressions in __attribute__((enable_if)), both...
authorNick Lewycky <nicholas@mxc.ca>
Tue, 16 Dec 2014 06:12:01 +0000 (06:12 +0000)
committerNick Lewycky <nicholas@mxc.ca>
Tue, 16 Dec 2014 06:12:01 +0000 (06:12 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@224320 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprConstant.cpp
lib/Sema/SemaOverload.cpp
test/SemaCXX/enable_if.cpp

index ad36e76bea4586995e278397e3b7e766f73878e9..59b8e988bf46672af841de7dcef16eeedffe6db8 100644 (file)
@@ -9088,7 +9088,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
   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)
index 9058fc098d8b65a99718718a8ca9f7d7fb3777fb..8341c008e82a6df0d515ed28dcc63edeb35092e8 100644 (file)
@@ -5792,6 +5792,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
   // 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(FunctionDecl *Function, ArrayRef<Expr *> Args,
         InitializationFailed = true;
         break;
       }
+      ContainsValueDependentExpr |= R.get()->isValueDependent();
       ConvertedArgs.push_back(R.get());
     } else {
       ExprResult R =
@@ -5816,6 +5818,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
         InitializationFailed = true;
         break;
       }
+      ContainsValueDependentExpr |= R.get()->isValueDependent();
       ConvertedArgs.push_back(R.get());
     }
   }
@@ -5826,9 +5829,16 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
   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;
     }
   }
index e9dc24254f209b58b2e93d4d8c577780da846b32..99545e09820e12721d9620a53e95efd008558e8a 100644 (file)
@@ -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);
+  }
+}