This testcase was breaking because multiple substitutions of <Ts..., ContainerEndA> into T... would lose the original arguments when we pull the pattern out of the intermediate expansion. So the added assert guards against that happening again, and we avoid the situation by simplifying the handling of that situation: if we are substituting into a trivial expansion like T... we can just return the argument pack.

Tested x86_64-pc-linux-gnu, applying to trunk and 4.9.
commit 25baa58252bce8ac42d96710c48107df3e2c56c8
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Sep 10 21:58:58 2014 -0400

    	PR c++/63139
    	* pt.c (tsubst_pack_expansion): Simplify substitution into T....
    	(tsubst): Don't throw away PACK_EXPANSION_EXTRA_ARGS.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3c93178..7f7ab93 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9913,6 +9913,11 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 	}
     }
 
+  /* If the expansion is just T..., return the matching argument pack.  */
+  if (!unsubstituted_packs
+      && TREE_PURPOSE (packs) == pattern)
+    return ARGUMENT_PACK_ARGS (TREE_VALUE (packs));
+
   /* We cannot expand this expansion expression, because we don't have
      all of the argument packs we need.  */
   if (use_pack_expansion_extra_args_p (packs, len, unsubstituted_packs))
@@ -11831,7 +11836,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 		   gen_elem_of_pack_expansion_instantiation will
 		   build the resulting pack expansion from it.  */
 		if (PACK_EXPANSION_P (arg))
-		  arg = PACK_EXPANSION_PATTERN (arg);
+		  {
+		    /* Make sure we aren't throwing away arg info.  */
+		    gcc_assert (!PACK_EXPANSION_EXTRA_ARGS (arg));
+		    arg = PACK_EXPANSION_PATTERN (arg);
+		  }
 	      }
 	  }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic161.C b/gcc/testsuite/g++.dg/cpp0x/variadic161.C
new file mode 100644
index 0000000..ac6eaf6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic161.C
@@ -0,0 +1,51 @@
+// PR c++/63139
+// { dg-do compile { target c++11 } }
+
+template<typename ...T>
+struct type_list {};
+
+template<typename ...T>
+struct make_type_list
+{
+    using type = type_list<T...>;
+};
+
+// The bug disappears if you use make_type_list directly.
+template<typename ...T>
+using make_type_list_t = typename make_type_list<T...>::type;
+
+
+struct ContainerEndA {};
+
+template<typename ...Ts>
+struct ContainerA
+{
+    using type = make_type_list_t<Ts..., ContainerEndA>;
+};
+
+
+struct ContainerEndB {};
+
+template<typename ...Ts>
+struct ContainerB
+{
+    using type = make_type_list_t<Ts..., ContainerEndB>;
+};
+
+template<typename T, typename U>
+struct is_same
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+  static const bool value = true;
+};
+
+#define SA(X) static_assert((X), #X)
+
+SA((is_same<ContainerB<>::type, type_list<ContainerEndB>>::value));
+SA((!is_same<ContainerA<>::type, type_list<ContainerEndB>>::value));
+SA((!is_same<ContainerA<>::type, ContainerB<>::type>::value));

Reply via email to