diff mbox

C++ PATCH for c++/42329, P0522 and other template template parm issues

Message ID CADzB+2mMXqd6eCe__bpgzAy1PtMnY-VHpV-r4U1EV2cGTdtZSQ@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Dec. 21, 2016, 9:06 p.m. UTC
The first patch fixes some issues that I noticed in implementing P0522
with my earlier auto non-type parameters work.

The second patch uses deduction to confirm that a partial
specialization is more specialized than the primary template, which
catches some bugs in the testsuite that the existing checks didn't.

The third patch fixes an issue that came up in the context of P0522
with explicit arguments and variadic templates: we were incorrectly
rejecting a template template-argument because of the trailing
expansion of pack elements yet to be deduced.  This is incorrect
because they can be deduced to an empty set, making the binding
well-formed.  This fix required a change to the libstdc++ testsuite,
as the test_property overloads become ambiguous.

The fourth patch fixes 42329, where we were failing to bind a template
template-parameter to a base class of the argument type.

The last patch implements paper P0522, which resolves DR150 to clarify
that default arguments do make a template suitable as an argument to a
template template-parameter based on a new rule that the
template-parameter must be more specialized (as newly defined) than
the argument template.  This is a defect report that will apply to all
standard levels, but since we're in stage3 I limited it by default to
C++17 for GCC 7; it can also be explicitly enabled with
-fnew-ttp-matching.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 8c2a8bda53668122de62e49086b38876cde747b6
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Dec 5 11:46:13 2016 -0500

    Fixes for P0127R2 implementation.
    
            * pt.c (convert_template_argument): Pass args to do_auto_deduction.
            (mark_template_parm): Handle deducibility from type of non-type
            argument here.
            (for_each_template_parm_r): Not here.
commit e41c94be9f4303fd6714ffd594d1864a3b2255a3
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Dec 21 14:17:56 2016 -0500

    Check that a partial specialization is more specialized.
    
            * pt.c (process_partial_specialization): Use
            get_partial_spec_bindings to check that the partial specialization
            is more specialized than the primary template.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9d9c35e..8abbcfb 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -4606,9 +4606,20 @@ process_partial_specialization (tree decl)
 	     "primary template because it replaces multiple parameters "
 	     "with a pack expansion");
       inform (DECL_SOURCE_LOCATION (maintmpl), "primary template here");
+      /* Avoid crash in process_partial_specialization.  */
       return decl;
     }
 
