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{});
+}

Reply via email to