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>
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.

View File

@ -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 = &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
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

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" }
// { dg-error "invalid type" "invalid" { target *-*-* } 24 }
A<int, float> apple4;
// { dg-prune-output "provided for" }