diff mbox series

c++: matching deduced template template parameters [PR67829]

Message ID 20210609193406.2908473-1-ppalka@redhat.com
State New
Headers show
Series c++: matching deduced template template parameters [PR67829] | expand

Commit Message

Patrick Palka June 9, 2021, 7:34 p.m. UTC
During deduction, when the template of a BOUND_TEMPLATE_TEMPLATE_PARM is
a template template parameter, we need to consider the
TEMPLATE_TEMPLATE_PARAMETER rather than the TEMPLATE_DECL thereof,
because the canonical form of a template template parameter in a
template argument list is the TEMPLATE_TEMPLATE_PARAMETER tree.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

	PR c++/67829

gcc/cp/ChangeLog:

	* pt.c (unify) <case BOUND_TEMPLATE_TEMPLATE_PARM>: When
	the TEMPLATE_DECL of a BOUND_TEMPLATE_TEMPLATE_PARM argument is
	a template template parameter, adjust to the
	TEMPLATE_TEMPLATE_PARAMETER before falling through.

gcc/testsuite/ChangeLog:

	* g++.dg/template/ttp34.C: New test.
	* g++.dg/template/ttp34a.C: New test.
	* g++.dg/template/ttp34b.C: New test.
---
 gcc/cp/pt.c                            |  4 ++++
 gcc/testsuite/g++.dg/template/ttp34.C  | 14 ++++++++++++++
 gcc/testsuite/g++.dg/template/ttp34a.C | 14 ++++++++++++++
 gcc/testsuite/g++.dg/template/ttp34b.C | 14 ++++++++++++++
 4 files changed, 46 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp34.C
 create mode 100644 gcc/testsuite/g++.dg/template/ttp34a.C
 create mode 100644 gcc/testsuite/g++.dg/template/ttp34b.C

Comments

Patrick Palka June 9, 2021, 7:56 p.m. UTC | #1
On Wed, 9 Jun 2021, Patrick Palka wrote:

> During deduction, when the template of a BOUND_TEMPLATE_TEMPLATE_PARM is

Ah sorry, this should instead say "when the template of _the argument for_
a BOUND_TEMPLATE_TEMPLATE_PARM is ..."

