Message ID | 20210609193406.2908473-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: matching deduced template template parameters [PR67829] | expand |
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 > >
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; >
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; > > > >
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 --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;