c++/48320 - Template parameter packs cannot be expanded in default template arguments

gcc/cp/

	PR c++/48320
	* pt.c (template_parameter_pack_p):  Support TEMPLATE_PARM_INDEX
	nodes.  Add a comment.
	(arg_from_parm_pack_p):  New static function, factorized out from
	tsubst_pack_expansion and extended to support non-type parameter
	packs represented with TEMPLATE_PARM_INDEX nodes.
	(tsubst_pack_expansion): Use arg_from_parm_pack_p.

gcc/testsuite/

	PR c++/48320
	* g++.dg/cpp0x/variadic116.C: New test case.

From-SVN: r178811
This commit is contained in:
Dodji Seketeli 2011-09-13 14:39:15 +00:00 committed by Dodji Seketeli
parent 42f833bc5f
commit 1f15c50b16
4 changed files with 115 additions and 47 deletions

View File

@ -1,3 +1,13 @@
2011-09-13 Dodji Seketeli <dodji@redhat.com>
PR c++/48320
* pt.c (template_parameter_pack_p): Support TEMPLATE_PARM_INDEX
nodes. Add a comment.
(arg_from_parm_pack_p): New static function, factorized out from
tsubst_pack_expansion and extended to support non-type parameter
packs represented with TEMPLATE_PARM_INDEX nodes.
(tsubst_pack_expansion): Use arg_from_parm_pack_p.
2011-09-12 Jason Merrill <jason@redhat.com>
* pt.c (type_unification_real): Fix handling of DEDUCE_CONV

View File

