[Sema] Make type deduction work with some overloadable functions

Some functions can't have their address taken. If we encounter an
overload set where only one of the candidates can have its address
taken, we should automatically select that candidate's type in type
deduction.

Differential Revision: http://reviews.llvm.org/D15591

llvm-svn: 263888
This commit is contained in:
George Burgess IV 2016-03-19 21:51:45 +00:00
parent 3cde9bf9d5
commit cc2f355f71
2 changed files with 71 additions and 0 deletions

View File

@ -3016,6 +3016,11 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
return GetTypeOfFunction(S, R, ExplicitSpec);
}
DeclAccessPair DAP;
if (FunctionDecl *Viable =
S.resolveAddressOfOnlyViableOverloadCandidate(Arg, DAP))
return GetTypeOfFunction(S, R, Viable);
return QualType();
}

View File

@ -34,3 +34,69 @@ void foo(int) __attribute__((enable_if(false, "")));
void *Ptr = reinterpret_cast<void*>(foo); // expected-error{{'foo' is unavailable: don't call this}} expected-note@-3{{explicitly marked unavailable here}}
}
namespace template_deduction {
void foo() __attribute__((enable_if(false, "")));
void bar() __attribute__((enable_if(true, "")));
void bar() __attribute__((enable_if(false, "")));
void baz(int a) __attribute__((enable_if(true, "")));
void baz(int a) __attribute__((enable_if(a, "")));
void baz(int a) __attribute__((enable_if(false, "")));
void qux(int a) __attribute__((enable_if(1, "")));
void qux(int a) __attribute__((enable_if(true, "")));
void qux(int a) __attribute__((enable_if(a, "")));
void qux(int a) __attribute__((enable_if(false, "")));
template <typename Fn, typename... Args> void call(Fn F, Args... As) {
F(As...);
}
void test() {
call(foo); // expected-error{{cannot take address of function 'foo'}}
call(bar);
call(baz, 0);
call(qux, 0); // expected-error{{no matching function for call to 'call'}} expected-note@53{{candidate template ignored: couldn't infer template argument 'Fn'}}
auto Ptr1 = foo; // expected-error{{cannot take address of function 'foo'}}
auto Ptr2 = bar;
auto Ptr3 = baz;
auto Ptr4 = qux; // expected-error{{variable 'Ptr4' with type 'auto' has incompatible initializer of type '<overloaded function type>'}}
}
template <typename Fn, typename T, typename... Args>
void callMem(Fn F, T t, Args... As) {
(t.*F)(As...);
}
class Foo {
void bar() __attribute__((enable_if(true, "")));
void bar() __attribute__((enable_if(false, "")));
static void staticBar() __attribute__((enable_if(true, "")));
static void staticBar() __attribute__((enable_if(false, "")));
};
void testAccess() {
callMem(&Foo::bar, Foo()); // expected-error{{'bar' is a private member of 'template_deduction::Foo'}} expected-note@-8{{implicitly declared private here}}
call(&Foo::staticBar); // expected-error{{'staticBar' is a private member of 'template_deduction::Foo'}} expected-note@-6{{implicitly declared private here}}
}
}
namespace template_template_deduction {
void foo() __attribute__((enable_if(false, "")));
template <typename T>
T foo() __attribute__((enable_if(true, "")));
template <typename Fn, typename... Args> auto call(Fn F, Args... As) {
return F(As...);
}
auto Ok = call(&foo<int>);
auto Fail = call(&foo); // expected-error{{no matching function for call to 'call'}} expected-note@-5{{candidate template ignored: couldn't infer template argument 'Fn'}}
auto PtrOk = &foo<int>;
auto PtrFail = &foo; // expected-error{{variable 'PtrFail' with type 'auto' has incompatible initializer of type '<overloaded function type>'}}
}