PR c++/84182 - ICE with captured lambda
authorJason Merrill <jason@redhat.com>
Wed, 7 Feb 2018 16:02:50 +0000 (11:02 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 7 Feb 2018 16:02:50 +0000 (11:02 -0500)
PR c++/84181
* pt.c (extract_locals_r, extract_local_specs): New.
(tsubst_pack_expansion): Use them.

From-SVN: r257454

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1y/lambda-generic-targ2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic10.C [new file with mode: 0644]

index d27b885..ce0b759 100644 (file)
@@ -1,3 +1,10 @@
+2018-02-07  Jason Merrill  <jason@redhat.com>
+
+       PR c++/84182 - ICE with captured lambda
+       PR c++/84181
+       * pt.c (extract_locals_r, extract_local_specs): New.
+       (tsubst_pack_expansion): Use them.
+
 2018-02-07  Martin Liska  <mliska@suse.cz>
 
        PR c++/84059.
index ca73bb1..0d9e153 100644 (file)
@@ -11415,6 +11415,34 @@ tsubst_binary_right_fold (tree t, tree args, tsubst_flags_t complain,
   return expand_right_fold (t, vec, complain);
 }
 
+/* Walk through the pattern of a pack expansion, adding everything in
+   local_specializations to a list.  */
+
+static tree
+extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data)
+{
+  tree *extra = reinterpret_cast<tree*>(data);
+  if (tree spec = retrieve_local_specialization (*tp))
+    {
+      if (TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK)
+       {
+         /* Pull out the actual PARM_DECL for the partial instantiation.  */
+         tree args = ARGUMENT_PACK_ARGS (spec);
+         gcc_assert (TREE_VEC_LENGTH (args) == 1);
+         tree arg = TREE_VEC_ELT (args, 0);
+         spec = PACK_EXPANSION_PATTERN (arg);
+       }
+      *extra = tree_cons (*tp, spec, *extra);
+    }
+  return NULL_TREE;
+}
+static tree
+extract_local_specs (tree pattern)
+{
+  tree extra = NULL_TREE;
+  cp_walk_tree_without_duplicates (&pattern, extract_locals_r, &extra);
+  return extra;
+}
 
 /* Substitute ARGS into T, which is an pack expansion
    (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a
@@ -11442,14 +11470,17 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   tree extra = PACK_EXPANSION_EXTRA_ARGS (t);
   if (extra && TREE_CODE (extra) == TREE_LIST)
     {
-      /* The partial instantiation involved function parameter packs; map
-         from the general template to our current context.  */
-      for (tree fns = TREE_CHAIN (extra); fns; fns = TREE_CHAIN (fns))
+      for (tree elt = TREE_CHAIN (extra); elt; elt = TREE_CHAIN (elt))
        {
-         tree fn = TREE_PURPOSE (fns);
-         tree inst = enclosing_instantiation_of (fn);
-         register_parameter_specializations (fn, inst);
+         /* The partial instantiation involved local declarations collected in
+            extract_local_specs; map from the general template to our local
+            context.  */
+         tree gen = TREE_PURPOSE (elt);
+         tree partial = TREE_VALUE (elt);
+         tree inst = retrieve_local_specialization (partial);
+         register_local_specialization (inst, gen);
        }
+      gcc_assert (!TREE_PURPOSE (extra));
       extra = TREE_VALUE (extra);
     }
   args = add_to_template_args (extra, args);
@@ -11625,25 +11656,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
       t = make_pack_expansion (pattern, complain);
       tree extra = args;
       if (unsubstituted_fn_pack)
-       {
-         /* For function parameter packs it's more complicated; we need to
-            remember which enclosing function(s) provided them to this pack
-            expansion so we can map their parameters to the parameters of a
-            later full instantiation.  */
-         tree fns = NULL_TREE;
-         for (tree p = packs; p; p = TREE_CHAIN (p))
-           {
-             tree parm = TREE_PURPOSE (p);
-             if (TREE_CODE (parm) != PARM_DECL)
-               continue;
-             parm = DECL_CONTEXT (parm);
-             if (purpose_member (parm, fns))
-               continue;
-             fns = tree_cons (parm, NULL_TREE, fns);
-           }
-         if (fns)
-           extra = tree_cons (NULL_TREE, extra, fns);
-       }
+       if (tree locals = extract_local_specs (pattern))
+         extra = tree_cons (NULL_TREE, extra, locals);
       PACK_EXPANSION_EXTRA_ARGS (t) = extra;
       return t;
     }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-targ2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-targ2.C
new file mode 100644 (file)
index 0000000..b4d63da
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/84181
+// { dg-do compile { target c++14 } }
+
+template < int ... I >
+struct A{};
+
+template < typename T >
+auto var = [](auto ... i){
+        return A< decltype(i)::x ... >{};
+    };
+
+int main(){
+    var< int >();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic10.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic10.C
new file mode 100644 (file)
index 0000000..ab790cf
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/84182
+// { dg-do compile { target c++14 } }
+
+template < typename ... T > void sink(T ...){}
+
+template < typename >
+void f(){
+    auto const lambda = [](int){ return 1; };
+
+    [lambda](auto ... i){
+        sink(lambda(i) ...);
+    }(1);
+}
+
+int main(){
+    f< int >();
+}