c++/48320 - Template parameter packs cannot be expanded in default template arguments
authordodji <dodji@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Sep 2011 14:39:15 +0000 (14:39 +0000)
committerdodji <dodji@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Sep 2011 14:39:15 +0000 (14:39 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@178811 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/variadic116.C [new file with mode: 0644]

index 6b6c36d..aa4a31d 100644 (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
index 9a5e3dd..1407364 100644 (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)
         {
index eea712e..65af046 100644 (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.
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic116.C b/gcc/testsuite/g++.dg/cpp0x/variadic116.C
new file mode 100644 (file)
index 0000000..079d751
--- /dev/null
@@ -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> ());
+}