+  /* If we aren't in a dependent class, we can actually try deduction.  */
+  else if (tpd.level == 1
+	   && !get_partial_spec_bindings (maintmpl, maintmpl, specargs))
+    {
+      if (permerror (input_location, "partial specialization %qD is not "
+		     "more specialized than", decl))
+	inform (DECL_SOURCE_LOCATION (maintmpl), "primary template %qD",
+		maintmpl);
+    }
+
   /* [temp.class.spec]
 
      A partially specialized non-type argument expression shall not
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
index 312760a..8981021 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -12,7 +12,7 @@ template<typename _Tp, _Tp v>
   };
 
 // Partial specialization.
-template<typename _Tp, _Tp v>
+template<typename _Tp, _Tp* v>
   struct A3<_Tp*, v>
   {
     typedef _Tp* value_type;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic82.C b/gcc/testsuite/g++.dg/cpp0x/variadic82.C
index f9bbc35..9ac59cd 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic82.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic82.C
@@ -3,9 +3,9 @@
 
 template<typename> struct A;
 
-template<typename... T> struct A<T*...> // { dg-bogus "cannot expand" "" }
+template<typename... T> struct A<T*...> // { dg-error "" }
 {
   struct B;
 };
 
-A<void*> a; // { dg-bogus "incomplete type" "" }
+A<void*> a;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic83.C b/gcc/testsuite/g++.dg/cpp0x/variadic83.C
index 507fc7e..c751e73 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic83.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic83.C
@@ -3,6 +3,6 @@
 
 template<typename> struct A;
 
-template<typename... T> struct A<T...> { }; // { dg-bogus "cannot expand" "" }
+template<typename... T> struct A<T...> { }; // { dg-error "" }
 
-A<int> a; // { dg-bogus "incomplete type" "" }
+A<int> a;
diff --git a/gcc/testsuite/g++.dg/template/partial5.C b/gcc/testsuite/g++.dg/template/partial5.C
index 2f400f7..1b56fb3 100644
--- a/gcc/testsuite/g++.dg/template/partial5.C
+++ b/gcc/testsuite/g++.dg/template/partial5.C
@@ -14,7 +14,7 @@ template<typename T, typename T::foo V>
 struct Y { };
 
 template<typename T, typename U, U v>
-struct Y<T, v> { }; // { dg-error "not deducible|U" "" { target { ! c++1z } } }
+struct Y<T, v> { }; // { dg-error "" }
 
 
 template<typename T, T V>
commit ab1170fe55ac0c3e460747f11a1aa6f559f49403
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Dec 15 13:29:53 2016 -0500

    Fix handling of explicit function template arguments with TTPs.
    
    gcc/cp/
            * pt.c (coerce_template_parms): Consider variadic_args_p before
            complaining about too many template arguments.
    libstdc++-v3/
            * testsuite/util/testsuite_tr1.h (test_property): Don't define both
            variadic and non-variadic overloads.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8abbcfb..f839c53 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7658,7 +7658,7 @@ coerce_template_parms (tree parms,
   variadic_args_p = pack_expansion_args_count (inner_args);
 
   nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
-  if ((nargs > nparms && !variadic_p)
+  if ((nargs - variadic_args_p > nparms && !variadic_p)
       || (nargs < nparms - variadic_p
 	  && require_all_args
 	  && !variadic_args_p
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ttp3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp3.C
new file mode 100644
index 0000000..b1bd7a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp3.C
@@ -0,0 +1,23 @@
+// Test that passing a non-variadic template to a variadic TTP works
+// with explicit template arguments in a function call..
+// { dg-do compile { target c++11 } }
+
+template<template<typename> class Property, typename Type>
+bool test_property(typename Property<Type>::value_type value);
+
+template<template<typename...> class Property,
+	 typename Type1, typename... Types>
+bool test_property(typename Property<Type1, Types...>::value_type value);
+
+template <class T>
+struct X
+{
+  using type = X;
+  using value_type = int;
+  static const value_type value = 42;
+};
+
+int main()
+{
+  test_property<X,int>(42);	// { dg-error "ambiguous" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ttp3a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp3a.C
new file mode 100644
index 0000000..b3599b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp3a.C
@@ -0,0 +1,20 @@
+// Test that passing a non-variadic template to a variadic TTP works
+// with explicit template arguments in a function call..
+// { dg-do compile { target c++11 } }
+
+template<template<typename...> class Property,
+	 typename Type1, typename... Types>
+bool test_property(typename Property<Type1, Types...>::value_type value);
+
+template <class T>
+struct X
+{
+  using type = X;
+  using value_type = int;
+  static const value_type value = 42;
+};
+
+int main()
+{
+  test_property<X,int>(42);
+}
diff --git a/libstdc++-v3/testsuite/util/testsuite_tr1.h b/libstdc++-v3/testsuite/util/testsuite_tr1.h
index c6a4986..908a788 100644
--- a/libstdc++-v3/testsuite/util/testsuite_tr1.h
+++ b/libstdc++-v3/testsuite/util/testsuite_tr1.h
@@ -45,17 +45,6 @@ namespace __gnu_test
 	      && Category<const volatile Type>::type::value == value);
     }
 
-  template<template<typename> class Property, typename Type>
-#if __cplusplus >= 201103L
-    constexpr
-#endif
-    bool
-    test_property(typename Property<Type>::value_type value)
-    {
-      return (Property<Type>::value == value
-	      && Property<Type>::type::value == value);
-    }
-
   // For testing tr1/type_traits/extent, which has a second template
   // parameter.
   template<template<typename, unsigned> class Property,
@@ -79,6 +68,14 @@ namespace __gnu_test
       return (Property<Type1, Types...>::value == value
 	      && Property<Type1, Types...>::type::value == value);
     }
+#else
+  template<template<typename> class Property, typename Type>
+    bool
+    test_property(typename Property<Type>::value_type value)
+    {
+      return (Property<Type>::value == value
+	      && Property<Type>::type::value == value);
+    }
 #endif
 
   template<template<typename, typename> class Relationship,
commit 86393f8ab80672700fece7d570e886057f711ec7
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Dec 1 15:15:35 2016 -0500

            PR c++/42329 - deducing base template for template template arg
    
            * pt.c (unify_bound_ttp_args): Split out from unify.
            (try_class_unification): Handle BOUND_TEMPLATE_TEMPLATE_PARM.
            (unify): Check for type/non-type mismatch early.
            [BOUND_TEMPLATE_TEMPLATE_PARM]: Try get_template_base.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f839c53..6abb639 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6863,6 +6863,27 @@ coerce_template_template_parm (tree parm,
   return 1;
 }
 
+/* Subroutine of unify for the case when PARM is a
+   BOUND_TEMPLATE_TEMPLATE_PARM.  */
+
+static int
+unify_bound_ttp_args (tree tparms, tree targs, tree parm, tree arg,
+		      bool explain_p)
+{
+  tree parmvec = TYPE_TI_ARGS (parm);
+  tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
+
+  /* The template template parm might be variadic and the argument
+     not, so flatten both argument lists.  */
+  parmvec = expand_template_argument_pack (parmvec);
+  argvec = expand_template_argument_pack (argvec);
+
+  if (unify (tparms, targs, parmvec, argvec,
+	     UNIFY_ALLOW_NONE, explain_p))
+    return 1;
+
+  return 0;
+}
 
 /* Return 1 if PARM_PARMS and ARG_PARMS matches using rule for
    template template parameters.  Both PARM_PARMS and ARG_PARMS are
@@ -19391,9 +19412,12 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg,
 {
   tree copy_of_targs;
 
-  if (!CLASSTYPE_TEMPLATE_INFO (arg)
-      || (most_general_template (CLASSTYPE_TI_TEMPLATE (arg))
-	  != most_general_template (CLASSTYPE_TI_TEMPLATE (parm))))
+  if (!CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
+    return NULL_TREE;
+  else if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+    /* Matches anything.  */;
+  else if (most_general_template (CLASSTYPE_TI_TEMPLATE (arg))
+	   != most_general_template (CLASSTYPE_TI_TEMPLATE (parm)))
     return NULL_TREE;
 
   /* We need to make a new template argument vector for the call to
@@ -19428,6 +19452,13 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg,
      would reject the possibility I=1.  */
   copy_of_targs = make_tree_vec (TREE_VEC_LENGTH (targs));
 
+  if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+    {
+      if (unify_bound_ttp_args (tparms, copy_of_targs, parm, arg, explain_p))
+	return NULL_TREE;
+      return arg;
+    }
+
   /* If unification failed, we're done.  */
   if (unify (tparms, copy_of_targs, CLASSTYPE_TI_ARGS (parm),
 	     CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE, explain_p))
@@ -19832,6 +19863,25 @@ unify_array_domain (tree tparms, tree targs,
 		UNIFY_ALLOW_INTEGER, explain_p);
 }
 
