Fix more variadic capture issues.
authorJason Merrill <jason@redhat.com>
Tue, 13 Feb 2018 14:22:07 +0000 (09:22 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 13 Feb 2018 14:22:07 +0000 (09:22 -0500)
* pt.c (find_parameter_packs_r): Also look at explicit captures.
(check_for_bare_parameter_packs): Check current_class_type for
lambda context.
(extract_locals_r): Handle seeing a full instantiation of a pack.
(tsubst_pack_expansion): Likewise.  Force lambda capture.
* parser.c (cp_parser_lambda_introducer): Don't
check_for_bare_parameter_packs.

From-SVN: r257627

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

index 677392c31fc09c5b73a18d6426c107f7c006de2a..3f37392061670a840d0294beef2a121c91777675 100644 (file)
@@ -1,5 +1,14 @@
 2018-02-13  Jason Merrill  <jason@redhat.com>
 
+       Fix more variadic capture issues.
+       * pt.c (find_parameter_packs_r): Also look at explicit captures.
+       (check_for_bare_parameter_packs): Check current_class_type for
+       lambda context.
+       (extract_locals_r): Handle seeing a full instantiation of a pack.
+       (tsubst_pack_expansion): Likewise.  Force lambda capture.
+       * parser.c (cp_parser_lambda_introducer): Don't
+       check_for_bare_parameter_packs.
+
        PR c++/84338 - wrong variadic sizeof.
        * pt.c (argument_pack_select_arg): Like the macro, but look through
        a pack expansion.
index 9a05e4fc812b4549c6a00e0ac0ad775a737634d7..81c6f0128e63b690fc231fed8a1902afb7dac972 100644 (file)
@@ -10412,8 +10412,6 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
              cp_lexer_consume_token (parser->lexer);
              capture_init_expr = make_pack_expansion (capture_init_expr);
            }
-         else
-           check_for_bare_parameter_packs (capture_init_expr);
        }
 
       if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) != CPLD_NONE
index a83b7073d20f6d79ef2209f2cdc870fc25c50b1f..02d448e99b67d1a866c064688d8b3485dd6a3aff 100644 (file)
@@ -3587,7 +3587,6 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
         }
       break;
 
-      /* Look through a lambda capture proxy to the field pack.  */
     case VAR_DECL:
       if (DECL_PACK_P (t))
         {
@@ -3707,6 +3706,12 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
 
     case LAMBDA_EXPR:
       {
+       /* Look at explicit captures.  */
+       for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t);
+            cap; cap = TREE_CHAIN (cap))
+         cp_walk_tree (&TREE_VALUE (cap), &find_parameter_packs_r, ppd,
+                       ppd->visited);
+       /* Since we defer implicit capture, look in the body as well.  */
        tree fn = lambda_function (t);
        cp_walk_tree (&DECL_SAVED_TREE (fn), &find_parameter_packs_r, ppd,
                      ppd->visited);
@@ -3907,7 +3912,7 @@ check_for_bare_parameter_packs (tree t)
     return false;
 
   /* A lambda might use a parameter pack from the containing context.  */
-  if (current_function_decl && LAMBDA_FUNCTION_P (current_function_decl))
+  if (current_class_type && LAMBDA_TYPE_P (current_class_type))
     return false;
 
   if (TREE_CODE (t) == TYPE_DECL)
