On Wed, May 22, 2019 at 12:17:04AM -0400, Jason Merrill wrote:
> On 5/20/19 6:08 PM, Marek Polacek wrote:
> > 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.
> 
> Ah, the problem is that nargs is just wrong in the presence of pack
> expansions; in this case it's too large, but it could also end up too small.
> What we want is the length of call_args, not the number of args before doing
> the expansions.

Oh, right.  I've expanded the test to also detect the case when the number of
arguments grows after any packs have been expanded.  We still need the special
handling when adding 'this', though.

Thanks for catching the other problem!

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

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

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

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

diff --git gcc/cp/pt.c gcc/cp/pt.c
index 592adfcf5c1..0a31ba4f3fe 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -18861,6 +18861,9 @@ tsubst_copy_and_build (tree t,
           the thunk template for a generic lambda.  */
        if (CALL_FROM_THUNK_P (t))
          {
+           /* Now that we've expanded any packs, the number of call args
+              might be different.  */
+           unsigned int cargs = call_args->length ();
            tree thisarg = NULL_TREE;
            if (TREE_CODE (function) == COMPONENT_REF)
              {
@@ -18874,7 +18877,7 @@ 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)
+           for (unsigned i = 0; i < cargs; ++i)
              {
                /* In a thunk, pass through args directly, without any
                   conversions.  */
@@ -18885,12 +18888,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 (cargs == 0)
+                 vec_safe_push (call_args, thisarg);
+               else
+                 {
+                   /* Otherwise, shift the other args over to make room.  */
+                   tree last = (*call_args)[cargs - 1];
+                   vec_safe_push (call_args, last);
+                   for (int i = cargs - 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..b845dd85c41
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp1y/lambda-generic-90548.C
@@ -0,0 +1,22 @@
+// PR c++/90548
+// { dg-do compile { target c++14 } }
+
+struct S { S (void ()); };
+S foo([] (auto...) { });
+S foo2{[] (auto...) {}};
+S foo3 = {[] (auto...) {}};
+
+struct W { W(void (int)); };
+W bar([](auto...) { });
+W bar2{[](auto...) { }};
+W bar3 = {[](auto...) { }};
+
+struct T { T(void (int, int)); };
+T qux([](auto...) { });
+T qux2{[](auto...) { }};
+T qux3 = {[](auto...) { }};
+
+struct R { R(void (int, int, int, int, int, int, int, int, int, int)); };
+R baz([](auto...) { });
+R baz2{[](auto...) { }};
+R baz3 = {[](auto...) { }};

Reply via email to