commit 74510935cc6b482407a30e53ee27f6f13b8b3d0f
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Apr 5 15:39:35 2013 -0400

    	DR 1430
    	PR c++/51239
    	* pt.c (pack_expansion_args_count): Rename from
    	any_pack_expanson_args_p.
    	(coerce_template_parms): Reject pack expansion to
    	non-pack template parameter of alias template.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 82c72dd..bbaeb7d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6542,18 +6542,22 @@ coerce_template_parameter_pack (tree parms,
   return argument_pack;
 }
 
-/* Returns true if the template argument vector ARGS contains
-   any pack expansions, false otherwise.  */
+/* Returns the number of pack expansions in the template argument vector
+   ARGS.  */
 
-static bool
-any_pack_expanson_args_p (tree args)
+static int
+pack_expansion_args_count (tree args)
 {
   int i;
+  int count = 0;
   if (args)
     for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
-      if (PACK_EXPANSION_P (TREE_VEC_ELT (args, i)))
-	return true;
-  return false;
+      {
+	tree elt = TREE_VEC_ELT (args, i);
+	if (elt && PACK_EXPANSION_P (elt))
+	  ++count;
+      }
+  return count;
 }
 
 /* Convert all template arguments to their appropriate types, and
@@ -6588,6 +6592,7 @@ coerce_template_parms (tree parms,
      subtract it from nparms to get the number of non-variadic
      parameters.  */
   int variadic_p = 0;
+  int variadic_args_p = 0;
   int post_variadic_parms = 0;
 
   if (args == error_mark_node)