@@ -11410,30 +11415,72 @@ tsubst_binary_right_fold (tree t, tree args, tsubst_flags_t complain,
 /* Walk through the pattern of a pack expansion, adding everything in
    local_specializations to a list.  */
 
+struct el_data
+{
+  tree extra;
+  tsubst_flags_t complain;
+};
 static tree
-extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data)
+extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data_)
 {
-  tree *extra = reinterpret_cast<tree*>(data);
+  el_data &data = *reinterpret_cast<el_data*>(data_);
+  tree *extra = &data.extra;
+  tsubst_flags_t complain = data.complain;
   if (tree spec = retrieve_local_specialization (*tp))
     {
       if (TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK)
        {
-         /* Pull out the actual PARM_DECL for the partial instantiation.  */
+         /* Maybe pull out the PARM_DECL for a 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);
+         if (TREE_VEC_LENGTH (args) == 1)
+           {
+             tree elt = TREE_VEC_ELT (args, 0);
+             if (PACK_EXPANSION_P (elt))
+               elt = PACK_EXPANSION_PATTERN (elt);
+             if (DECL_PACK_P (elt))
+               spec = elt;
+           }
+         if (TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK)
+           {
+             /* Handle lambda capture here, since we aren't doing any
+                substitution now, and so tsubst_copy won't call
+                process_outer_var_ref.  */
+             tree args = ARGUMENT_PACK_ARGS (spec);
+             int len = TREE_VEC_LENGTH (args);
+             for (int i = 0; i < len; ++i)
+               {
+                 tree arg = TREE_VEC_ELT (args, i);
+                 tree carg = arg;
+                 if (outer_automatic_var_p (arg))
+                   carg = process_outer_var_ref (arg, complain);
+                 if (carg != arg)
+                   {
+                     /* Make a new NONTYPE_ARGUMENT_PACK of the capture
+                        proxies.  */
+                     if (i == 0)
+                       {
+                         spec = copy_node (spec);
+                         args = copy_node (args);
+                         SET_ARGUMENT_PACK_ARGS (spec, args);
+                         register_local_specialization (spec, *tp);
+                       }
+                     TREE_VEC_ELT (args, i) = carg;
+                   }
+               }
+           }
        }
+      if (outer_automatic_var_p (spec))
+       spec = process_outer_var_ref (spec, complain);
       *extra = tree_cons (*tp, spec, *extra);
     }
   return NULL_TREE;
 }
 static tree
-extract_local_specs (tree pattern)
+extract_local_specs (tree pattern, tsubst_flags_t complain)
 {
-  tree extra = NULL_TREE;
-  cp_walk_tree_without_duplicates (&pattern, extract_locals_r, &extra);
-  return extra;
+  el_data data = { NULL_TREE, complain };
+  cp_walk_tree_without_duplicates (&pattern, extract_locals_r, &data);
+  return data.extra;
 }
 
 /* Substitute ARGS into T, which is an pack expansion
@@ -11468,8 +11515,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
             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);
+         tree inst = TREE_VALUE (elt);
+         if (DECL_PACK_P (inst))
+           inst = retrieve_local_specialization (inst);
+         /* else inst is already a full instantiation of the pack.  */
          register_local_specialization (inst, gen);
        }
       gcc_assert (!TREE_PURPOSE (extra));
@@ -11651,7 +11700,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
       t = make_pack_expansion (pattern, complain);
       tree extra = args;
       if (local_specializations)
-       if (tree locals = extract_local_specs (pattern))
+       if (tree locals = extract_local_specs (pattern, complain))
          extra = tree_cons (NULL_TREE, extra, locals);
       PACK_EXPANSION_EXTRA_ARGS (t) = extra;
       return t;
index 5196a18b5f1c1b2c9cd02dd46533ef9d69e44952..97f64cd761a7af041d52709ea8c0e4f7f0fb54b3 100644 (file)
@@ -11,6 +11,7 @@ template<class... T>
 void print_all(const T&... t)
 {
   accept_all([&]()->int { print(t); return 0; }...);
+  accept_all([&t]()->int { print(t); return 0; }...);
 }
 
 int main()
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic12.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic12.C
new file mode 100644 (file)
index 0000000..8113320
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++14 } }
+
+template < typename... T > void sink(T ...){}
+
+template < typename... T >
+auto f(T... t){
+  [=](auto ... j){
+    sink((t + j)...);
+  }(t...);
+}
+
+int main(){
+  f(0);
+  f();
+  f(0.1,0.2);
+}