diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 677392c31fc..3f373920616 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,14 @@ 2018-02-13 Jason Merrill + 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. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9a05e4fc812..81c6f0128e6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a83b7073d20..02d448e99b6 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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. */ -static tree -extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data) +struct el_data { - tree *extra = reinterpret_cast(data); + tree extra; + tsubst_flags_t complain; +}; +static tree +extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data_) +{ + el_data &data = *reinterpret_cast(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; diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C index 5196a18b5f1..97f64cd761a 100644 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C @@ -11,6 +11,7 @@ template 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 index 00000000000..811332040fa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic12.C @@ -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); +}