From b0ff7fe1d223260aea5b7dc3f36892aa57d43c77 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 26 Feb 2014 12:08:20 -0500 Subject: [PATCH] re PR c++/54440 ([c++11] g++ prematurely applying rule that a template parameter pack cannot be followed by a template parameter) PR c++/54440 * pt.c (get_template_parm_index): New. (fixed_parameter_pack_p_1, fixed_parameter_pack_p): New. (process_template_parm): Allow bare packs in template template parm template parms. (coerce_template_parameter_pack): Handle fixed template template parm packs and fixed packs not at the end of the parm list. (coerce_template_parms): Handle template parm packs not at the end of the parm list. (gen_elem_of_pack_expansion_instantiation): Handle a decl expansion. From-SVN: r208178 --- gcc/cp/ChangeLog | 11 ++ gcc/cp/pt.c | 229 +++++++++++++++++------ gcc/testsuite/g++.dg/cpp0x/variadic151.C | 9 + gcc/testsuite/g++.dg/cpp0x/variadic152.C | 12 ++ gcc/testsuite/g++.dg/cpp0x/variadic74.C | 2 + 5 files changed, 206 insertions(+), 57 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic151.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic152.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b2e687c3ab3..f1f1195b7fd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,16 @@ 2014-02-26 Jason Merrill + PR c++/54440 + * pt.c (get_template_parm_index): New. + (fixed_parameter_pack_p_1, fixed_parameter_pack_p): New. + (process_template_parm): Allow bare packs in template template + parm template parms. + (coerce_template_parameter_pack): Handle fixed template template + parm packs and fixed packs not at the end of the parm list. + (coerce_template_parms): Handle template parm packs not at the end + of the parm list. + (gen_elem_of_pack_expansion_instantiation): Handle a decl expansion. + PR c++/60182 * pt.c (unify): Ignore alias templates when deducing a template template parameter. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d72331182da..1f5a2b73532 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3697,7 +3697,10 @@ process_template_parm (tree list, location_t parm_loc, tree parm, return chainon (list, err_parm_list); } - if (uses_parameter_packs (TREE_TYPE (parm)) && !is_parameter_pack) + if (uses_parameter_packs (TREE_TYPE (parm)) && !is_parameter_pack + /* If we're in a nested template parameter list, the template + template parameter could be a parameter pack. */ + && processing_template_parmlist == 1) { /* This template parameter is not a parameter pack, but it should be. Complain about "bare" parameter packs. */ @@ -4326,6 +4329,77 @@ process_partial_specialization (tree decl) return decl; } +/* PARM is a template parameter of some form; return the corresponding + TEMPLATE_PARM_INDEX. */ + +static tree +get_template_parm_index (tree parm) +{ + if (TREE_CODE (parm) == PARM_DECL + || TREE_CODE (parm) == CONST_DECL) + parm = DECL_INITIAL (parm); + else if (TREE_CODE (parm) == TYPE_DECL + || TREE_CODE (parm) == TEMPLATE_DECL) + parm = TREE_TYPE (parm); + if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM + || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM) + parm = TEMPLATE_TYPE_PARM_INDEX (parm); + gcc_assert (TREE_CODE (parm) == TEMPLATE_PARM_INDEX); + return parm; +} + +/* Subroutine of fixed_parameter_pack_p below. Look for any template + parameter packs used by the template parameter PARM. */ + +static void +fixed_parameter_pack_p_1 (tree parm, struct find_parameter_pack_data *ppd) +{ + /* A type parm can't refer to another parm. */ + if (TREE_CODE (parm) == TYPE_DECL) + return; + else if (TREE_CODE (parm) == PARM_DECL) + { + cp_walk_tree (&TREE_TYPE (parm), &find_parameter_packs_r, + ppd, ppd->visited); + return; + } + + gcc_assert (TREE_CODE (parm) == TEMPLATE_DECL); + + tree vec = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm)); + for (int i = 0; i < TREE_VEC_LENGTH (vec); ++i) + fixed_parameter_pack_p_1 (TREE_VALUE (TREE_VEC_ELT (vec, i)), ppd); +} + +/* PARM is a template parameter pack. Return any parameter packs used in + its type or the type of any of its template parameters. If there are + any such packs, it will be instantiated into a fixed template parameter + list by partial instantiation rather than be fully deduced. */ + +tree +fixed_parameter_pack_p (tree parm) +{ + /* This can only be true in a member template. */ + if (TEMPLATE_PARM_ORIG_LEVEL (get_template_parm_index (parm)) < 2) + return NULL_TREE; + /* This can only be true for a parameter pack. */ + if (!template_parameter_pack_p (parm)) + return NULL_TREE; + /* A type parm can't refer to another parm. */ + if (TREE_CODE (parm) == TYPE_DECL) + return NULL_TREE; + + tree parameter_packs = NULL_TREE; + struct find_parameter_pack_data ppd; + ppd.parameter_packs = ¶meter_packs; + ppd.visited = pointer_set_create (); + + fixed_parameter_pack_p_1 (parm, &ppd); + + pointer_set_destroy (ppd.visited); + return parameter_packs; +} + /* Check that a template declaration's use of default arguments and parameter packs is not invalid. Here, PARMS are the template parameters. IS_PRIMARY is true if DECL is the thing declared by @@ -4431,7 +4505,10 @@ check_default_tmpl_args (tree decl, tree parms, bool is_primary, && parm_level == parms && TREE_CODE (decl) == TYPE_DECL && i < ntparms - 1 - && template_parameter_pack_p (TREE_VALUE (parm))) + && template_parameter_pack_p (TREE_VALUE (parm)) + /* A fixed parameter pack will be partially + instantiated into a fixed length list. */ + && !fixed_parameter_pack_p (TREE_VALUE (parm))) { /* A primary class template can only have one parameter pack, at the end of the template @@ -6531,58 +6608,53 @@ coerce_template_parameter_pack (tree parms, int nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0; tree packed_args; tree argument_pack; - tree packed_types = NULL_TREE; + tree packed_parms = NULL_TREE; if (arg_idx > nargs) arg_idx = nargs; - packed_args = make_tree_vec (nargs - arg_idx); - - if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL - && uses_parameter_packs (TREE_TYPE (TREE_VALUE (parm)))) + if (tree packs = fixed_parameter_pack_p (TREE_VALUE (parm))) { - /* When the template parameter is a non-type template - parameter pack whose type uses parameter packs, we need - to look at each of the template arguments - separately. Build a vector of the types for these - non-type template parameters in PACKED_TYPES. */ - tree expansion - = make_pack_expansion (TREE_TYPE (TREE_VALUE (parm))); - packed_types = tsubst_pack_expansion (expansion, args, - complain, in_decl); + /* When the template parameter is a non-type template parameter pack + or template template parameter pack whose type or template + parameters use parameter packs, we know exactly how many arguments + we are looking for. Build a vector of the instantiated decls for + these template parameters in PACKED_PARMS. */ + /* We can't use make_pack_expansion here because it would interpret a + _DECL as a use rather than a declaration. */ + tree decl = TREE_VALUE (parm); + tree exp = cxx_make_type (TYPE_PACK_EXPANSION); + SET_PACK_EXPANSION_PATTERN (exp, decl); + PACK_EXPANSION_PARAMETER_PACKS (exp) = packs; + SET_TYPE_STRUCTURAL_EQUALITY (exp); - if (packed_types == error_mark_node) + TREE_VEC_LENGTH (args)--; + packed_parms = tsubst_pack_expansion (exp, args, complain, decl); + TREE_VEC_LENGTH (args)++; + + if (packed_parms == error_mark_node) return error_mark_node; - /* Check that we have the right number of arguments. */ - if (arg_idx < nargs - && !PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx)) - && nargs - arg_idx != TREE_VEC_LENGTH (packed_types)) - { - int needed_parms - = TREE_VEC_LENGTH (parms) - 1 + TREE_VEC_LENGTH (packed_types); - error ("wrong number of template arguments (%d, should be %d)", - nargs, needed_parms); - return error_mark_node; - } - - /* If we aren't able to check the actual arguments now - (because they haven't been expanded yet), we can at least + /* If we're doing a partial instantiation of a member template, verify that all of the types used for the non-type template parameter pack are, in fact, valid for non-type template parameters. */ - if (arg_idx < nargs + if (arg_idx < nargs && PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx))) { - int j, len = TREE_VEC_LENGTH (packed_types); + int j, len = TREE_VEC_LENGTH (packed_parms); for (j = 0; j < len; ++j) { - tree t = TREE_VEC_ELT (packed_types, j); + tree t = TREE_TYPE (TREE_VEC_ELT (packed_parms, j)); if (invalid_nontype_parm_type_p (t, complain)) return error_mark_node; } } + + packed_args = make_tree_vec (TREE_VEC_LENGTH (packed_parms)); } + else + packed_args = make_tree_vec (nargs - arg_idx); /* Convert the remaining arguments, which will be a part of the parameter pack "parm". */ @@ -6590,18 +6662,19 @@ coerce_template_parameter_pack (tree parms, { tree arg = TREE_VEC_ELT (inner_args, arg_idx); tree actual_parm = TREE_VALUE (parm); + int pack_idx = arg_idx - parm_idx; - if (packed_types && !PACK_EXPANSION_P (arg)) + if (packed_parms) { - /* When we have a vector of types (corresponding to the - non-type template parameter pack that uses parameter - packs in its type, as mention above), and the - argument is not an expansion (which expands to a - currently unknown number of arguments), clone the - parm and give it the next type in PACKED_TYPES. */ - actual_parm = copy_node (actual_parm); - TREE_TYPE (actual_parm) = - TREE_VEC_ELT (packed_types, arg_idx - parm_idx); + /* Once we've packed as many args as we have types, stop. */ + if (pack_idx >= TREE_VEC_LENGTH (packed_parms)) + break; + else if (PACK_EXPANSION_P (arg)) + /* We don't know how many args we have yet, just + use the unconverted ones for now. */ + return NULL_TREE; + else + actual_parm = TREE_VEC_ELT (packed_parms, pack_idx); } if (arg == error_mark_node) @@ -6615,7 +6688,15 @@ coerce_template_parameter_pack (tree parms, in_decl); if (arg == error_mark_node) (*lost)++; - TREE_VEC_ELT (packed_args, arg_idx - parm_idx) = arg; + TREE_VEC_ELT (packed_args, pack_idx) = arg; + } + + if (arg_idx - parm_idx < TREE_VEC_LENGTH (packed_args) + && TREE_VEC_LENGTH (packed_args) > 0) + { + error ("wrong number of template arguments (%d, should be %d)", + arg_idx - parm_idx, TREE_VEC_LENGTH (packed_args)); + return error_mark_node; } if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL @@ -6676,6 +6757,7 @@ coerce_template_parms (tree parms, bool use_default_args) { int nparms, nargs, parm_idx, arg_idx, lost = 0; + tree orig_inner_args; tree inner_args; tree new_args; tree new_inner_args; @@ -6705,7 +6787,7 @@ coerce_template_parms (tree parms, ++variadic_p; } - inner_args = INNERMOST_TEMPLATE_ARGS (args); + inner_args = orig_inner_args = INNERMOST_TEMPLATE_ARGS (args); /* If there are no parameters that follow a parameter pack, we need to expand any argument packs so that we can deduce a parameter pack from some non-packed args followed by an argument pack, as in variadic85.C. @@ -6783,6 +6865,7 @@ coerce_template_parms (tree parms, c_inhibit_evaluation_warnings = 0; new_inner_args = make_tree_vec (nparms); new_args = add_outermost_template_args (args, new_inner_args); + int pack_adjust = 0; for (parm_idx = 0, arg_idx = 0; parm_idx < nparms; parm_idx++, arg_idx++) { tree arg; @@ -6806,22 +6889,36 @@ coerce_template_parms (tree parms, if (template_parameter_pack_p (TREE_VALUE (parm)) && !(arg && ARGUMENT_PACK_P (arg))) { - /* All remaining arguments will be placed in the + /* Some arguments will be placed in the template parameter pack PARM. */ arg = coerce_template_parameter_pack (parms, parm_idx, args, inner_args, arg_idx, new_args, &lost, in_decl, complain); - /* Store this argument. */ - if (arg == error_mark_node) - lost++; - if (lost) - break; + if (arg == NULL_TREE) + { + /* We don't know how many args we have yet, just use the + unconverted (and still packed) ones for now. */ + new_inner_args = orig_inner_args; + arg_idx = nargs; + break; + } + TREE_VEC_ELT (new_inner_args, parm_idx) = arg; - /* We are done with all of the arguments. */ - arg_idx = nargs; + /* Store this argument. */ + if (arg == error_mark_node) + { + lost++; + /* We are done with all of the arguments. */ + arg_idx = nargs; + } + else + { + pack_adjust = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) - 1; + arg_idx += pack_adjust; + } continue; } @@ -6832,6 +6929,7 @@ coerce_template_parms (tree parms, /* We don't know how many args we have yet, just use the unconverted ones for now. */ new_inner_args = inner_args; + arg_idx = nargs; break; } } @@ -6844,7 +6942,8 @@ coerce_template_parms (tree parms, is also the number of non-defaulted arguments in NEW_INNER_ARGS. Record that. */ if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args)) - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args, arg_idx); + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args, + arg_idx - pack_adjust); } else break; @@ -6868,11 +6967,23 @@ coerce_template_parms (tree parms, if (arg == error_mark_node) lost++; - TREE_VEC_ELT (new_inner_args, arg_idx) = arg; + TREE_VEC_ELT (new_inner_args, arg_idx - pack_adjust) = arg; } cp_unevaluated_operand = saved_unevaluated_operand; c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings; + if (variadic_p && arg_idx < nargs) + { + if (complain & tf_error) + { + error ("wrong number of template arguments " + "(%d, should be %d)", nargs, arg_idx); + if (in_decl) + error ("provided for %q+D", in_decl); + } + return error_mark_node; + } + if (lost) return error_mark_node; @@ -9509,7 +9620,11 @@ gen_elem_of_pack_expansion_instantiation (tree pattern, /* Substitute into the PATTERN with the (possibly altered) arguments. */ - if (!TYPE_P (pattern)) + if (pattern == in_decl) + /* Expanding a fixed parameter pack from + coerce_template_parameter_pack. */ + t = tsubst_decl (pattern, args, complain); + else if (!TYPE_P (pattern)) t = tsubst_expr (pattern, args, complain, in_decl, /*integral_constant_expression_p=*/false); else diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic151.C b/gcc/testsuite/g++.dg/cpp0x/variadic151.C new file mode 100644 index 00000000000..a65351db410 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic151.C @@ -0,0 +1,9 @@ +// PR c++/54440 +// { dg-do compile { target c++11 } } + +template struct A +{ + template struct B { }; +}; + +A::B<42,'a',float> b; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic152.C b/gcc/testsuite/g++.dg/cpp0x/variadic152.C new file mode 100644 index 00000000000..d7dccc53f6b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic152.C @@ -0,0 +1,12 @@ +// PR c++/54440 +// { dg-do compile { target c++11 } } + +template struct A +{ + template