> a template template parameter, we need to consider the
> TEMPLATE_TEMPLATE_PARAMETER rather than the TEMPLATE_DECL thereof,
> because the canonical form of a template template parameter in a
> template argument list is the TEMPLATE_TEMPLATE_PARAMETER tree.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> 	PR c++/67829
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.c (unify) <case BOUND_TEMPLATE_TEMPLATE_PARM>: When
> 	the TEMPLATE_DECL of a BOUND_TEMPLATE_TEMPLATE_PARM argument is
> 	a template template parameter, adjust to the
> 	TEMPLATE_TEMPLATE_PARAMETER before falling through.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/template/ttp34.C: New test.
> 	* g++.dg/template/ttp34a.C: New test.
> 	* g++.dg/template/ttp34b.C: New test.
> ---
>  gcc/cp/pt.c                            |  4 ++++
>  gcc/testsuite/g++.dg/template/ttp34.C  | 14 ++++++++++++++
>  gcc/testsuite/g++.dg/template/ttp34a.C | 14 ++++++++++++++
>  gcc/testsuite/g++.dg/template/ttp34b.C | 14 ++++++++++++++
>  4 files changed, 46 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/template/ttp34.C
>  create mode 100644 gcc/testsuite/g++.dg/template/ttp34a.C
>  create mode 100644 gcc/testsuite/g++.dg/template/ttp34b.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 05679b12973..963a182b9e5 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -23555,6 +23555,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
>  	    return 1;
>  
>  	  arg = TYPE_TI_TEMPLATE (arg);
> +	  if (TREE_CODE (TREE_TYPE (arg)) == TEMPLATE_TEMPLATE_PARM)
> +	    /* If the template is a template template parameter, use the
> +	       TEMPLATE_TEMPLATE_PARM for matching.  */
> +	    arg = TREE_TYPE (arg);
>  
>  	  /* Fall through to deduce template name.  */
>  	}
> diff --git a/gcc/testsuite/g++.dg/template/ttp34.C b/gcc/testsuite/g++.dg/template/ttp34.C
> new file mode 100644
> index 00000000000..67094063ba5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/ttp34.C
> @@ -0,0 +1,14 @@
> +// PR c++/67829
> +
> +template<class> class Purr;
> +
> +template<template<class> class, class, class>
> +class Meow;
> +
> +template<template<class> class P>
> +class Meow<P, P<int>, int> { }; // 1
> +
> +template<template<class> class P, class T>
> +class Meow<P, P<int>, T>; // 2
> +
> +Meow<Purr, Purr<int>, int> kitty;
> diff --git a/gcc/testsuite/g++.dg/template/ttp34a.C b/gcc/testsuite/g++.dg/template/ttp34a.C
> new file mode 100644
> index 00000000000..e3303dcf212
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/ttp34a.C
> @@ -0,0 +1,14 @@
> +// PR c++/67829
> +
> +template<class> class Purr;
> +
> +template<template<class> class, class>
> +class Meow;
> +
> +template<template<class> class P>
> +class Meow<P, P<int> > { }; // 1
> +
> +template<template<class> class P, class T>
> +class Meow<P, P<T> >; // 2
> +
> +Meow<Purr, Purr<int> > kitty;
> diff --git a/gcc/testsuite/g++.dg/template/ttp34b.C b/gcc/testsuite/g++.dg/template/ttp34b.C
> new file mode 100644
> index 00000000000..ed3b3e8ab05
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/ttp34b.C
> @@ -0,0 +1,14 @@
> +// PR c++/67829
> +
> +template<class> class Purr;
> +
> +template<class, template<class> class>
> +class Meow;
> +
> +template<template<class> class P>
> +class Meow<P<int>, P> { }; // 1
> +
> +template<template<class> class P, class T>
> +class Meow<P<T>, P>; // 2
> +
> +Meow<Purr<int>, Purr> kitty;
> -- 
> 2.32.0.rc2
> 
>
Jason Merrill June 10, 2021, 7:12 p.m. UTC | #2
On 6/9/21 3:34 PM, Patrick Palka wrote:
> During deduction, when the template of a BOUND_TEMPLATE_TEMPLATE_PARM is
> a template template parameter, we need to consider the
> TEMPLATE_TEMPLATE_PARAMETER rather than the TEMPLATE_DECL thereof,
> because the canonical form of a template template parameter in a
> template argument list is the TEMPLATE_TEMPLATE_PARAMETER tree.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> 	PR c++/67829
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.c (unify) <case BOUND_TEMPLATE_TEMPLATE_PARM>: When
> 	the TEMPLATE_DECL of a BOUND_TEMPLATE_TEMPLATE_PARM argument is
> 	a template template parameter, adjust to the
> 	TEMPLATE_TEMPLATE_PARAMETER before falling through.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/template/ttp34.C: New test.
> 	* g++.dg/template/ttp34a.C: New test.
> 	* g++.dg/template/ttp34b.C: New test.
> ---
>   gcc/cp/pt.c                            |  4 ++++
>   gcc/testsuite/g++.dg/template/ttp34.C  | 14 ++++++++++++++
>   gcc/testsuite/g++.dg/template/ttp34a.C | 14 ++++++++++++++
>   gcc/testsuite/g++.dg/template/ttp34b.C | 14 ++++++++++++++
>   4 files changed, 46 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/template/ttp34.C
>   create mode 100644 gcc/testsuite/g++.dg/template/ttp34a.C
>   create mode 100644 gcc/testsuite/g++.dg/template/ttp34b.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 05679b12973..963a182b9e5 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -23555,6 +23555,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
>   	    return 1;
>   
>   	  arg = TYPE_TI_TEMPLATE (arg);
> +	  if (TREE_CODE (TREE_TYPE (arg)) == TEMPLATE_TEMPLATE_PARM)
> +	    /* If the template is a template template parameter, use the
> +	       TEMPLATE_TEMPLATE_PARM for matching.  */
> +	    arg = TREE_TYPE (arg);

