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:
parent
42f833bc5f
commit
1f15c50b16
@ -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
|
||||
|
113
gcc/cp/pt.c
113
gcc/cp/pt.c
@ -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. */
|
||||
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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
32
gcc/testsuite/g++.dg/cpp0x/variadic116.C
Normal file
32
gcc/testsuite/g++.dg/cpp0x/variadic116.C
Normal 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> ());
|
||||
}
|
Loading…
Reference in New Issue
Block a user