In this testcase, when we try to call the object of 'overloader' type, we consider the conversion function from the first lambda to void (*)(a) and build up a surrogate call function for it. We consider how to convert from overloader to that type, which means also looking at the template conversion function from the second lambda, which involves instantiating the operator() to determine the return type, which is ill-formed.
But the standard seems to say that we shouldn't bother to consider how to do that conversion unless we actually choose the surrogate call function for that type, so that's what this patch implemenets. Tested x86_64-pc-linux-gnu, applying to trunk.
commit b987db09b63a8fc89f0d6cb2712c1ba8ee47eefd Author: Jason Merrill <ja...@redhat.com> Date: Mon Aug 28 17:38:59 2017 -0400 PR c++/80767 - unnecessary instantiation of generic lambda * call.c (convert_like_real): Call build_user_type_conversion_1 if cand is null. (add_conv_candidate): Build a ck_user conversion with no candidate. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 70c2f86..c446057 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2278,8 +2278,10 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj, if (i == 0) { - t = implicit_conversion (totype, argtype, arg, /*c_cast_p=*/false, - flags, complain); + t = build_identity_conv (argtype, NULL_TREE); + t = build_conv (ck_user, totype, t); + /* Leave the 'cand' field null; we'll figure out the conversion in + convert_like_real if this candidate is chosen. */ convert_type = totype; } else if (parmnode == void_list_node) @@ -6692,6 +6694,13 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, case ck_user: { struct z_candidate *cand = convs->cand; + + if (cand == NULL) + /* We chose the surrogate function from add_conv_candidate, now we + actually need to build the conversion. */ + cand = build_user_type_conversion_1 (totype, expr, + LOOKUP_NO_CONVERSION, complain); + tree convfn = cand->fn; /* When converting from an init list we consider explicit diff --git a/gcc/testsuite/g++.dg/cpp1z/lambda-inherit1.C b/gcc/testsuite/g++.dg/cpp1z/lambda-inherit1.C new file mode 100644 index 0000000..75ef586 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/lambda-inherit1.C @@ -0,0 +1,23 @@ +// PR c++/80767 +// { dg-options -std=c++17 } + +template <typename... Fs> +struct overloader : Fs... +{ + overloader(Fs... fs) + : Fs(fs)... + { } + + using Fs::operator()...; +}; + +struct a { void foo() { } }; +struct b { void bar() { } }; +struct c { void bar() { } }; + +int main() { + overloader{ + [](a x) { x.foo(); }, + [](auto x) { x.bar(); } + }(a{}); +}