Why don't we need the same thing for non-bound ttp unification?

>   	  /* Fall through to deduce template name.  */
>   	}
> diff --git a/gcc/testsuite/g++.dg/template/ttp34.C b/gcc/testsuite/g++.dg/template/ttp34.C
> new file mode 100644
> index 00000000000..67094063ba5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/ttp34.C
> @@ -0,0 +1,14 @@
> +// PR c++/67829
> +
> +template<class> class Purr;
> +
> +template<template<class> class, class, class>
> +class Meow;
> +
> +template<template<class> class P>
> +class Meow<P, P<int>, int> { }; // 1
> +
> +template<template<class> class P, class T>
> +class Meow<P, P<int>, T>; // 2
> +
> +Meow<Purr, Purr<int>, int> kitty;
> diff --git a/gcc/testsuite/g++.dg/template/ttp34a.C b/gcc/testsuite/g++.dg/template/ttp34a.C
> new file mode 100644
> index 00000000000..e3303dcf212
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/ttp34a.C
> @@ -0,0 +1,14 @@
> +// PR c++/67829
> +
> +template<class> class Purr;
> +
> +template<template<class> class, class>
> +class Meow;
> +
> +template<template<class> class P>
> +class Meow<P, P<int> > { }; // 1
> +
> +template<template<class> class P, class T>
> +class Meow<P, P<T> >; // 2
> +
> +Meow<Purr, Purr<int> > kitty;
> diff --git a/gcc/testsuite/g++.dg/template/ttp34b.C b/gcc/testsuite/g++.dg/template/ttp34b.C
> new file mode 100644
> index 00000000000..ed3b3e8ab05
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/ttp34b.C
> @@ -0,0 +1,14 @@
> +// PR c++/67829
> +
> +template<class> class Purr;
> +
> +template<class, template<class> class>
> +class Meow;
> +
> +template<template<class> class P>
> +class Meow<P<int>, P> { }; // 1
> +
> +template<template<class> class P, class T>
> +class Meow<P<T>, P>; // 2
> +
> +Meow<Purr<int>, Purr> kitty;
>
Patrick Palka June 10, 2021, 7:45 p.m. UTC | #3
On Thu, 10 Jun 2021, Jason Merrill wrote:

