Patchwork Fix PR c++/46394

login
register
mail settings
Submitter Dodji Seketeli
Date Feb. 18, 2011, 4:13 p.m.
Message ID <m3sjvl9v81.fsf@seketeli.org>
Download mbox | patch
Permalink /patch/83621/
State New
Headers show

Comments

Dodji Seketeli - Feb. 18, 2011, 4:13 p.m.
Dodji Seketeli <dodji@redhat.com> a écrit:

> Jason Merrill <jason@redhat.com> writes:
>
>> It seems to me that rather than try hard to make the pre-fixup parm
>> compare equal to the post-fixup parm, we could just drop the
>> same_type_p/cp_tree_equal check in tsubst_pack_expansion and clear
>> arg_pack if the argument is an expansion of *any* parameter pack.

After looking into this a bit more, here is a patch along these lines.
When comparing an argument pack "arg_pack<P...>" [an argument pack whose
sole element is an expansion of the parameter P] with a parameter pack
P', it checks if P and P' have the same DECL. It looks like this would
be a good enough approximation, given that the instances of
"arg_pack<P...>" are created by template_parm_to_arg, AIUI.
Jason Merrill - Feb. 19, 2011, 10:38 p.m.
On 02/18/2011 11:13 AM, Dodji Seketeli wrote:
> After looking into this a bit more, here is a patch along these lines.
> When comparing an argument pack "arg_pack<P...>" [an argument pack whose
> sole element is an expansion of the parameter P] with a parameter pack
> P', it checks if P and P' have the same DECL. It looks like this would
> be a good enough approximation, given that the instances of
> "arg_pack<P...>" are created by template_parm_to_arg, AIUI.

OK, but please add something to the comment to mention having different 
types with the same decl during fixup.

Jason

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4990636..edb1465 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8717,13 +8717,24 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
         {
           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.  */
+	  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;
         }
           
diff --git a/gcc/testsuite/g++.dg/template/typedef38.C b/gcc/testsuite/g++.dg/template/typedef38.C
new file mode 100644
index 0000000..1c76404
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef38.C
@@ -0,0 +1,27 @@ 
+// Origin: PR c++/46394
+// { dg-options "-std=c++0x" }
+// { dg-do "compile" }
+
+template<class T>
+struct S0
+{
+  typedef T type;
+};
+
+template<class... X>
+struct S1
+{
+  typedef int I;
+};
+
+struct A
+{
+  template<class...U, class V=typename S1<typename S0<U>::type...>::I>
+  A(U...u);
+};
+
+int
+main()
+{
+  A a(1, 2);
+}