+/* Returns whether T, a P or A in unify, is a type, template or expression.  */
+
+enum pa_kind_t { pa_type, pa_tmpl, pa_expr };
+
+static pa_kind_t
+pa_kind (tree t)
+{
+  if (PACK_EXPANSION_P (t))
+    t = PACK_EXPANSION_PATTERN (t);
+  if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
+      || TREE_CODE (t) == UNBOUND_CLASS_TEMPLATE
+      || DECL_TYPE_TEMPLATE_P (t))
+    return pa_tmpl;
+  else if (TYPE_P (t))
+    return pa_type;
+  else
+    return pa_expr;
+}
+
 /* Deduce the value of template parameters.  TPARMS is the (innermost)
    set of template parameters to a template.  TARGS is the bindings
    for those template parameters, as determined thus far; TARGS may
@@ -19985,6 +20035,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
       return unify_success (explain_p);
     }
 
+  /* If parm and arg aren't the same kind of thing (template, type, or
+     expression), fail early.  */
+  if (pa_kind (parm) != pa_kind (arg))
+    return unify_invalid (explain_p);
+
   /* Immediately reject some pairs that won't unify because of
      cv-qualification mismatches.  */
   if (TREE_CODE (arg) == TREE_CODE (parm)
@@ -20053,100 +20108,32 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 
       if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 	{
+	  if (strict_in & UNIFY_ALLOW_DERIVED)
+	    {
+	      /* First try to match ARG directly.  */
+	      tree t = try_class_unification (tparms, targs, parm, arg,
+					      explain_p);
+	      if (!t)
+		{
+		  /* Otherwise, look for a suitable base of ARG, as below.  */
+		  enum template_base_result r;
+		  r = get_template_base (tparms, targs, parm, arg,
+					 explain_p, &t);
+		  if (!t)
+		    return unify_no_common_base (explain_p, r, parm, arg);
+		  arg = t;
+		}
+	    }
 	  /* ARG must be constructed from a template class or a template
 	     template parameter.  */
-	  if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
-	      && !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
+	  else if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
+		   && !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
 	    return unify_template_deduction_failure (explain_p, parm, arg);
-	  {
-	    tree parmvec = TYPE_TI_ARGS (parm);
-	    tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg));
-	    tree full_argvec = add_to_template_args (targs, argvec);
-	    tree parm_parms 
-              = DECL_INNERMOST_TEMPLATE_PARMS
-	          (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (parm));
-	    int i, len;
-            int parm_variadic_p = 0;
 
-	    /* The resolution to DR150 makes clear that default
-	       arguments for an N-argument may not be used to bind T
-	       to a template template parameter with fewer than N
-	       parameters.  It is not safe to permit the binding of
-	       default arguments as an extension, as that may change
-	       the meaning of a conforming program.  Consider:
+	  /* Deduce arguments T, i from TT<T> or TT<i>.  */
+	  if (unify_bound_ttp_args (tparms, targs, parm, arg, explain_p))
+	    return 1;
 
-		  struct Dense { static const unsigned int dim = 1; };
-
-		  template <template <typename> class View,
-			    typename Block>
-		  void operator+(float, View<Block> const&);
-
-		  template <typename Block,
-			    unsigned int Dim = Block::dim>
-		  struct Lvalue_proxy { operator float() const; };
-
-		  void
-		  test_1d (void) {
-		    Lvalue_proxy<Dense> p;
-		    float b;
-		    b + p;
-		  }
-
-	      Here, if Lvalue_proxy is permitted to bind to View, then
-	      the global operator+ will be used; if they are not, the
-	      Lvalue_proxy will be converted to float.  */
-	    if (coerce_template_parms (parm_parms,
-                                       full_argvec,
-				       TYPE_TI_TEMPLATE (parm),
-				       complain,
-				       /*require_all_args=*/true,
-				       /*use_default_args=*/false)
-		== error_mark_node)
-	      return 1;
-
-	    /* Deduce arguments T, i from TT<T> or TT<i>.
-	       We check each element of PARMVEC and ARGVEC individually
-	       rather than the whole TREE_VEC since they can have
-	       different number of elements.  */
-
-            parmvec = expand_template_argument_pack (parmvec);
-            argvec = expand_template_argument_pack (argvec);
-
-            len = TREE_VEC_LENGTH (parmvec);
-
-            /* Check if the parameters end in a pack, making them
-               variadic.  */
-            if (len > 0
-                && PACK_EXPANSION_P (TREE_VEC_ELT (parmvec, len - 1)))
-              parm_variadic_p = 1;
-            
-             for (i = 0; i < len - parm_variadic_p; ++i)
-	       /* If the template argument list of P contains a pack
-		  expansion that is not the last template argument, the
-		  entire template argument list is a non-deduced
-		  context.  */
-	       if (PACK_EXPANSION_P (TREE_VEC_ELT (parmvec, i)))
-		 return unify_success (explain_p);
-
-            if (TREE_VEC_LENGTH (argvec) < len - parm_variadic_p)
-              return unify_too_few_arguments (explain_p,
-					      TREE_VEC_LENGTH (argvec), len);
-
-             for (i = 0; i < len - parm_variadic_p; ++i)
-	      {
-		RECUR_AND_CHECK_FAILURE (tparms, targs,
-					 TREE_VEC_ELT (parmvec, i),
-					 TREE_VEC_ELT (argvec, i),
-					 UNIFY_ALLOW_NONE, explain_p);
-	      }
-
-	    if (parm_variadic_p
-		&& unify_pack_expansion (tparms, targs,
-					 parmvec, argvec,
-					 DEDUCE_EXACT,
-					 /*subr=*/true, explain_p))
-	      return 1;
-	  }
 	  arg = TYPE_TI_TEMPLATE (arg);
 
 	  /* Fall through to deduce template name.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C
index cf59a55..b70b7d4 100644
--- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C
@@ -22,7 +22,7 @@ template<class T> using Vec = Vector<T, Alloc<T> >;
 
 template<class T> void g(Vector<T, Alloc<T> >);
 
-template<template<class T> class TT> void h(TT<int>); // { dg-message "provided for" }
+template<template<class T> class TT> void h(TT<int>); // { dg-message "" }
 
 void
 bar()
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ttp6.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp6.C
new file mode 100644
index 0000000..cf70a7a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp6.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++11 } }
+
+template <class T> struct A { using type = T; };
+template <template <class...> class C, class... Ts>
+struct A<C<Ts...>> { };
+
+template <class T2, template <class> class TT> struct B { };
+template <class T3> struct C { };
+
+A<B<int,C>>::type a;
diff --git a/gcc/testsuite/g++.dg/template/ttp-derived1.C b/gcc/testsuite/g++.dg/template/ttp-derived1.C
new file mode 100644
index 0000000..4238eef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp-derived1.C
@@ -0,0 +1,12 @@
+// PR c++/60177
+
+template<class> struct Base { };
+
+struct Derived : Base<void> { };
+
+template<template<typename> class TT, typename T>
+void func (TT<T>) { }
+
+int main () {
+  func (Derived ());
+}
diff --git a/gcc/testsuite/g++.dg/template/ttp-derived2.C b/gcc/testsuite/g++.dg/template/ttp-derived2.C
new file mode 100644
index 0000000..b2fe36f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp-derived2.C
@@ -0,0 +1,16 @@
+// PR c++/42329
+
+template <typename T1, typename T2>
+class B {};
+
+template <typename T>
+class D : public B<T, T> {};
+
+template <template <typename, typename> class U, typename T1, typename T2>
+void g(U<T1, T2>*) {}
+
+int main()
+{
+  D<long> dl;
+  g(&dl); // error: no matching function for call to ‘g(D<long int>*)’
+}
commit e365fd242fdeeea879ff098081c19490241c05bb
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Dec 2 13:38:29 2016 -0500

            Implement P0522R0, matching of template template arguments.
    
    gcc/c-family/
            * c.opt (-fnew-ttp-matching): New flag.
            * c-opts.c (c_common_post_options): Default on if -std=c++1z.
    gcc/cp/
            * pt.c (coerce_template_template_parms): Allow a template argument
            that's less specialized than the parameter.
            (unify_bound_ttp_args): Adjust parm's args to apply to arg's
            template.
            (coerce_template_args_for_ttp): Split out from
            lookup_template_class_1.
            (coerce_ttp_args_for_tta, store_defaulted_ttp)
            (lookup_defaulted_ttp, add_defaults_to_ttp): New.
            (process_partial_specialization): Set DECL_CONTEXT of
            template template-parameters.
            (coerce_template_parms): Only inform when complain.
            (expand_template_argument_pack): Handle error_mark_node.
            (convert_template_argument, template_args_equal, unify): Handle
            any_targ_node.
            * cp-tree.h (enum cp_tree_index): Add CPTI_ANY_TARG.
            (any_targ_node): New.
            * decl.c (cxx_init_decl_processing): Set it.
            * name-lookup.c (consider_binding_level): Ignore names with embedded
            spaces.

diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 57717ff..62d2f46 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -920,6 +920,10 @@ c_common_post_options (const char **pfilename)
   if (!global_options_set.x_flag_new_inheriting_ctors)
     flag_new_inheriting_ctors = abi_version_at_least (11);
 
+  /* For GCC 7, only enable DR150 resolution by default if -std=c++1z.  */
+  if (!global_options_set.x_flag_new_ttp)
+    flag_new_ttp = (cxx_dialect >= cxx1z);
+
   if (cxx_dialect >= cxx11)
     {
       /* If we're allowing C++0x constructs, don't warn about C++98
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 33c5def..a5333a3 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1443,6 +1443,10 @@ C++ ObjC++ Joined Ignore Warn(switch %qs is no longer supported)
 fnew-abi
 C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
 
+fnew-ttp-matching
+C++ ObjC++ Var(flag_new_ttp)
+Implement resolution of DR 150 for matching of template template arguments.
+
 fnext-runtime
 ObjC ObjC++ LTO Report RejectNegative Var(flag_next_runtime)
 Generate code for NeXT (Apple Mac OS X) runtime environment.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 89bb9b2..ef6265e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1140,6 +1140,8 @@ enum cp_tree_index
 
     CPTI_ALIGN_TYPE,
 
+    CPTI_ANY_TARG,
+
     CPTI_MAX
 };
 
@@ -1245,6 +1247,9 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 
 #define keyed_classes			cp_global_trees[CPTI_KEYED_CLASSES]
 
+/* A node which matches any template argument.  */
+#define any_targ_node			cp_global_trees[CPTI_ANY_TARG]
+
 /* Node to indicate default access. This must be distinct from the
    access nodes in tree.h.  */
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2954160..e70b34c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4161,6 +4161,9 @@ cxx_init_decl_processing (void)
   global_type_node = make_node (LANG_TYPE);
   record_unknown_type (global_type_node, "global type");
 
+  any_targ_node = make_node (LANG_TYPE);
+  record_unknown_type (any_targ_node, "any type");
+
   /* Now, C++.  */
   current_lang_name = lang_name_cplusplus;
 
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index d80c031..a0cadb8 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -4758,8 +4758,10 @@ consider_binding_level (tree name, best_match <tree, tree> &bm,
 	  && DECL_ANTICIPATED (d))
 	continue;
 
-      if (DECL_NAME (d))
-	bm.consider (DECL_NAME (d));
+      if (tree name = DECL_NAME (d))
+	/* Ignore internal names with spaces in them.  */
+	if (!strchr (IDENTIFIER_POINTER (name), ' '))
+	  bm.consider (DECL_NAME (d));
     }
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6abb639..301eb52 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3836,6 +3836,9 @@ check_for_bare_parameter_packs (tree t)
 tree
 expand_template_argument_pack (tree args)
 {
+  if (args == error_mark_node)
+    return error_mark_node;
+
   tree result_args = NULL_TREE;
   int in_arg, out_arg = 0, nargs = args ? TREE_VEC_LENGTH (args) : 0;
   int num_result_args = -1;
@@ -4758,6 +4761,15 @@ process_partial_specialization (tree decl)
   DECL_TEMPLATE_INFO (tmpl) = build_template_info (maintmpl, specargs);
   DECL_PRIMARY_TEMPLATE (tmpl) = maintmpl;
 
+  /* Give template template parms a DECL_CONTEXT of the template
+     for which they are a parameter.  */
+  for (i = 0; i < ntparms; ++i)
+    {
+      tree parm = TREE_VALUE (TREE_VEC_ELT (inner_parms, i));
+      if (TREE_CODE (parm) == TEMPLATE_DECL)
+	DECL_CONTEXT (parm) = tmpl;
+    }
+
   if (VAR_P (decl))
     /* We didn't register this in check_explicit_specialization so we could
        wait until the constraints were set.  */
@@ -6863,11 +6875,164 @@ coerce_template_template_parm (tree parm,
   return 1;
 }
 
+/* Coerce template argument list ARGLIST for use with template
+   template-parameter TEMPL.  */
+
+static tree
+coerce_template_args_for_ttp (tree templ, tree arglist,
+			      tsubst_flags_t complain)
+{
+  /* Consider an example where a template template parameter declared as
+
+     template <class T, class U = std::allocator<T> > class TT
+
+     The template parameter level of T and U are one level larger than
+     of TT.  To proper process the default argument of U, say when an
+     instantiation `TT<int>' is seen, we need to build the full
+     arguments containing {int} as the innermost level.  Outer levels,
+     available when not appearing as default template argument, can be
+     obtained from the arguments of the enclosing template.
+
+     Suppose that TT is later substituted with std::vector.  The above
+     instantiation is `TT<int, std::allocator<T> >' with TT at
+     level 1, and T at level 2, while the template arguments at level 1
+     becomes {std::vector} and the inner level 2 is {int}.  */
+
+  tree outer = DECL_CONTEXT (templ);
+  if (outer)
+    {
+      if (DECL_TEMPLATE_SPECIALIZATION (outer))
+	/* We want arguments for the partial specialization, not arguments for
+	   the primary template.  */
+	outer = template_parms_to_args (DECL_TEMPLATE_PARMS (outer));
+      else
+	outer = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (outer)));
+    }
+  else if (current_template_parms)
+    {
+      /* This is an argument of the current template, so we haven't set
+	 DECL_CONTEXT yet.  */
+      tree relevant_template_parms;
+
+      /* Parameter levels that are greater than the level of the given
+	 template template parm are irrelevant.  */
+      relevant_template_parms = current_template_parms;
+      while (TMPL_PARMS_DEPTH (relevant_template_parms)
+	     != TEMPLATE_TYPE_LEVEL (TREE_TYPE (templ)))
+	relevant_template_parms = TREE_CHAIN (relevant_template_parms);
+
+      outer = template_parms_to_args (relevant_template_parms);
+    }
+
+  if (outer)
+    arglist = add_to_template_args (outer, arglist);
+
+  tree parmlist = DECL_INNERMOST_TEMPLATE_PARMS (templ);
+  return coerce_template_parms (parmlist, arglist, templ,
+				complain,
+				/*require_all_args=*/true,
+				/*use_default_args=*/true);
+}
+
+/* A cache of template template parameters with match-all default
+   arguments.  */
+static GTY((deletable)) hash_map<tree,tree> *defaulted_ttp_cache;
+static void
+store_defaulted_ttp (tree v, tree t)
+{
+  if (!defaulted_ttp_cache)
+    defaulted_ttp_cache = hash_map<tree,tree>::create_ggc (13);
+  defaulted_ttp_cache->put (v, t);
+}
+static tree
+lookup_defaulted_ttp (tree v)
+{
+  if (defaulted_ttp_cache)
+    if (tree *p = defaulted_ttp_cache->get (v))
+      return *p;
+  return NULL_TREE;
+}
+
+/* T is a bound template template-parameter.  Copy its arguments into default
+   arguments of the template template-parameter's template parameters.  */
+
+static tree
+add_defaults_to_ttp (tree otmpl)
+{
+  if (tree c = lookup_defaulted_ttp (otmpl))
+    return c;
+
+  tree ntmpl = copy_node (otmpl);
+
+  tree ntype = copy_node (TREE_TYPE (otmpl));
+  TYPE_STUB_DECL (ntype) = TYPE_NAME (ntype) = ntmpl;
+  TYPE_MAIN_VARIANT (ntype) = ntype;
+  TYPE_POINTER_TO (ntype) = TYPE_REFERENCE_TO (ntype) = NULL_TREE;
+  TYPE_NAME (ntype) = ntmpl;
+  SET_TYPE_STRUCTURAL_EQUALITY (ntype);
+
+  tree idx = TEMPLATE_TYPE_PARM_INDEX (ntype)
+    = copy_node (TEMPLATE_TYPE_PARM_INDEX (ntype));
+  TEMPLATE_PARM_DECL (idx) = ntmpl;
+  TREE_TYPE (ntmpl) = TREE_TYPE (idx) = ntype;
+
+  tree oparms = DECL_TEMPLATE_PARMS (otmpl);
+  tree parms = DECL_TEMPLATE_PARMS (ntmpl) = copy_node (oparms);
+  TREE_CHAIN (parms) = TREE_CHAIN (oparms);
+  tree vec = TREE_VALUE (parms) = copy_node (TREE_VALUE (parms));
+  for (int i = 0; i < TREE_VEC_LENGTH (vec); ++i)
+    {
+      tree o = TREE_VEC_ELT (vec, i);
+      if (!template_parameter_pack_p (TREE_VALUE (o)))
+	{
+	  tree n = TREE_VEC_ELT (vec, i) = copy_node (o);
+	  TREE_PURPOSE (n) = any_targ_node;
+	}
+    }
+
+  store_defaulted_ttp (otmpl, ntmpl);
+  return ntmpl;
+}
+
+/* ARG is a bound potential template template-argument, and PARGS is a list
+   of arguments for the corresponding template template-parameter.  Adjust
+   PARGS as appropriate for application to ARG's template, and if ARG is a
+   BOUND_TEMPLATE_TEMPLATE_PARM, possibly adjust it to add default template
+   arguments to the template template parameter.  */
+
+static tree
+coerce_ttp_args_for_tta (tree& arg, tree pargs, tsubst_flags_t complain)
+{
+  ++processing_template_decl;
+  tree arg_tmpl = TYPE_TI_TEMPLATE (arg);
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
+    {
+      /* When comparing two template template-parameters in partial ordering,
+	 rewrite the one currently being used as an argument to have default
+	 arguments for all parameters.  */
+      arg_tmpl = add_defaults_to_ttp (arg_tmpl);
+      pargs = coerce_template_args_for_ttp (arg_tmpl, pargs, complain);
+      if (pargs != error_mark_node)
+	arg = bind_template_template_parm (TREE_TYPE (arg_tmpl),
+					   TYPE_TI_ARGS (arg));
+    }
+  else
+    {
+      tree aparms
+	= INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (arg_tmpl));
+      pargs = coerce_template_parms (aparms, pargs, arg_tmpl, complain,
+				       /*require_all*/true,
+				       /*use_default*/true);
+    }
+  --processing_template_decl;
+  return pargs;
+}
+
 /* Subroutine of unify for the case when PARM is a
    BOUND_TEMPLATE_TEMPLATE_PARM.  */
 
 static int