> On 6/9/21 3:34 PM, Patrick Palka wrote:
> > During deduction, when the template of a BOUND_TEMPLATE_TEMPLATE_PARM is
> > a template template parameter, we need to consider the
> > TEMPLATE_TEMPLATE_PARAMETER rather than the TEMPLATE_DECL thereof,
> > because the canonical form of a template template parameter in a
> > template argument list is the TEMPLATE_TEMPLATE_PARAMETER tree.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> > 
> > 	PR c++/67829
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* pt.c (unify) <case BOUND_TEMPLATE_TEMPLATE_PARM>: When
> > 	the TEMPLATE_DECL of a BOUND_TEMPLATE_TEMPLATE_PARM argument is
> > 	a template template parameter, adjust to the
> > 	TEMPLATE_TEMPLATE_PARAMETER before falling through.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/template/ttp34.C: New test.
> > 	* g++.dg/template/ttp34a.C: New test.
> > 	* g++.dg/template/ttp34b.C: New test.
> > ---
> >   gcc/cp/pt.c                            |  4 ++++
> >   gcc/testsuite/g++.dg/template/ttp34.C  | 14 ++++++++++++++
> >   gcc/testsuite/g++.dg/template/ttp34a.C | 14 ++++++++++++++
> >   gcc/testsuite/g++.dg/template/ttp34b.C | 14 ++++++++++++++
> >   4 files changed, 46 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/template/ttp34.C
> >   create mode 100644 gcc/testsuite/g++.dg/template/ttp34a.C
> >   create mode 100644 gcc/testsuite/g++.dg/template/ttp34b.C
> > 
> > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > index 05679b12973..963a182b9e5 100644
> > --- a/gcc/cp/pt.c
> > +++ b/gcc/cp/pt.c
> > @@ -23555,6 +23555,10 @@ unify (tree tparms, tree targs, tree parm, tree
> > arg, int strict,
> >   	    return 1;
> >     	  arg = TYPE_TI_TEMPLATE (arg);
> > +	  if (TREE_CODE (TREE_TYPE (arg)) == TEMPLATE_TEMPLATE_PARM)
> > +	    /* If the template is a template template parameter, use the
> > +	       TEMPLATE_TEMPLATE_PARM for matching.  */
> > +	    arg = TREE_TYPE (arg);
> 
> Why don't we need the same thing for non-bound ttp unification?

It seems for non-bound ttp unification, if the argument is itself a ttp
then we can rely on it always being represented as the
TEMPLATE_TEMPLATE_PARAMETER tree instead of as the TEMPLATE_DECL thereof,
so this adjustment isn't necessary.

I tested this empirically with the following assert

@@ -23566,6 +23566,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
       if (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
          || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
        {
+         if (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
+             && TREE_CODE (arg) == TEMPLATE_DECL)
+           gcc_assert (TREE_CODE (TREE_TYPE (arg)) != TEMPLATE_TEMPLATE_PARM);
          /* Deduce template name TT from TT, TT<>, TT<T> and TT<i>.  */

          /* Simple cases: Value already set, does match or doesn't.  */

which survives the testsuite.

> 
> >   	  /* Fall through to deduce template name.  */
> >   	}
> > diff --git a/gcc/testsuite/g++.dg/template/ttp34.C
> > b/gcc/testsuite/g++.dg/template/ttp34.C
> > new file mode 100644
> > index 00000000000..67094063ba5
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/ttp34.C
> > @@ -0,0 +1,14 @@
> > +// PR c++/67829
> > +
> > +template<class> class Purr;
> > +
> > +template<template<class> class, class, class>
> > +class Meow;
> > +
> > +template<template<class> class P>
> > +class Meow<P, P<int>, int> { }; // 1
> > +
> > +template<template<class> class P, class T>
> > +class Meow<P, P<int>, T>; // 2
> > +
> > +Meow<Purr, Purr<int>, int> kitty;
> > diff --git a/gcc/testsuite/g++.dg/template/ttp34a.C
> > b/gcc/testsuite/g++.dg/template/ttp34a.C
> > new file mode 100644
> > index 00000000000..e3303dcf212
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/ttp34a.C
> > @@ -0,0 +1,14 @@
> > +// PR c++/67829
> > +
> > +template<class> class Purr;
> > +
> > +template<template<class> class, class>
> > +class Meow;
> > +
> > +template<template<class> class P>
> > +class Meow<P, P<int> > { }; // 1
> > +
> > +template<template<class> class P, class T>
> > +class Meow<P, P<T> >; // 2
> > +
> > +Meow<Purr, Purr<int> > kitty;
> > diff --git a/gcc/testsuite/g++.dg/template/ttp34b.C
> > b/gcc/testsuite/g++.dg/template/ttp34b.C
> > new file mode 100644
> > index 00000000000..ed3b3e8ab05
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/ttp34b.C
> > @@ -0,0 +1,14 @@
> > +// PR c++/67829
> > +
> > +template<class> class Purr;
> > +
> > +template<class, template<class> class>
> > +class Meow;
> > +
> > +template<template<class> class P>
> > +class Meow<P<int>, P> { }; // 1
> > +
> > +template<template<class> class P, class T>
> > +class Meow<P<T>, P>; // 2
> > +
> > +Meow<Purr<int>, Purr> kitty;
> > 
> 
>
Jason Merrill June 10, 2021, 8:16 p.m. UTC | #4
On 6/10/21 3:45 PM, Patrick Palka wrote:
> On Thu, 10 Jun 2021, Jason Merrill wrote:
> 
>> On 6/9/21 3:34 PM, Patrick Palka wrote:
>>> During deduction, when the template of a BOUND_TEMPLATE_TEMPLATE_PARM is
>>> a template template parameter, we need to consider the
>>> TEMPLATE_TEMPLATE_PARAMETER rather than the TEMPLATE_DECL thereof,
>>> because the canonical form of a template template parameter in a
>>> template argument list is the TEMPLATE_TEMPLATE_PARAMETER tree.
>>>
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
>>> trunk?
>>>
>>> 	PR c++/67829
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	* pt.c (unify) <case BOUND_TEMPLATE_TEMPLATE_PARM>: When
>>> 	the TEMPLATE_DECL of a BOUND_TEMPLATE_TEMPLATE_PARM argument is
>>> 	a template template parameter, adjust to the
>>> 	TEMPLATE_TEMPLATE_PARAMETER before falling through.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 	* g++.dg/template/ttp34.C: New test.
>>> 	* g++.dg/template/ttp34a.C: New test.
>>> 	* g++.dg/template/ttp34b.C: New test.
>>> ---
>>>    gcc/cp/pt.c                            |  4 ++++
>>>    gcc/testsuite/g++.dg/template/ttp34.C  | 14 ++++++++++++++
>>>    gcc/testsuite/g++.dg/template/ttp34a.C | 14 ++++++++++++++
>>>    gcc/testsuite/g++.dg/template/ttp34b.C | 14 ++++++++++++++
>>>    4 files changed, 46 insertions(+)
>>>    create mode 100644 gcc/testsuite/g++.dg/template/ttp34.C
>>>    create mode 100644 gcc/testsuite/g++.dg/template/ttp34a.C
>>>    create mode 100644 gcc/testsuite/g++.dg/template/ttp34b.C
>>>
>>> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
>>> index 05679b12973..963a182b9e5 100644
>>> --- a/gcc/cp/pt.c
>>> +++ b/gcc/cp/pt.c
>>> @@ -23555,6 +23555,10 @@ unify (tree tparms, tree targs, tree parm, tree
>>> arg, int strict,
>>>    	    return 1;
>>>      	  arg = TYPE_TI_TEMPLATE (arg);
>>> +	  if (TREE_CODE (TREE_TYPE (arg)) == TEMPLATE_TEMPLATE_PARM)
>>> +	    /* If the template is a template template parameter, use the
>>> +	       TEMPLATE_TEMPLATE_PARM for matching.  */
>>> +	    arg = TREE_TYPE (arg);
>>
>> Why don't we need the same thing for non-bound ttp unification?
> 
> It seems for non-bound ttp unification, if the argument is itself a ttp
> then we can rely on it always being represented as the
> TEMPLATE_TEMPLATE_PARAMETER tree instead of as the TEMPLATE_DECL thereof,
> so this adjustment isn't necessary.
> 
> I tested this empirically with the following assert
> 
> @@ -23566,6 +23566,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
>         if (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
>            || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
>          {
> +         if (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
> +             && TREE_CODE (arg) == TEMPLATE_DECL)
> +           gcc_assert (TREE_CODE (TREE_TYPE (arg)) != TEMPLATE_TEMPLATE_PARM);
>            /* Deduce template name TT from TT, TT<>, TT<T> and TT<i>.  */
> 
>            /* Simple cases: Value already set, does match or doesn't.  */
> 
> which survives the testsuite.

Sounds good.  Let's use DECL_TEMPLATE_TEMPLATE_PARM_P for the test; OK 
with that change.

>>
>>>    	  /* Fall through to deduce template name.  */
>>>    	}
>>> diff --git a/gcc/testsuite/g++.dg/template/ttp34.C
>>> b/gcc/testsuite/g++.dg/template/ttp34.C
>>> new file mode 100644
>>> index 00000000000..67094063ba5
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.dg/template/ttp34.C
>>> @@ -0,0 +1,14 @@
>>> +// PR c++/67829
>>> +
>>> +template<class> class Purr;
>>> +
>>> +template<template<class> class, class, class>
>>> +class Meow;
>>> +
>>> +template<template<class> class P>
>>> +class Meow<P, P<int>, int> { }; // 1
>>> +
>>> +template<template<class> class P, class T>
>>> +class Meow<P, P<int>, T>; // 2
>>> +
>>> +Meow<Purr, Purr<int>, int> kitty;
>>> diff --git a/gcc/testsuite/g++.dg/template/ttp34a.C
>>> b/gcc/testsuite/g++.dg/template/ttp34a.C
>>> new file mode 100644
>>> index 00000000000..e3303dcf212
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.dg/template/ttp34a.C
>>> @@ -0,0 +1,14 @@
>>> +// PR c++/67829
>>> +
>>> +template<class> class Purr;
>>> +
>>> +template<template<class> class, class>
>>> +class Meow;
>>> +
>>> +template<template<class> class P>
>>> +class Meow<P, P<int> > { }; // 1
>>> +
>>> +template<template<class> class P, class T>
>>> +class Meow<P, P<T> >; // 2
>>> +
>>> +Meow<Purr, Purr<int> > kitty;
>>> diff --git a/gcc/testsuite/g++.dg/template/ttp34b.C
>>> b/gcc/testsuite/g++.dg/template/ttp34b.C
>>> new file mode 100644
>>> index 00000000000..ed3b3e8ab05
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.dg/template/ttp34b.C
>>> @@ -0,0 +1,14 @@
>>> +// PR c++/67829
>>> +
>>> +template<class> class Purr;
>>> +
>>> +template<class, template<class> class>
>>> +class Meow;
>>> +
>>> +template<template<class> class P>
>>> +class Meow<P<int>, P> { }; // 1
>>> +
>>> +template<template<class> class P, class T>
>>> +class Meow<P<T>, P>; // 2
>>> +
>>> +Meow<Purr<int>, Purr> kitty;
>>>
>>
>>
>
diff mbox series

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 05679b12973..963a182b9e5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -23555,6 +23555,10 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 	    return 1;
 
 	  arg = TYPE_TI_TEMPLATE (arg);
+	  if (TREE_CODE (TREE_TYPE (arg)) == TEMPLATE_TEMPLATE_PARM)
+	    /* If the template is a template template parameter, use the
+	       TEMPLATE_TEMPLATE_PARM for matching.  */
+	    arg = TREE_TYPE (arg);
 
 	  /* Fall through to deduce template name.  */
 	}
diff --git a/gcc/testsuite/g++.dg/template/ttp34.C b/gcc/testsuite/g++.dg/template/ttp34.C
new file mode 100644
index 00000000000..67094063ba5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp34.C
@@ -0,0 +1,14 @@ 
+// PR c++/67829
+
+template<class> class Purr;
+
+template<template<class> class, class, class>
+class Meow;
+
+template<template<class> class P>
+class Meow<P, P<int>, int> { }; // 1
+
+template<template<class> class P, class T>
+class Meow<P, P<int>, T>; // 2
+
+Meow<Purr, Purr<int>, int> kitty;
diff --git a/gcc/testsuite/g++.dg/template/ttp34a.C b/gcc/testsuite/g++.dg/template/ttp34a.C
new file mode 100644
index 00000000000..e3303dcf212
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp34a.C
@@ -0,0 +1,14 @@ 
+// PR c++/67829
+
+template<class> class Purr;
+
+template<template<class> class, class>
+class Meow;
+
+template<template<class> class P>
+class Meow<P, P<int> > { }; // 1
+
+template<template<class> class P, class T>
+class Meow<P, P<T> >; // 2
+
+Meow<Purr, Purr<int> > kitty;
diff --git a/gcc/testsuite/g++.dg/template/ttp34b.C b/gcc/testsuite/g++.dg/template/ttp34b.C
new file mode 100644
index 00000000000..ed3b3e8ab05
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ttp34b.C
@@ -0,0 +1,14 @@ 
+// PR c++/67829
+
+template<class> class Purr;
+
+template<class, template<class> class>
+class Meow;
+
+template<template<class> class P>
+class Meow<P<int>, P> { }; // 1
+
+template<template<class> class P, class T>
+class Meow<P<T>, P>; // 2
+
+Meow<Purr<int>, Purr> kitty;