@@ -6617,11 +6622,14 @@ coerce_template_parms (tree parms,
   if (!post_variadic_parms)
     inner_args = expand_template_argument_pack (inner_args);
 
+  /* Count any pack expansion args.  */
+  variadic_args_p = pack_expansion_args_count (inner_args);
+
   nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
   if ((nargs > nparms && !variadic_p)
       || (nargs < nparms - variadic_p
 	  && require_all_args
-	  && !any_pack_expanson_args_p (inner_args)
+	  && !variadic_args_p
 	  && (!use_default_args
 	      || (TREE_VEC_ELT (parms, nargs) != error_mark_node
                   && !TREE_PURPOSE (TREE_VEC_ELT (parms, nargs))))))
@@ -6644,6 +6652,33 @@ coerce_template_parms (tree parms,
 
       return error_mark_node;
     }
+  /* We can't pass a pack expansion to a non-pack parameter of an alias
+     template (DR 1430).  */
+  else if (in_decl && DECL_ALIAS_TEMPLATE_P (in_decl)
+	   && variadic_args_p
+	   && nargs - variadic_args_p < nparms - variadic_p)
+    {
+      if (complain & tf_error)
+	{
+	  for (int i = 0; i < TREE_VEC_LENGTH (inner_args); ++i)
+	    {
+	      tree arg = TREE_VEC_ELT (inner_args, i);
+	      tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
+
+	      if (PACK_EXPANSION_P (arg)
+		  && !template_parameter_pack_p (parm))
+		{
+		  error ("pack expansion argument for non-pack parameter "
+			 "%qD of alias template %qD", parm, in_decl);
+		  inform (DECL_SOURCE_LOCATION (parm), "declared here");
+		  goto found;
+		}
+	    }
+	  gcc_unreachable ();
+	found:;
+	}
+      return error_mark_node;
+    }
 
   /* We need to evaluate the template arguments, even though this
      template-id may be nested within a "sizeof".  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-33.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-33.C
new file mode 100644
index 0000000..25781a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-33.C
@@ -0,0 +1,14 @@
+// PR c++/51239
+// { dg-require-effective-target c++11 }
+
+template<class... x>
+class list{};
+template<class a, class... b>
+using tail=list<b...>;
+template <class...T>
+void f(tail<T...>);		// { dg-error "alias" }
+
+int main()
+{
+  f<int,int>({});
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-37.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-37.C
new file mode 100644
index 0000000..d6a3e12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-37.C
@@ -0,0 +1,21 @@
+// PR c++/57138
+// { dg-do compile { target c++11 } }
+
+template <template <typename ... X> class T, typename ... Y>
+struct D
+{
+  template <typename ... Z>
+  using type = T <Y..., Z...>;	// { dg-error "pack expansion" }
+};
+template <typename T>
+class A {};
+template <typename X, typename Y>
+struct B;
+template <typename T>
+struct B <int, T>
+{
+  typedef A <T> type;
+};
+template <typename X, typename Y>
+using C = typename B <X, Y>::type;
+struct E : public D <C> {};

commit 42137e0d2c1a1dd949999080707a95b60266c6aa
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Aug 2 20:08:48 2013 -0400

    	DR 1286
    	* pt.c (get_underlying_template): New.
    	(convert_template_argument, lookup_template_class_1): Use it.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bbaeb7d..d03c1cf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5111,6 +5111,34 @@ alias_template_specialization_p (const_tree t)
 	  && DECL_ALIAS_TEMPLATE_P (TYPE_TI_TEMPLATE (t)));
 }
 
+/* Return either TMPL or another template that it is equivalent to under DR
+   1286: An alias that just changes the name of a template is equivalent to
+   the other template.  */
+
+static tree
+get_underlying_template (tree tmpl)
+{
+  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+  while (DECL_ALIAS_TEMPLATE_P (tmpl))
+    {
+      tree result = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+      if (TYPE_TEMPLATE_INFO (result))
+	{
+	  tree sub = TYPE_TI_TEMPLATE (result);
+	  if (PRIMARY_TEMPLATE_P (sub)
+	      && same_type_p (result, TREE_TYPE (sub)))
+	    {
+	      /* The alias type is equivalent to the pattern of the
+		 underlying template, so strip the alias.  */
+	      tmpl = sub;
+	      continue;
+	    }
+	}
+      break;
+    }
+  return tmpl;
+}
+
 /* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which
    must be a function or a pointer-to-function type, as specified
    in [temp.arg.nontype]: disambiguate EXPR if it is an overload set,
@@ -6319,6 +6347,9 @@ convert_template_argument (tree parm,
 	      tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
 	      tree argparm;
 
+	      /* Strip alias templates that are equivalent to another
+		 template.  */
+	      arg = get_underlying_template (arg);
               argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
 
 	      if (coerce_template_template_parms (parmparm, argparm,
@@ -7177,6 +7208,13 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 
   complain &= ~tf_user;
 
+  /* An alias that just changes the name of a template is equivalent to the
+     other template, so if any of the arguments are pack expansions, strip
+     the alias to avoid problems with a pack expansion passed to a non-pack
+     alias template parameter (DR 1430).  */
+  if (pack_expansion_args_count (INNERMOST_TEMPLATE_ARGS (arglist)))
+    templ = get_underlying_template (templ);
+
   if (DECL_TEMPLATE_TEMPLATE_PARM_P (templ))
     {
       /* Create a new TEMPLATE_DECL and TEMPLATE_TEMPLATE_PARM node to store
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C
index c5760cf..f38f993 100644
--- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-0.C
@@ -10,14 +10,13 @@ void g(X<Z>);
 void
 foo()
 {
-    // Below x and y don't have the same type, because Y and Z don't
-    // designate the same template ...
+    // Below x and y have the same type (DR 1286)
     X<Y> y; 
     X<Z> z;
 
-    // ... So these must fail to compile.
-    f(z);   // { dg-error "" }
-    g(y);   // { dg-error "" }
+    // ... So these must compile.
+    f(z);   // { dg-bogus "" }
+    g(y);   // { dg-bogus "" }
 }
 
 template<class> struct A0 {};
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-33a.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-33a.C
new file mode 100644
index 0000000..a1c442e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-33a.C
@@ -0,0 +1,15 @@
+// PR c++/51239
+// { dg-require-effective-target c++11 }
+// This variant should work because tail is equivalent to list.
+
+template<class y, class... x>
+class list{};
+template<class a, class... b>
+using tail=list<a, b...>;
+template <class...T>
+void f(tail<T...>);
+
+int main()
+{
+  f<int,int>({});
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286.C
new file mode 100644
index 0000000..0c545c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286.C
@@ -0,0 +1,13 @@
+// DR 1286: An alias template can be equivalent to an underlying template.
+// { dg-do compile { target c++11 } }
+
+template <class T, class U> struct same;
+template <class T> struct same<T,T> {};
+
+template <class T> struct A {};
+template <class T> using B = A<T>;
+
+template <template <class> class T> class C {};
+
+void f(C<B>) { }	    // { dg-final { scan-assembler "_Z1f1CI1AE" } }
+same<C<A>, C<B> > s;
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286a.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286a.C
new file mode 100644
index 0000000..1780c9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-dr1286a.C
@@ -0,0 +1,60 @@
+// DR 1286
+// { dg-do compile { target c++11 } }
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+template <class,class> struct different {};
+template <class T> struct different<T,T>;
+
+template<typename T, typename U = T> struct A;
+template<template <class...> class> struct X;
+
+// equivalent to A
+template<typename V, typename W>
+using B = A<V, W>;
+
+same<X<A>,X<B>> s1;
+
+// not equivalent to A: not all parameters used
+template<typename V, typename W>
+using C = A<V>;
+
+different<X<A>,X<C>> d1;
+
+// not equivalent to A: different number of parameters
+template<typename V>
+using D = A<V>;
+
+different<X<A>,X<D>> d2;
+
+// not equivalent to A: template-arguments in wrong order
+template<typename V, typename W>
+using E = A<W, V>;
+
+different<X<A>,X<E>> d3;
+
+// equivalent to A: default arguments not considered
+template<typename V, typename W = int>
+using F = A<V, W>;
+
+same<X<A>,X<F>> s2;
+
+// equivalent to A and B
+template<typename V, typename W>
+using G = A<V, W>;
+
+same<X<A>,X<G>> s3;
+same<X<B>,X<G>> s3b;
+
+// equivalent to E
+template<typename V, typename W>
+using H = E<V, W>;
+
+same<X<E>,X<H>> s4;
+
+// not equivalent to A: argument not identifier
+template<typename V, typename W>
+using I = A<V, typename W::type>;
+
+different<X<A>,X<I>> d4;