@ -203,6 +203,7 @@ static void append_type_to_template_for_access_check_1 (tree, tree, tree,
static tree listify (tree);
static tree listify_autos (tree, tree);
static tree template_parm_to_arg (tree t);
static bool arg_from_parm_pack_p (tree, tree);
static tree current_template_args (void);
static tree fixup_template_type_parm_type (tree, int);
static tree fixup_template_parm_index (tree, tree, int);
@ -2741,12 +2742,15 @@ template_parameter_pack_p (const_tree parm)
if (TREE_CODE (parm) == PARM_DECL)
return (DECL_TEMPLATE_PARM_P (parm)
&& TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)));
if (TREE_CODE (parm) == TEMPLATE_PARM_INDEX)
return TEMPLATE_PARM_PARAMETER_PACK (parm);
/* If this is a list of template parameters, we could get a
TYPE_DECL or a TEMPLATE_DECL. */
if (TREE_CODE (parm) == TYPE_DECL || TREE_CODE (parm) == TEMPLATE_DECL)
parm = TREE_TYPE (parm);
/* Otherwise it must be a type template parameter. */
return ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
|| TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM)
&& TEMPLATE_TYPE_PARAMETER_PACK (parm));
@ -4005,6 +4009,63 @@ template_parm_to_arg (tree t)
return t;
}
/* This function returns TRUE if PARM_PACK is a template parameter
pack and if ARG_PACK is what template_parm_to_arg returned when
passed PARM_PACK. */
static bool
arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
{
/* For clarity in the comments below let's use the representation
argument_pack<elements>' to denote an argument pack and its
elements.
In the 'if' block below, we want to detect cases where
ARG_PACK is argument_pack<PARM_PACK...>. I.e, we want to
check if ARG_PACK is an argument pack which sole element is
the expansion of PARM_PACK. That argument pack is typically
created by template_parm_to_arg when passed a parameter
pack. */
if (arg_pack
&& TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
&& PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0)))
{
tree expansion = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0);
tree pattern = PACK_EXPANSION_PATTERN (expansion);
/* So we have an argument_pack<P...>. We want to test if P
is actually PARM_PACK. We will not use cp_tree_equal to
test P and PARM_PACK because during type fixup (by
fixup_template_parm) P can be a pre-fixup version of a
type and PARM_PACK be its post-fixup version.
cp_tree_equal would consider them as different even
though we would want to consider them compatible for our
precise purpose here.
Thus we are going to consider that P and PARM_PACK are
compatible if they have the same DECL. */
if ((/* If ARG_PACK is a type parameter pack named by the
same DECL as parm_pack ... */
(TYPE_P (pattern)
&& TYPE_P (parm_pack)
&& TYPE_NAME (pattern) == TYPE_NAME (parm_pack))
/* ... or if PARM_PACK is a non-type parameter named by the
same DECL as ARG_PACK. Note that PARM_PACK being a
non-type parameter means it's either a PARM_DECL or a
TEMPLATE_PARM_INDEX. */
|| (TREE_CODE (pattern) == TEMPLATE_PARM_INDEX
&& ((TREE_CODE (parm_pack) == PARM_DECL
&& (TEMPLATE_PARM_DECL (pattern)
== TEMPLATE_PARM_DECL (DECL_INITIAL (parm_pack))))
|| (TREE_CODE (parm_pack) == TEMPLATE_PARM_INDEX
&& (TEMPLATE_PARM_DECL (pattern)
== TEMPLATE_PARM_DECL (parm_pack))))))
&& template_parameter_pack_p (pattern))
return true;
}
return false;
}
/* Within the declaration of a template, return all levels of template
parameters that apply. The template parameters are represented as
a TREE_VEC, in the form documented in cp-tree.h for template
@ -9105,53 +9166,13 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
return result;
}
/* For clarity in the comments below let's use the
representation 'argument_pack<elements>' to denote an
argument pack and its elements.
In the 'if' block below, we want to detect cases where
ARG_PACK is argument_pack<PARM_PACK...>. I.e, we want to
check if ARG_PACK is an argument pack which sole element is
the expansion of PARM_PACK. That argument pack is typically
created by template_parm_to_arg when passed a parameter
pack. */
if (arg_pack
&& TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
&& PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0)))
{
tree expansion = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0);
tree pattern = PACK_EXPANSION_PATTERN (expansion);
/* So we have an argument_pack<P...>. We want to test if P
is actually PARM_PACK. We will not use cp_tree_equal to
test P and PARM_PACK because during type fixup (by
fixup_template_parm) P can be a pre-fixup version of a
type and PARM_PACK be its post-fixup version.
cp_tree_equal would consider them as different even
though we would want to consider them compatible for our
precise purpose here.
Thus we are going to consider that P and PARM_PACK are
compatible if they have the same DECL. */
if ((/* If ARG_PACK is a type parameter pack named by the
same DECL as parm_pack ... */
(TYPE_P (pattern)
&& TYPE_P (parm_pack)
&& TYPE_NAME (pattern) == TYPE_NAME (parm_pack))
/* ... or if ARG_PACK is a non-type parameter
named by the same DECL as parm_pack ... */
|| (TREE_CODE (pattern) == TEMPLATE_PARM_INDEX
&& TREE_CODE (parm_pack) == PARM_DECL
&& TEMPLATE_PARM_DECL (pattern)
== TEMPLATE_PARM_DECL (DECL_INITIAL (parm_pack))))
&& template_parameter_pack_p (pattern))
/* ... then the argument pack that the parameter maps to
is just an expansion of the parameter itself, such as
one would find in the implicit typedef of a class
inside the class itself. Consider this parameter
"unsubstituted", so that we will maintain the outer
pack expansion. */
arg_pack = NULL_TREE;
}
if (arg_from_parm_pack_p (arg_pack, parm_pack))
/* The argument pack that the parameter maps to is just an
expansion of the parameter itself, such as one would find
in the implicit typedef of a class inside the class itself.
Consider this parameter "unsubstituted", so that we will
maintain the outer pack expansion. */
arg_pack = NULL_TREE;
if (arg_pack)
{

View File

@ -1,3 +1,8 @@
2011-09-13 Dodji Seketeli <dodji@redhat.com>
PR c++/48320
* g++.dg/cpp0x/variadic116.C: New test case.
2011-09-12 Richard Sandiford <rdsandiford@googlemail.com>
* gcc.target/mips/mips.exp (mips_option_groups): Add debug options.

View File

@ -0,0 +1,32 @@
// Origin: PR c++/48320
// { dg-options -std=c++0x }
template<class... T>
struct tuple
{
typedef int type;
};
template<int... Indices>
struct indices
{
};
template<unsigned i, class Tuple>
struct tuple_element
{
typedef Tuple type;
};
template<class Tuple,
int... Indices,
class Result = tuple<typename tuple_element<Indices, Tuple>::type...> >
Result
f(Tuple&&, indices<Indices...>);
void
foo()
{
f(tuple<int, char, unsigned> (), indices<2, 1, 0> ());
}