We ICE here because we are accessing call_args even though it's empty:

(gdb) p (*call_args).is_empty()
$5 = true

It's empty because the pack processed by tsubst_pack_expansion expanded into an
empty vector, so nothing got pushed onto call_args.  So handle that, and also
handle pushing 'this' properly when call_args is empty.

Bootstrapped/regtested on x86_64-linux, ok for trunk and 9?

2019-05-20  Marek Polacek  <pola...@redhat.com>

        PR c++/90548 - ICE with generic lambda and empty pack.
        * pt.c (tsubst_copy_and_build): Handle empty call args vector properly.

        * g++.dg/cpp1y/lambda-generic-90548.C: New test.

diff --git gcc/cp/pt.c gcc/cp/pt.c
index 3519c7a34a6..d9b99740947 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -18880,7 +18880,10 @@ tsubst_copy_and_build (tree t,
            /* We aren't going to do normal overload resolution, so force the
               template-id to resolve.  */
            function = resolve_nondeduced_context (function, complain);
-           for (unsigned i = 0; i < nargs; ++i)
+           /* There's no guarantee that there are any args; e.g., we could've
+              expanded an empty pack.  */
+           const bool empty_p = call_args->is_empty ();
+           for (unsigned i = 0; i < nargs && !empty_p; ++i)
              {
                /* In a thunk, pass through args directly, without any
                   conversions.  */
@@ -18891,12 +18894,18 @@ tsubst_copy_and_build (tree t,
              }
            if (thisarg)
              {
-               /* Shift the other args over to make room.  */
-               tree last = (*call_args)[nargs - 1];
-               vec_safe_push (call_args, last);
-               for (int i = nargs-1; i > 0; --i)
-                 (*call_args)[i] = (*call_args)[i-1];
-               (*call_args)[0] = thisarg;
+               /* If there are no other args, just push 'this'.  */
+               if (empty_p)
+                 vec_safe_push (call_args, thisarg);
+               else
+                 {
+                   /* Otherwise, shift the other args over to make room.  */
+                   tree last = (*call_args)[nargs - 1];
+                   vec_safe_push (call_args, last);
+                   for (int i = nargs-1; i > 0; --i)
+                     (*call_args)[i] = (*call_args)[i-1];
+                   (*call_args)[0] = thisarg;
+                 }
              }
            ret = build_call_a (function, call_args->length (),
                                call_args->address ());
diff --git gcc/testsuite/g++.dg/cpp1y/lambda-generic-90548.C 
gcc/testsuite/g++.dg/cpp1y/lambda-generic-90548.C
new file mode 100644
index 00000000000..beaffc29cfd
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp1y/lambda-generic-90548.C
@@ -0,0 +1,8 @@
+// PR c++/90548
+// { dg-do compile { target c++14 } }
+
+struct S { S (void ()); };
+
+S foo([] (auto...) {});
+S foo2{[] (auto...) {}};
+S foo3 = {[] (auto...) {}};

Reply via email to