diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index ad36e76bea45..59b8e988bf46 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9088,7 +9088,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, ArgVector ArgValues(Args.size()); for (ArrayRef::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) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 9058fc098d8b..8341c008e82a 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5792,6 +5792,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef Args, // Convert the arguments. SmallVector ConvertedArgs; bool InitializationFailed = false; + bool ContainsValueDependentExpr = false; for (unsigned i = 0, e = Args.size(); i != e; ++i) { if (i == 0 && !MissingImplicitThis && isa(Function) && !cast(Function)->isStatic() && @@ -5804,6 +5805,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef 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 Args, InitializationFailed = true; break; } + ContainsValueDependentExpr |= R.get()->isValueDependent(); ConvertedArgs.push_back(R.get()); } } @@ -5826,9 +5829,16 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef Args, for (AttrVec::iterator I = Attrs.begin(); I != E; ++I) { APValue Result; EnableIfAttr *EIA = cast(*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; } } diff --git a/clang/test/SemaCXX/enable_if.cpp b/clang/test/SemaCXX/enable_if.cpp index e9dc24254f20..99545e09820e 100644 --- a/clang/test/SemaCXX/enable_if.cpp +++ b/clang/test/SemaCXX/enable_if.cpp @@ -77,3 +77,44 @@ void test() { typedep(1); typedep(n); // expected-note{{in instantiation of function template specialization 'typedep' requested here}} } + +template class C { + void f() __attribute__((enable_if(T::expr == 0, ""))) {} + void g() { f(); } +}; + +int fn3(bool b) __attribute__((enable_if(b, ""))); +template 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 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 void test1() { + int &expr = T::expr(); + fn1(expr); + } + + int fn2(const Integer &) __attribute__((enable_if(false, ""))); // expected-note{{candidate disabled}} + template 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 void test3() { + fn3(sizeof(T) == 1); + } +}