-unify_bound_ttp_args (tree tparms, tree targs, tree parm, tree arg,
+unify_bound_ttp_args (tree tparms, tree targs, tree parm, tree& arg,
 		      bool explain_p)
 {
   tree parmvec = TYPE_TI_ARGS (parm);
@@ -6878,10 +7043,27 @@ unify_bound_ttp_args (tree tparms, tree targs, tree parm, tree arg,
   parmvec = expand_template_argument_pack (parmvec);
   argvec = expand_template_argument_pack (argvec);
 
-  if (unify (tparms, targs, parmvec, argvec,
+  tree nparmvec = parmvec;
+  if (flag_new_ttp)
+    {
+      /* In keeping with P0522R0, adjust P's template arguments
+	 to apply to A's template; then flatten it again.  */
+      nparmvec = coerce_ttp_args_for_tta (arg, parmvec, tf_none);
+      nparmvec = expand_template_argument_pack (nparmvec);
+    }
+
+  if (unify (tparms, targs, nparmvec, argvec,
 	     UNIFY_ALLOW_NONE, explain_p))
     return 1;
 
+  /* If the P0522 adjustment eliminated a pack expansion, deduce
+     empty packs.  */
+  if (flag_new_ttp
+      && TREE_VEC_LENGTH (nparmvec) < TREE_VEC_LENGTH (parmvec)
+      && unify_pack_expansion (tparms, targs, parmvec, argvec,
+			       DEDUCE_EXACT, /*sub*/true, explain_p))
+    return 1;
+
   return 0;
 }
 
@@ -6914,6 +7096,48 @@ coerce_template_template_parms (tree parm_parms,
   nparms = TREE_VEC_LENGTH (parm_parms);
   nargs = TREE_VEC_LENGTH (arg_parms);
 
+  if (flag_new_ttp)
+    {
+      /* P0522R0: A template template-parameter P is at least as specialized as
+	 a template template-argument A if, given the following rewrite to two
+	 function templates, the function template corresponding to P is at
+	 least as specialized as the function template corresponding to A
+	 according to the partial ordering rules for function templates
+	 ([temp.func.order]). Given an invented class template X with the
+	 template parameter list of A (including default arguments):
+
+	 * Each of the two function templates has the same template parameters,
+	 respectively, as P or A.
+
+	 * Each function template has a single function parameter whose type is
+	 a specialization of X with template arguments corresponding to the
+	 template parameters from the respective function template where, for
+	 each template parameter PP in the template parameter list of the
+	 function template, a corresponding template argument AA is formed. If
+	 PP declares a parameter pack, then AA is the pack expansion
+	 PP... ([temp.variadic]); otherwise, AA is the id-expression PP.
+
+	 If the rewrite produces an invalid type, then P is not at least as
+	 specialized as A.  */
+
+      /* So coerce P's args to apply to A's parms, and then deduce between A's
+	 args and the converted args.  If that succeeds, A is at least as
+	 specialized as P, so they match.*/
+      tree pargs = template_parms_level_to_args (parm_parms);
+      ++processing_template_decl;
+      pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none,
+				     /*require_all*/true, /*use_default*/true);
+      --processing_template_decl;
+      if (pargs != error_mark_node)
+	{
+	  tree targs = make_tree_vec (nargs);
+	  tree aargs = template_parms_level_to_args (arg_parms);
+	  if (!unify (arg_parms, targs, aargs, pargs, UNIFY_ALLOW_NONE,
+		      /*explain*/false))
+	    return 1;
+	}
+    }
+
   /* Determine whether we have a parameter pack at the end of the
      template template parameter's template parameter list.  */
   if (TREE_VEC_ELT (parm_parms, nparms - 1) != error_mark_node)
@@ -7172,6 +7396,9 @@ convert_template_argument (tree parm,
   if (TREE_CODE (arg) == WILDCARD_DECL)
     return convert_wildcard_argument (parm, arg);
 
+  if (arg == any_targ_node)
+    return arg;
+
   if (TREE_CODE (arg) == TREE_LIST
       && TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)
     {
@@ -7822,8 +8049,9 @@ coerce_template_parms (tree parms,
 						     in_decl);
 	      if (conv == error_mark_node)
 		{
-		  inform (input_location, "so any instantiation with a "
-			 "non-empty parameter pack would be ill-formed");
+		  if (complain & tf_error)
+		    inform (input_location, "so any instantiation with a "
+			    "non-empty parameter pack would be ill-formed");
 		  ++lost;
 		}
 	      else if (TYPE_P (conv) && !TYPE_P (pattern))
@@ -7987,6 +8215,8 @@ template_args_equal (tree ot, tree nt)
     return 1;
   if (nt == NULL_TREE || ot == NULL_TREE)
     return false;
+  if (nt == any_targ_node || ot == any_targ_node)
+    return true;
 
   if (TREE_CODE (nt) == TREE_VEC)
     /* For member templates */
@@ -8328,57 +8558,8 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 
   if (DECL_TEMPLATE_TEMPLATE_PARM_P (templ))
     {
-      /* Create a new TEMPLATE_DECL and TEMPLATE_TEMPLATE_PARM node to store
-	 template arguments */
-
       tree parm;
-      tree arglist2;
-      tree outer;
-
-      parmlist = DECL_INNERMOST_TEMPLATE_PARMS (templ);
-
-      /* Consider an example where a template template parameter declared as
-
-	   template <class T, class U = std::allocator<T> > class TT
-
-	 The template parameter level of T and U are one level larger than
-	 of TT.  To proper process the default argument of U, say when an
-	 instantiation `TT<int>' is seen, we need to build the full
-	 arguments containing {int} as the innermost level.  Outer levels,
-	 available when not appearing as default template argument, can be
-	 obtained from the arguments of the enclosing template.
-
-	 Suppose that TT is later substituted with std::vector.  The above
-	 instantiation is `TT<int, std::allocator<T> >' with TT at
-	 level 1, and T at level 2, while the template arguments at level 1
-	 becomes {std::vector} and the inner level 2 is {int}.  */
-
-      outer = DECL_CONTEXT (templ);
-      if (outer)
-	outer = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (outer)));
-      else if (current_template_parms)
-	{
-	  /* This is an argument of the current template, so we haven't set
-	     DECL_CONTEXT yet.  */
-	  tree relevant_template_parms;
-
-	  /* Parameter levels that are greater than the level of the given
-	     template template parm are irrelevant.  */
-	  relevant_template_parms = current_template_parms;
-	  while (TMPL_PARMS_DEPTH (relevant_template_parms)
-		 != TEMPLATE_TYPE_LEVEL (TREE_TYPE (templ)))
-	    relevant_template_parms = TREE_CHAIN (relevant_template_parms);
-
-	  outer = template_parms_to_args (relevant_template_parms);
-	}
-
-      if (outer)
-	arglist = add_to_template_args (outer, arglist);
-
-      arglist2 = coerce_template_parms (parmlist, arglist, templ,
-					complain,
-					/*require_all_args=*/true,
-					/*use_default_args=*/true);
+      tree arglist2 = coerce_template_args_for_ttp (templ, arglist, complain);
       if (arglist2 == error_mark_node
 	  || (!uses_template_parms (arglist2)
 	      && check_instantiated_args (templ, arglist2, complain)))
@@ -19950,6 +20131,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
        template args from other function args.  */
     return unify_success (explain_p);
 
+  if (parm == any_targ_node || arg == any_targ_node)
+    return unify_success (explain_p);
+
   /* If PARM uses template parameters, then we can't bail out here,
      even if ARG == PARM, since we won't record unifications for the
      template parameters.  We might need them if we're trying to
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5c92fe6..1096254 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -201,6 +201,7 @@ in the following sections.
 -fno-implicit-inline-templates @gol
 -fno-implement-inlines  -fms-extensions @gol
 -fnew-inheriting-ctors @gol
+-fnew-ttp-matching @gol
 -fno-nonansi-builtins  -fnothrow-opt  -fno-operator-names @gol
 -fno-optional-diags  -fpermissive @gol
 -fno-pretty-templates @gol
@@ -2455,6 +2456,14 @@ inheritance.  This is part of C++17 but also considered to be a Defect
 Report against C++11 and C++14.  This flag is enabled by default
 unless @option{-fabi-version=10} or lower is specified.
 
+@item -fnew-ttp-matching
+@opindex fnew-ttp-matching
+Enable the P0522 resolution to Core issue 150, template template
+parameters and default arguments: this allows a template with default
+template arguments as an argument for a template template parameter
+with fewer template parameters.  This flag is enabled by default for
+@option{-std=c++1z}.
+
 @item -fno-nonansi-builtins
 @opindex fno-nonansi-builtins
 Disable built-in declarations of functions that are not mandated by
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ex14.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ex14.C
index e301e7a..5ec05cd 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic-ex14.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ex14.C
@@ -1,5 +1,5 @@
 // { dg-do compile { target c++11 } }
-
+// { dg-options -fno-new-ttp-matching }
 template<class T> class A { /* ... */ };
 template<class T, class U = T> class B { /* ... */ };
 template<class... Types> class C { /* ... */ };
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ex14a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ex14a.C
new file mode 100644
index 0000000..8887033
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ex14a.C
@@ -0,0 +1,24 @@
+// CWG 150: Matching of template template-arguments excludes compatible
+// templates
+// { dg-options -fnew-ttp-matching }
+
+template<class T> class A { /* ... */ };
+template<class T, class U = T> class B { /* ... */ };
+template<template<class> class P> class X { /* ... */ };
+X<A> xa; // OK
+X<B> xb; // OK since P0522R0
+
+#if __cpp_variadic_templates
+template <class ... Types> class C { /* ... */ };
+template<template<class ...> class Q> class Y { /* ... */ };
+X<C> xc; // OK since P0522R0
+Y<A> ya; // OK
+Y<B> yb; // OK
+Y<C> yc; // OK
+#endif
+
+#if __cpp_template_auto
+template<auto n> class D { /* ... */ };
+template<template<int> class R> class Z { /* ... */ };
+Z<D> zd; // OK
+#endif
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ttp4.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp4.C
new file mode 100644
index 0000000..72cff38
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp4.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++11 } }
+
+template<typename _Tp>
+struct get_first_arg;
+
+template<template<typename, typename...> class _Template, typename _Tp,
+	 typename... _Types>
+struct get_first_arg<_Template<_Tp, _Types...>>
+{ using type = _Tp; };
+
+template<typename T> struct A { };
+
+template<class,class> struct same;
+template<class T> struct same<T,T> {};
+
+same<get_first_arg<A<int>>::type,
+     int> x;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ttp5.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp5.C
new file mode 100644
index 0000000..43f951a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ttp5.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++11 } }
+
+template <typename, typename> struct A { };
+template <typename T> struct B { };
+
+template <typename T, template <T...> class C, T... Is>
+struct A<B<T>, C<Is...>>
+{
+  using type = C<Is...>;
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic79.C b/gcc/testsuite/g++.dg/cpp0x/variadic79.C
index 389199c..ed5e028 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic79.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic79.C
@@ -1,5 +1,6 @@
 // PR c++/33213
 // { dg-do compile { target c++11 } }
+// { dg-options -fno-new-ttp-matching }
 
 template<template<typename> class...> struct A;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic79a.C b/gcc/testsuite/g++.dg/cpp0x/variadic79a.C
new file mode 100644
index 0000000..67376cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic79a.C
@@ -0,0 +1,7 @@
+// PR c++/33213
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-ttp-matching }
+
+template<template<typename> class...> struct A;
+
+template<template<typename...> class... B> struct A<B...> {};
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic85.C b/gcc/testsuite/g++.dg/cpp0x/variadic85.C
index 708104a..c1d6ab9 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic85.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic85.C
@@ -1,5 +1,6 @@
 // PR c++/32565
 // { dg-do compile { target c++11 } }
