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
This commit is contained in:
Jason Merrill 2014-02-26 12:08:20 -05:00 committed by Jason Merrill
parent f3417723b7
commit b0ff7fe1d2
5 changed files with 206 additions and 57 deletions

View File

@ -1,5 +1,16 @@
2014-02-26 Jason Merrill <jason@redhat.com> 2014-02-26 Jason Merrill <jason@redhat.com>
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 PR c++/60182
* pt.c (unify): Ignore alias templates when deducing a template * pt.c (unify): Ignore alias templates when deducing a template
template parameter. template parameter.

View File

@ -3697,7 +3697,10 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
return chainon (list, err_parm_list); 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 /* This template parameter is not a parameter pack, but it
should be. Complain about "bare" parameter packs. */ should be. Complain about "bare" parameter packs. */
@ -4326,6 +4329,77 @@ process_partial_specialization (tree decl)
return 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 = &parameter_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 /* Check that a template declaration's use of default arguments and
parameter packs is not invalid. Here, PARMS are the template parameter packs is not invalid. Here, PARMS are the template
parameters. IS_PRIMARY is true if DECL is the thing declared by 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 && parm_level == parms
&& TREE_CODE (decl) == TYPE_DECL && TREE_CODE (decl) == TYPE_DECL
&& i < ntparms - 1 && 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 /* A primary class template can only have one
parameter pack, at the end of the template 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; int nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
tree packed_args; tree packed_args;
tree argument_pack; tree argument_pack;
tree packed_types = NULL_TREE; tree packed_parms = NULL_TREE;
if (arg_idx > nargs) if (arg_idx > nargs)
arg_idx = nargs; arg_idx = nargs;
packed_args = make_tree_vec (nargs - arg_idx); if (tree packs = fixed_parameter_pack_p (TREE_VALUE (parm)))
if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL
&& uses_parameter_packs (TREE_TYPE (TREE_VALUE (parm))))
{ {
/* When the template parameter is a non-type template /* When the template parameter is a non-type template parameter pack
parameter pack whose type uses parameter packs, we need or template template parameter pack whose type or template
to look at each of the template arguments parameters use parameter packs, we know exactly how many arguments
separately. Build a vector of the types for these we are looking for. Build a vector of the instantiated decls for
non-type template parameters in PACKED_TYPES. */ these template parameters in PACKED_PARMS. */
tree expansion /* We can't use make_pack_expansion here because it would interpret a
= make_pack_expansion (TREE_TYPE (TREE_VALUE (parm))); _DECL as a use rather than a declaration. */
packed_types = tsubst_pack_expansion (expansion, args, tree decl = TREE_VALUE (parm);
complain, in_decl); 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; return error_mark_node;
/* Check that we have the right number of arguments. */ /* If we're doing a partial instantiation of a member template,
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
verify that all of the types used for the non-type verify that all of the types used for the non-type
template parameter pack are, in fact, valid for non-type template parameter pack are, in fact, valid for non-type
template parameters. */ template parameters. */
if (arg_idx < nargs if (arg_idx < nargs
&& PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, arg_idx))) && 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) 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)) if (invalid_nontype_parm_type_p (t, complain))
return error_mark_node; 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 /* Convert the remaining arguments, which will be a part of the
parameter pack "parm". */ parameter pack "parm". */
@ -6590,18 +6662,19 @@ coerce_template_parameter_pack (tree parms,
{ {
tree arg = TREE_VEC_ELT (inner_args, arg_idx); tree arg = TREE_VEC_ELT (inner_args, arg_idx);
tree actual_parm = TREE_VALUE (parm); 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 /* Once we've packed as many args as we have types, stop. */
non-type template parameter pack that uses parameter if (pack_idx >= TREE_VEC_LENGTH (packed_parms))
packs in its type, as mention above), and the break;
argument is not an expansion (which expands to a else if (PACK_EXPANSION_P (arg))
currently unknown number of arguments), clone the /* We don't know how many args we have yet, just
parm and give it the next type in PACKED_TYPES. */ use the unconverted ones for now. */
actual_parm = copy_node (actual_parm); return NULL_TREE;
TREE_TYPE (actual_parm) = else
TREE_VEC_ELT (packed_types, arg_idx - parm_idx); actual_parm = TREE_VEC_ELT (packed_parms, pack_idx);
} }
if (arg == error_mark_node) if (arg == error_mark_node)
@ -6615,7 +6688,15 @@ coerce_template_parameter_pack (tree parms,
in_decl); in_decl);
if (arg == error_mark_node) if (arg == error_mark_node)
(*lost)++; (*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 if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL
@ -6676,6 +6757,7 @@ coerce_template_parms (tree parms,
bool use_default_args) bool use_default_args)
{ {
int nparms, nargs, parm_idx, arg_idx, lost = 0; int nparms, nargs, parm_idx, arg_idx, lost = 0;
tree orig_inner_args;
tree inner_args; tree inner_args;
tree new_args; tree new_args;
tree new_inner_args; tree new_inner_args;
@ -6705,7 +6787,7 @@ coerce_template_parms (tree parms,
++variadic_p; ++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 /* 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 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. 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; c_inhibit_evaluation_warnings = 0;
new_inner_args = make_tree_vec (nparms); new_inner_args = make_tree_vec (nparms);
new_args = add_outermost_template_args (args, new_inner_args); 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++) for (parm_idx = 0, arg_idx = 0; parm_idx < nparms; parm_idx++, arg_idx++)
{ {
tree arg; tree arg;
@ -6806,22 +6889,36 @@ coerce_template_parms (tree parms,
if (template_parameter_pack_p (TREE_VALUE (parm)) if (template_parameter_pack_p (TREE_VALUE (parm))
&& !(arg && ARGUMENT_PACK_P (arg))) && !(arg && ARGUMENT_PACK_P (arg)))
{ {
/* All remaining arguments will be placed in the /* Some arguments will be placed in the
template parameter pack PARM. */ template parameter pack PARM. */
arg = coerce_template_parameter_pack (parms, parm_idx, args, arg = coerce_template_parameter_pack (parms, parm_idx, args,
inner_args, arg_idx, inner_args, arg_idx,
new_args, &lost, new_args, &lost,
in_decl, complain); in_decl, complain);
/* Store this argument. */ if (arg == NULL_TREE)
if (arg == error_mark_node) {
lost++; /* We don't know how many args we have yet, just use the
if (lost) unconverted (and still packed) ones for now. */
break; new_inner_args = orig_inner_args;
arg_idx = nargs;
break;
}
TREE_VEC_ELT (new_inner_args, parm_idx) = arg; TREE_VEC_ELT (new_inner_args, parm_idx) = arg;
/* We are done with all of the arguments. */ /* Store this argument. */
arg_idx = nargs; 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; continue;
} }
@ -6832,6 +6929,7 @@ coerce_template_parms (tree parms,
/* We don't know how many args we have yet, just /* We don't know how many args we have yet, just
use the unconverted ones for now. */ use the unconverted ones for now. */
new_inner_args = inner_args; new_inner_args = inner_args;
arg_idx = nargs;
break; break;
} }
} }
@ -6844,7 +6942,8 @@ coerce_template_parms (tree parms,
is also the number of non-defaulted arguments in NEW_INNER_ARGS. is also the number of non-defaulted arguments in NEW_INNER_ARGS.
Record that. */ Record that. */
if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args)) 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 else
break; break;
@ -6868,11 +6967,23 @@ coerce_template_parms (tree parms,
if (arg == error_mark_node) if (arg == error_mark_node)
lost++; 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; cp_unevaluated_operand = saved_unevaluated_operand;
c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings; 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) if (lost)
return error_mark_node; return error_mark_node;
@ -9509,7 +9620,11 @@ gen_elem_of_pack_expansion_instantiation (tree pattern,
/* Substitute into the PATTERN with the (possibly altered) /* Substitute into the PATTERN with the (possibly altered)
arguments. */ 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, t = tsubst_expr (pattern, args, complain, in_decl,
/*integral_constant_expression_p=*/false); /*integral_constant_expression_p=*/false);
else else

View File

@ -0,0 +1,9 @@
// PR c++/54440
// { dg-do compile { target c++11 } }
template <class...T> struct A
{
template <T... t, class U> struct B { };
};
A<int,char>::B<42,'a',float> b;

View File

@ -0,0 +1,12 @@
// PR c++/54440
// { dg-do compile { target c++11 } }
template <class...T> struct A
{
template <template <T> class... TP, class U> struct B { };
};
template <int I> struct C { };
template <char C> struct D { };
A<int,char>::B<C,D,float> b;

View File

@ -24,3 +24,5 @@ A<int*, float*>::X<&i> apple2; // { dg-error "wrong number of template arguments
A<int*, float*>::X<&i, &f, &f> apple3; // { dg-error "wrong number of template arguments" "wrong number" } A<int*, float*>::X<&i, &f, &f> apple3; // { dg-error "wrong number of template arguments" "wrong number" }
// { dg-error "invalid type" "invalid" { target *-*-* } 24 } // { dg-error "invalid type" "invalid" { target *-*-* } 24 }
A<int, float> apple4; A<int, float> apple4;
// { dg-prune-output "provided for" }