Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2482,8 +2482,13 @@ /// Check the enable_if expressions on the given function. Returns the first /// failing attribute, or NULL if they were all successful. + /// + /// If `Dependent` is non-NULL, this function will set it to true if the + /// attribute it's handing back couldn't be evaluated properly due to a + /// value-dependent expression. EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef Args, - bool MissingImplicitThis = false); + bool MissingImplicitThis = false, + bool *Dependent = nullptr); /// Returns whether the given function's address can be taken or not, /// optionally emitting a diagnostic if the address can't be taken. Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -5089,8 +5089,6 @@ // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. - // FIXME: Will need to cache the results of name lookup (including ADL) in - // Fn. bool Dependent = false; if (Fn->isTypeDependent()) Dependent = true; @@ -5177,6 +5175,7 @@ } else if (isa(NakedFn)) NDecl = cast(NakedFn)->getMemberDecl(); + bool MakeCallInstantiationDependent = false; if (FunctionDecl *FD = dyn_cast_or_null(NDecl)) { if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, @@ -5191,21 +5190,35 @@ // already emitted an error about the bad call. if (FD->hasAttr() && isNumberOfArgsValidForCall(*this, FD, ArgExprs.size())) { - if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) { - Diag(Fn->getLocStart(), - isa(FD) ? - diag::err_ovl_no_viable_member_function_in_call : - diag::err_ovl_no_viable_function_in_call) - << FD << FD->getSourceRange(); - Diag(FD->getLocation(), - diag::note_ovl_candidate_disabled_by_enable_if_attr) - << Attr->getCond()->getSourceRange() << Attr->getMessage(); + bool DependentExpr; + if (const EnableIfAttr *Attr = + CheckEnableIf(FD, ArgExprs, true, &DependentExpr)) { + if (DependentExpr) { + // We can build this as usual, but we need to check the enable_if + // condition when we have all of the necessary values, so we need to + // ensure the resultant function is properly marked as instantiation + // dependent. + MakeCallInstantiationDependent = true; + } else { + Diag(Fn->getLocStart(), + isa(FD) ? + diag::err_ovl_no_viable_member_function_in_call : + diag::err_ovl_no_viable_function_in_call) + << FD << FD->getSourceRange(); + Diag(FD->getLocation(), + diag::note_ovl_candidate_disabled_by_enable_if_attr) + << Attr->getCond()->getSourceRange() << Attr->getMessage(); + } } } } - return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc, - ExecConfig, IsExecConfig); + ExprResult BuiltCall = BuildResolvedCallExpr( + Fn, NDecl, LParenLoc, ArgExprs, RParenLoc, ExecConfig, IsExecConfig); + + if (MakeCallInstantiationDependent) + BuiltCall.get()->setInstantiationDependent(true); + return BuiltCall; } /// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments. Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -5691,6 +5691,33 @@ return false; } +namespace { +/// In overload resolution, we need to know if any enable_if candidates couldn't +/// be evaluated due to value-dependent values. So, we pack that into the +/// FailedAttr pointer, rather than recomputing it. +struct EnableIfFailureResults { + EnableIfAttr *FailedAttr; + bool ValueDependent; +}; +} + +static EnableIfFailureResults unpackEnableIfFailure(void *Opaque) { + llvm::PointerIntPair Pair; + Pair.setFromOpaqueValue(Opaque); + return {Pair.getPointer(), bool(Pair.getInt())}; +} + +static void *packedCheckEnableIf(Sema &S, FunctionDecl *Fn, + ArrayRef Args, + bool MissingImplicitThis = false) { + bool ValDep = false; + EnableIfAttr *EIA = S.CheckEnableIf(Fn, Args, MissingImplicitThis, &ValDep); + // ValDep is meaningless if we didn't fail. + if (!EIA) + return nullptr; + return llvm::PointerIntPair(EIA, ValDep).getOpaqueValue(); +} + /// AddOverloadCandidate - Adds the given function to the set of /// candidate functions, using the given function call arguments. If /// @p SuppressUserConversions, then don't allow user-defined @@ -5848,10 +5875,10 @@ } } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) { + if (void *Failed = packedCheckEnableIf(*this, Function, Args)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; - Candidate.DeductionFailure.Data = FailedAttr; + Candidate.DeductionFailure.Data = Failed; return; } } @@ -5962,7 +5989,10 @@ } EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef Args, - bool MissingImplicitThis) { + bool MissingImplicitThis, bool *Dependent) { + if (Dependent) + *Dependent = false; + auto EnableIfAttrs = getOrderedEnableIfAttrs(Function); if (EnableIfAttrs.empty()) return nullptr; @@ -5992,6 +6022,8 @@ break; } + // Some args may be ignored by enable_if conditions, so we shouldn't + // immediately fail when we see a value-dependent argument. ContainsValueDependentExpr |= R.get()->isValueDependent(); ConvertedArgs.push_back(R.get()); } @@ -6024,17 +6056,24 @@ for (auto *EIA : EnableIfAttrs) { APValue Result; if (EIA->getCond()->isValueDependent()) { - // Don't even try now, we'll examine it after instantiation. - continue; + if (Dependent) + *Dependent = true; + return EIA; } if (!EIA->getCond()->EvaluateWithSubstitution( Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) { - if (!ContainsValueDependentExpr) - return EIA; - } else if (!Result.isInt() || !Result.getInt().getBoolValue()) { + // Dependent is a best effort check that notes that we *may* have failed + // due to a value dependent expression. There's no cheap way to figure out + // if this is true, so set it in all cases where it may apply. If we're + // wrong, we'll find that out after instantiation. + if (Dependent) + *Dependent = ContainsValueDependentExpr; return EIA; } + + if (!Result.isInt() || !Result.getInt().getBoolValue()) + return EIA; } return nullptr; } @@ -6231,10 +6270,10 @@ } } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Method, Args, true)) { + if (void *Failed = packedCheckEnableIf(*this, Method, Args, true)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; - Candidate.DeductionFailure.Data = FailedAttr; + Candidate.DeductionFailure.Data = Failed; return; } } @@ -6540,10 +6579,10 @@ "Can only end up with a standard conversion sequence or failure"); } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) { + if (void *Failed = packedCheckEnableIf(*this, Conversion, None)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; - Candidate.DeductionFailure.Data = FailedAttr; + Candidate.DeductionFailure.Data = Failed; return; } } @@ -6692,10 +6731,10 @@ } } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) { + if (void *Failed = packedCheckEnableIf(*this, Conversion, None)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; - Candidate.DeductionFailure.Data = FailedAttr; + Candidate.DeductionFailure.Data = Failed; return; } } @@ -9616,7 +9655,8 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) { FunctionDecl *Callee = Cand->Function; - EnableIfAttr *Attr = static_cast(Cand->DeductionFailure.Data); + void *PackedFailure = Cand->DeductionFailure.Data; + EnableIfAttr *Attr = unpackEnableIfFailure(PackedFailure).FailedAttr; S.Diag(Callee->getLocation(), diag::note_ovl_candidate_disabled_by_enable_if_attr) @@ -11382,8 +11422,32 @@ &result)) return result; + // If we had any enable_if attributes fail because they were value dependent, + // then we can't accurately resolve the overload now. Defer it until later. + if (getLangOpts().CPlusPlus) + for (auto I = CandidateSet.begin(), E = CandidateSet.end(); I != E; ++I) + if (!I->Viable && I->FailureKind == ovl_fail_enable_if && + unpackEnableIfFailure(I->DeductionFailure.Data).ValueDependent) { + // The overload we select may change depending on the value the failing + // enable_if is dependent upon. So, the type of the function we're + // using is both type dependent and value dependent. + CallExpr *CE; + if (ExecConfig) + CE = new (Context) + CUDAKernelCallExpr(Context, Fn, cast(ExecConfig), Args, + Context.DependentTy, VK_RValue, RParenLoc); + else + CE = new (Context) CallExpr(Context, Fn, Args, Context.DependentTy, + VK_RValue, RParenLoc); + + CE->setInstantiationDependent(true); + CE->setValueDependent(true); + CE->setTypeDependent(true); + return CE; + } + // If the user handed us something like `(&Foo)(Bar)`, we need to ensure that - // functions that aren't addressible are considered unviable. + // functions that aren't addressable are considered unviable. if (CalleesAddressIsTaken) markUnaddressableCandidatesUnviable(*this, CandidateSet); Index: test/SemaCXX/enable_if.cpp =================================================================== --- test/SemaCXX/enable_if.cpp +++ test/SemaCXX/enable_if.cpp @@ -133,13 +133,18 @@ int t1 = y.h(1, 2); // expected-error{{no matching member function for call to 'h'}} } -// FIXME: issue an error (without instantiation) because ::h(T()) is not -// convertible to bool, because return types aren't overloadable. +void ovlH(int); +int ovlH(double); void h(int); -template void outer() { - void local_function() __attribute__((enable_if(::h(T()), ""))); +template int outer() { + void local_function() __attribute__((enable_if(::h(T()), ""))); // expected-error{{value of type 'void' is not contextually convertible to 'bool'}} + void local_function2() __attribute__((enable_if(::ovlH(T()), ""))); // expected-error{{value of type 'void' is not contextually convertible to 'bool'}} local_function(); -}; + local_function2(); + return 0; +} + +int runOuter = outer(); // expected-note{{in instantiation of function template specialization 'outer'}} namespace PR20988 { struct Integer { @@ -191,11 +196,11 @@ int ovlConflict(int m) __attribute__((enable_if(true, ""))); int ovlConflict(int m) __attribute__((enable_if(1, ""))); void test3() { - int (*p)(int) = ovlConflict; // expected-error{{address of overloaded function 'ovlConflict' is ambiguous}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} - int (*p2)(int) = &ovlConflict; // expected-error{{address of overloaded function 'ovlConflict' is ambiguous}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} + int (*p)(int) = ovlConflict; // expected-error{{address of overloaded function 'ovlConflict' is ambiguous}} expected-note@196{{candidate function}} expected-note@197{{candidate function}} + int (*p2)(int) = &ovlConflict; // expected-error{{address of overloaded function 'ovlConflict' is ambiguous}} expected-note@196{{candidate function}} expected-note@197{{candidate function}} int (*a)(int); - a = ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} - a = &ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} + a = ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@196{{candidate function}} expected-note@197{{candidate function}} + a = &ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@196{{candidate function}} expected-note@197{{candidate function}} } template @@ -213,11 +218,11 @@ template T templatedBar(T m) __attribute__((enable_if(m > 0, ""))) { return T(); } void test5() { - int (*p)(int) = templatedBar; // expected-error{{address of overloaded function 'templatedBar' does not match required type 'int (int)'}} expected-note@214{{candidate function made ineligible by enable_if}} - int (*p2)(int) = &templatedBar; // expected-error{{address of overloaded function 'templatedBar' does not match required type 'int (int)'}} expected-note@214{{candidate function made ineligible by enable_if}} + int (*p)(int) = templatedBar; // expected-error{{address of overloaded function 'templatedBar' does not match required type 'int (int)'}} expected-note@219{{candidate function made ineligible by enable_if}} + int (*p2)(int) = &templatedBar; // expected-error{{address of overloaded function 'templatedBar' does not match required type 'int (int)'}} expected-note@219{{candidate function made ineligible by enable_if}} int (*a)(int); - a = templatedBar; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@214{{candidate function made ineligible by enable_if}} - a = &templatedBar; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@214{{candidate function made ineligible by enable_if}} + a = templatedBar; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@219{{candidate function made ineligible by enable_if}} + a = &templatedBar; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@219{{candidate function made ineligible by enable_if}} } template @@ -227,21 +232,21 @@ template T templatedConflict(T m) __attribute__((enable_if(1, ""))) { return T(); } void test6() { - int (*p)(int) = templatedConflict; // expected-error{{address of overloaded function 'templatedConflict' is ambiguous}} expected-note@224{{candidate function made ineligible by enable_if}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} - int (*p0)(int) = &templatedConflict; // expected-error{{address of overloaded function 'templatedConflict' is ambiguous}} expected-note@224{{candidate function made ineligible by enable_if}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} + int (*p)(int) = templatedConflict; // expected-error{{address of overloaded function 'templatedConflict' is ambiguous}} expected-note@229{{candidate function made ineligible by enable_if}} expected-note@231{{candidate function}} expected-note@233{{candidate function}} + int (*p0)(int) = &templatedConflict; // expected-error{{address of overloaded function 'templatedConflict' is ambiguous}} expected-note@229{{candidate function made ineligible by enable_if}} expected-note@231{{candidate function}} expected-note@233{{candidate function}} int (*a)(int); - a = templatedConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} - a = &templatedConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} + a = templatedConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@231{{candidate function}} expected-note@233{{candidate function}} + a = &templatedConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@231{{candidate function}} expected-note@233{{candidate function}} } int ovlNoCandidate(int m) __attribute__((enable_if(false, ""))); int ovlNoCandidate(int m) __attribute__((enable_if(0, ""))); void test7() { - int (*p)(int) = ovlNoCandidate; // expected-error{{address of overloaded function 'ovlNoCandidate' does not match required type}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}} - int (*p2)(int) = &ovlNoCandidate; // expected-error{{address of overloaded function 'ovlNoCandidate' does not match required type}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}} + int (*p)(int) = ovlNoCandidate; // expected-error{{address of overloaded function 'ovlNoCandidate' does not match required type}} expected-note@242{{made ineligible by enable_if}} expected-note@243{{made ineligible by enable_if}} + int (*p2)(int) = &ovlNoCandidate; // expected-error{{address of overloaded function 'ovlNoCandidate' does not match required type}} expected-note@242{{made ineligible by enable_if}} expected-note@243{{made ineligible by enable_if}} int (*a)(int); - a = ovlNoCandidate; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}} - a = &ovlNoCandidate; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}} + a = ovlNoCandidate; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@242{{made ineligible by enable_if}} expected-note@243{{made ineligible by enable_if}} + a = &ovlNoCandidate; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@242{{made ineligible by enable_if}} expected-note@243{{made ineligible by enable_if}} } int noOvlNoCandidate(int m) __attribute__((enable_if(false, ""))); @@ -386,3 +391,47 @@ f.bar(1, 2); // expected-error{{too many arguments}} } } + +namespace value_dependent { +// Ensure that enable_if works well with dependent expressions... + +constexpr int noOverload(int N) __attribute__((enable_if(!N, ""))) { return 0; } //expected-note 2 {{candidate disabled}} + +template constexpr int callNoOverload() { return noOverload(N); } + +static_assert(callNoOverload<0>() == 0, ""); +constexpr int Fail = callNoOverload<1>(); // expected-error@-3{{no matching function for call to 'noOverload'}} expected-error{{constexpr variable 'Fail' must be initialized by a constant expression}} expected-note{{in instantiation of function}} + +// Prefixing noOverload with its namespace means we get to skip ADL, so we won't +// go into overload resolution for this. +template constexpr int directCallNoOverload() { + return ::value_dependent::noOverload(N); +} + +static_assert(directCallNoOverload<0>() == 0, ""); +constexpr int FailAgain = directCallNoOverload<1>(); // expected-error@-4{{no matching function for call to 'noOverload'}} expected-note{{in instantiation of function}} + +constexpr int overloaded(int N) __attribute__((enable_if(N == 0, ""))) { + return 1; +} + +constexpr int overloaded(int N) __attribute__((enable_if(N == 1, ""))) { + return 2; +} + +constexpr int overloaded(int N) { return 4; } + +template constexpr int callIt() { return overloaded(N); } + +static_assert(callIt<0>() == 1, ""); +static_assert(callIt<1>() == 2, ""); +static_assert(callIt<2>() == 4, ""); + +template +constexpr int directlyDepends() __attribute__((enable_if(N, ""))) { + return N; +} + +static_assert(directlyDepends<1>() == 1, ""); +constexpr int FailYetAgain = directlyDepends<0>(); // expected-error{{no matching function for call to 'directlyDepends'}} expected-note@-5{{candidate disabled}} +}