+// { dg-options -fno-new-ttp-matching }
 
 template<typename...> struct A1;
 template<template<int, int...> class T> struct A1<T<0, 1> > {};
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic85a.C b/gcc/testsuite/g++.dg/cpp0x/variadic85a.C
new file mode 100644
index 0000000..b3cfeee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic85a.C
@@ -0,0 +1,10 @@
+// PR c++/32565
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-ttp-matching }
+
+template<typename...> struct A1;
+template<template<int, int...> class T> struct A1<T<0, 1> > {};
+template<int, int, int...> struct B1 {};
+A1<B1<0, 1> > a1;
+template<int...> struct B2 {};
+A1<B2<0, 1> > a2;
diff --git a/gcc/testsuite/g++.dg/cpp1z/ttp1.C b/gcc/testsuite/g++.dg/cpp1z/ttp1.C
new file mode 100644
index 0000000..7577b5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/ttp1.C
@@ -0,0 +1,19 @@
+// CWG 150: Matching of template template-arguments excludes compatible
+// templates
+
+// { dg-options -fnew-ttp-matching }
+
+template<class T, class U = T> class B { /* ... */ };
+#if __cpp_variadic_templates
+template <class ... Types> class C { /* ... */ };
+#endif
+template<template<class> class P, class T> void f(P<T>);
+
+int main()
+{
+  f(B<int>());
+  f(B<int,float>());		// { dg-error "no match" }
+#if __cpp_variadic_templates
+  f(C<int>());
+#endif
+}
diff --git a/gcc/testsuite/g++.dg/template/ttp16.C b/gcc/testsuite/g++.dg/template/ttp16.C
index c556c7d..510ef65 100644
--- a/gcc/testsuite/g++.dg/template/ttp16.C
+++ b/gcc/testsuite/g++.dg/template/ttp16.C
@@ -1,3 +1,5 @@
+// { dg-options -fno-new-ttp-matching }
+
 template <template <typename> class C>
 void f() {}
 
