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;