This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Fix PRs c++/31993 and c++/32252 (variadic templates)
- From: "Doug Gregor" <doug dot gregor at gmail dot com>
- To: "GCC Patches" <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 4 Jul 2007 09:39:00 -0400
- Subject: [C++ PATCH] Fix PRs c++/31993 and c++/32252 (variadic templates)
PRs c++/31993 and c++/32252 (both P1s) are ice-on-valid-code failures
in the handling of variadic templates. PR 31993 concerns member
templates of variadic templates, while PR 32252 concerns non-type
template parameter packs whose types involve other template
parameters. Both problems concern substitution of argument packs, so
I've addressed both PRs with one patch.
Tested powerpc-apple-darwin8.10.0; no regressions in the C++ front end
or libstdc++.
Okay for mainline?
:ADDPATCH c++:
- Doug
2007-07-04 Douglas Gregor <doug.gregor@gmail.com>
PR c++/31993
PR c++/32252
* pt.c (find_parameter_packs_r): Fix typo in comment.
(convert_template_argument): Look at the pattern of a pack
expansion to determine what kind of entity we're converting.
(coerce_template_parameter_pack): When we have coerced a non-type
template parameter pack, substitute into the type of that pack.
(tsubst_pack_expansion): We our substitution of a parameter pack
is a "trivial" substitution of itself, just substitute into the
pack expansion rather than actually expanding.
(tsubst): Dig out the pattern of a pack expansion when examining
the structure of the expansion.
2007-07-04 Douglas Gregor <doug.gregor@gmail.com>
* g++.dg/cpp0x/pr31993.C: New
* g++.dg/cpp0x/pr32252.C: New
Index: cp/pt.c
===================================================================
--- cp/pt.c (revision 126265)
+++ cp/pt.c (working copy)
@@ -2389,9 +2389,9 @@ struct find_parameter_pack_data
struct pointer_set_t *visited;
};
-/* Identifiers all of the argument packs that occur in a template
+/* Identifies all of the argument packs that occur in a template
argument and appends them to the TREE_LIST inside DATA, which is a
- find_parameter_pack_Data structure. This is a subroutine of
+ find_parameter_pack_data structure. This is a subroutine of
make_pack_expansion and uses_parameter_packs. */
static tree
find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
@@ -4630,7 +4630,7 @@ convert_template_argument (tree parm,
{
tree val;
int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
- tree check_arg = arg;
+ tree check_arg;
if (TREE_CODE (arg) == TREE_LIST
&& TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)
@@ -4644,6 +4644,8 @@ convert_template_argument (tree parm,
TREE_TYPE (arg) = unknown_type_node;
}
+ check_arg = arg;
+
requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;
requires_type = (TREE_CODE (parm) == TYPE_DECL
|| requires_tmpl_type);
@@ -4664,18 +4666,24 @@ convert_template_argument (tree parm,
|| TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE))
arg = TYPE_STUB_DECL (arg);
- is_type = TYPE_P (arg) || is_tmpl_type;
+ if (is_tmpl_type
+ && (TREE_CODE (check_arg) == TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (check_arg) == UNBOUND_CLASS_TEMPLATE))
+ check_arg = TYPE_STUB_DECL (check_arg);
+
+ is_type = TYPE_P (check_arg) || is_tmpl_type;
- if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF
- && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
+ if (requires_type && ! is_type && TREE_CODE (check_arg) == SCOPE_REF
+ && TREE_CODE (TREE_OPERAND (check_arg, 0)) == TEMPLATE_TYPE_PARM)
{
pedwarn ("to refer to a type member of a template parameter, "
- "use %<typename %E%>", arg);
+ "use %<typename %E%>", check_arg);
- arg = make_typename_type (TREE_OPERAND (arg, 0),
- TREE_OPERAND (arg, 1),
+ arg = make_typename_type (TREE_OPERAND (check_arg, 0),
+ TREE_OPERAND (check_arg, 1),
typename_type,
complain & tf_error);
+ check_arg = arg;
is_type = 1;
}
if (is_type != requires_type)
@@ -4718,21 +4726,15 @@ convert_template_argument (tree parm,
{
if (requires_tmpl_type)
{
- if (TREE_CODE (TREE_TYPE (arg)) == UNBOUND_CLASS_TEMPLATE)
+ if (TREE_CODE (TREE_TYPE (check_arg)) == UNBOUND_CLASS_TEMPLATE)
/* The number of argument required is not known yet.
Just accept it for now. */
- val = TREE_TYPE (arg);
+ val = TREE_TYPE (check_arg);
else
{
tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
tree argparm;
- check_arg = arg;
- /* When determining whether a pack expansion is a template,
- look at the pattern. */
- if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
- check_arg = PACK_EXPANSION_PATTERN (check_arg);
-
argparm = DECL_INNERMOST_TEMPLATE_PARMS (check_arg);
if (coerce_template_template_parms (parmparm, argparm,
@@ -4763,7 +4765,7 @@ convert_template_argument (tree parm,
"template parameter list for %qD",
i + 1, in_decl);
error (" expected a template of type %qD, got %qD",
- parm, arg);
+ parm, check_arg);
}
val = error_mark_node;
@@ -4918,7 +4920,8 @@ coerce_template_parameter_pack (tree par
else
{
argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
- TREE_TYPE (argument_pack) = TREE_TYPE (TREE_VALUE (parm));
+ TREE_TYPE (argument_pack)
+ = tsubst (TREE_TYPE (TREE_VALUE (parm)), args, complain, in_decl);
TREE_CONSTANT (argument_pack) = 1;
}
@@ -6998,6 +7001,22 @@ tsubst_pack_expansion (tree t, tree args
return result;
}
+ 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);
+ if ((TYPE_P (pattern) && same_type_p (pattern, parm_pack))
+ || (!TYPE_P (pattern) && cp_tree_equal (parm_pack, pattern)))
+ /* 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)
{
int my_len =
@@ -8607,6 +8626,12 @@ tsubst (tree t, tree args, tsubst_flags_
if (argvec == error_mark_node)
return error_mark_node;
+ /* We can get a pack expansion here when we are
+ instantiating a member template and ARG is a pack
+ expansion from the outer template. */
+ if (PACK_EXPANSION_P (arg))
+ arg = PACK_EXPANSION_PATTERN (arg);
+
/* We can get a TEMPLATE_TEMPLATE_PARM here when we
are resolving nested-types in the signature of a
member function templates. Otherwise ARG is a
Index: testsuite/g++.dg/cpp0x/pr31993.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr31993.C (revision 0)
+++ testsuite/g++.dg/cpp0x/pr31993.C (revision 0)
@@ -0,0 +1,9 @@
+// { dg-options "-std=c++0x" }
+
+template<typename...> struct A;
+
+template<template<int> class... T> struct A<T<0>...>
+{
+ template<int> struct B {};
+ B<0> b;
+};
Index: testsuite/g++.dg/cpp0x/pr32252.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr32252.C (revision 0)
+++ testsuite/g++.dg/cpp0x/pr32252.C (revision 0)
@@ -0,0 +1,8 @@
+// { dg-options "-std=c++0x" }
+int x[5];
+
+template<int M, int N, int (&... p)[N]> struct A;
+
+template<int M> struct A<M,5,x> {};
+
+A<0,5,x> a;