diff --git a/gcc/testsuite/g++.dg/template/ttp16a.C b/gcc/testsuite/g++.dg/template/ttp16a.C
new file mode 100644
index 0000000..0ecada1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp16a.C
@@ -0,0 +1,9 @@
+// { dg-options -fnew-ttp-matching }
+
+template <template <typename> class C>
+void f() {}
+
+template <typename T, typename U = int>
+struct S {};
+
+template void f<S>();
diff --git a/gcc/testsuite/g++.dg/template/ttp17.C b/gcc/testsuite/g++.dg/template/ttp17.C
index f1ddeb1..cc9bc6e 100644
--- a/gcc/testsuite/g++.dg/template/ttp17.C
+++ b/gcc/testsuite/g++.dg/template/ttp17.C
@@ -1,3 +1,5 @@
+// { dg-options -fno-new-ttp-matching }
+
 template <template <typename> class C>
 void f(C<double>) {}
 
diff --git a/gcc/testsuite/g++.dg/template/ttp17a.C b/gcc/testsuite/g++.dg/template/ttp17a.C
new file mode 100644
index 0000000..3bd0b0c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp17a.C
@@ -0,0 +1,9 @@
+// { dg-options -fnew-ttp-matching }
+
+template <template <typename> class C>
+void f(C<double>) {}
+
+template <typename T, typename U = int>
+struct S {};
+
+template void f(S<double>);
diff --git a/gcc/testsuite/g++.dg/torture/pr68220.C b/gcc/testsuite/g++.dg/torture/pr68220.C
index 3b27653..9522e2f 100644
--- a/gcc/testsuite/g++.dg/torture/pr68220.C
+++ b/gcc/testsuite/g++.dg/torture/pr68220.C
@@ -1,3 +1,4 @@
+// { dg-options -fno-new-ttp-matching }
 // { dg-do compile }
 namespace mpl {
 template <typename, typename = int> struct lambda;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ttp49.C b/gcc/testsuite/g++.old-deja/g++.pt/ttp49.C
index 8449849..c60a160 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ttp49.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ttp49.C
@@ -1,4 +1,4 @@
-// { dg-do assemble  }
+// { dg-options -fno-new-ttp-matching }
 
 template <int i> class C {};
 template <template <long> class TT> class D {};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ttp49a.C b/gcc/testsuite/g++.old-deja/g++.pt/ttp49a.C
new file mode 100644
index 0000000..88a1c50
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ttp49a.C
@@ -0,0 +1,9 @@
+// { dg-options -fnew-ttp-matching }
+
+template <int i> class C {};
+template <template <long> class TT> class D {};
+
+int main()
+{
+  D<C> d;
+}
diff mbox

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 91178ea..9d9c35e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -4467,6 +4467,15 @@  mark_template_parm (tree t, void* data)
       tpd->arg_uses_template_parms[tpd->current_arg] = 1;
     }
 
