Commit 1f15c50b by Dodji Seketeli Committed by Dodji Seketeli

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
parent 42f833bc
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> 2011-09-12 Jason Merrill <jason@redhat.com>
* pt.c (type_unification_real): Fix handling of DEDUCE_CONV * pt.c (type_unification_real): Fix handling of DEDUCE_CONV
......
...@@ -203,6 +203,7 @@ static void append_type_to_template_for_access_check_1 (tree, tree, tree, ...@@ -203,6 +203,7 @@ static void append_type_to_template_for_access_check_1 (tree, tree, tree,
static tree listify (tree); static tree listify (tree);
static tree listify_autos (tree, tree); static tree listify_autos (tree, tree);
static tree template_parm_to_arg (tree t); 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 current_template_args (void);
static tree fixup_template_type_parm_type (tree, int); static tree fixup_template_type_parm_type (tree, int);
static tree fixup_template_parm_index (tree, tree, int); static tree fixup_template_parm_index (tree, tree, int);
...@@ -2741,12 +2742,15 @@ template_parameter_pack_p (const_tree parm) ...@@ -2741,12 +2742,15 @@ template_parameter_pack_p (const_tree parm)
if (TREE_CODE (parm) == PARM_DECL) if (TREE_CODE (parm) == PARM_DECL)
return (DECL_TEMPLATE_PARM_P (parm) return (DECL_TEMPLATE_PARM_P (parm)
&& TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (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 /* If this is a list of template parameters, we could get a
TYPE_DECL or a TEMPLATE_DECL. */ TYPE_DECL or a TEMPLATE_DECL. */
if (TREE_CODE (parm) == TYPE_DECL || TREE_CODE (parm) == TEMPLATE_DECL) if (TREE_CODE (parm) == TYPE_DECL || TREE_CODE (parm) == TEMPLATE_DECL)
parm = TREE_TYPE (parm); parm = TREE_TYPE (parm);
/* Otherwise it must be a type template parameter. */
return ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM return ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
|| TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM) || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM)
&& TEMPLATE_TYPE_PARAMETER_PACK (parm)); && TEMPLATE_TYPE_PARAMETER_PACK (parm));
...@@ -4005,6 +4009,63 @@ template_parm_to_arg (tree t) ...@@ -4005,6 +4009,63 @@ template_parm_to_arg (tree t)
return 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 /* Within the declaration of a template, return all levels of template
parameters that apply. The template parameters are represented as parameters that apply. The template parameters are represented as
a TREE_VEC, in the form documented in cp-tree.h for template 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, ...@@ -9105,53 +9166,13 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
return result; return result;
} }
/* For clarity in the comments below let's use the if (arg_from_parm_pack_p (arg_pack, parm_pack))
representation 'argument_pack<elements>' to denote an /* The argument pack that the parameter maps to is just an
argument pack and its elements. expansion of the parameter itself, such as one would find
in the implicit typedef of a class inside the class itself.
In the 'if' block below, we want to detect cases where Consider this parameter "unsubstituted", so that we will
ARG_PACK is argument_pack<PARM_PACK...>. I.e, we want to maintain the outer pack expansion. */
check if ARG_PACK is an argument pack which sole element is arg_pack = NULL_TREE;
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_pack) if (arg_pack)
{ {
......
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> 2011-09-12 Richard Sandiford <rdsandiford@googlemail.com>
* gcc.target/mips/mips.exp (mips_option_groups): Add debug options. * gcc.target/mips/mips.exp (mips_option_groups): Add debug options.
......
// 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> ());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment