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]
Related show

Commit Message

Marek Polacek via Gcc-patches June 9, 2021, 7:34 p.m.
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

-- 
2.32.0.rc2

Comments

Marek Polacek via Gcc-patches June 9, 2021, 7:56 p.m. | #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

> 

>
Marek Polacek via Gcc-patches June 10, 2021, 7:12 p.m. | #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;

>
Marek Polacek via Gcc-patches June 10, 2021, 7:45 p.m. | #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;

> > 

> 

>
Marek Polacek via Gcc-patches June 10, 2021, 8:16 p.m. | #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;

>>>

>>

>>

>

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;