+  /* In C++17 the type of a non-type argument is a deduced context.  */
+  if (cxx_dialect >= cxx1z
+      && TREE_CODE (t) == TEMPLATE_PARM_INDEX)
+    for_each_template_parm (TREE_TYPE (t),
+			    &mark_template_parm,
+			    data,
+			    NULL,
+			    /*include_nondeduced_p=*/false);
+
   /* Return zero so that for_each_template_parm will continue the
      traversal of the tree; we want to mark *every* template parm.  */
   return 0;
@@ -7328,14 +7337,16 @@  convert_template_argument (tree parm,
     }
   else
     {
-      tree t = tsubst (TREE_TYPE (parm), args, complain, in_decl);
+      tree t = TREE_TYPE (parm);
 
       if (tree a = type_uses_auto (t))
 	{
-	  t = do_auto_deduction (t, arg, a, complain, adc_unspecified);
+	  t = do_auto_deduction (t, arg, a, complain, adc_unify, args);
 	  if (t == error_mark_node)
 	    return error_mark_node;
 	}
+      else
+	t = tsubst (t, args, complain, in_decl);
 
       if (invalid_nontype_parm_type_p (t, complain))
 	return error_mark_node;
@@ -8956,12 +8967,6 @@  for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
 	return t;
       else if (!fn)
 	return t;
-
-      /* In C++17 we can deduce a type argument from the type of a non-type
-	 argument.  */
-      if (cxx_dialect >= cxx1z
-	  && TREE_CODE (t) == TEMPLATE_PARM_INDEX)
-	WALK_SUBTREE (TREE_TYPE (t));
       break;
 
     case TEMPLATE_DECL: