[PATCH] c++: unqualified member template in constraint [PR101247]
Patrick Palka
ppalka@redhat.com
Thu Jul 1 15:33:07 GMT 2021
On Thu, 1 Jul 2021, Jason Merrill wrote:
> On 6/30/21 5:27 PM, Patrick Palka wrote:
> > Here any_template_parm_r is failing to mark the template parameters
> > that're implicitly used by the unqualified use of 'd' inside the constraint,
> > because the code to do so assumes each level of a template parameter
> > list points to the corresponding primary template, but here the
> > parameter level for A in the out-of-line definition of A::B does not
> > (nor do the parameter levels for A and C in the definition of A::C),
> > which causes us to overlook the sharing.
> >
> > So it seems we can't in general depend on the TREE_TYPE of a template
> > parameter level being non-empty here. This patch partially fixes this
> > by rewriting the relevant part of any_template_parm_r to not depend on
> > the TREE_TYPE of outer levels. We still depend on the innermost level
> > to point to the innermost primary template, so unfortunately we still
> > crash on the commented out lines in the below testcase. (The problem
> > there ultimately seems to be in push_template_decl, where we consider
> > the out-of-line definition of A::C to not be primary since
> > template_parm_scope_p is false, so DECL_PRIMARY_TEMPLATE never gets set.
> > Fixing that might not be safe enough to backport, but hopefully this
> > partial fix is.)
> >
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, also tested on
> > range-v3 and cmcstl2, does this look OK for trunk/11?
>
> OK. Are you looking at fixing the commented-out line in a separate patch?
Thanks a lot. Yes, I'm going to try to make us set
DECL_PRIMARY_TEMPLATE (probably from push_template_decl) when defining a
class-scope class template out-of-line.
>
> > PR c++/101247
> >
> > gcc/cp/ChangeLog:
> >
> > * pt.c (any_template_parm_r) <case TEMPLATE_DECL>: Rewrite to
> > use common_enclosing_class and to not depend on the TREE_TYPE
> > of outer levels pointing to the corresponding primary template.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/cpp2a/concepts-memtmpl4.C: New test.
> > ---
> > gcc/cp/pt.c | 23 ++++-----------
> > .../g++.dg/cpp2a/concepts-memtmpl4.C | 28 +++++++++++++++++++
> > 2 files changed, 33 insertions(+), 18 deletions(-)
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl4.C
> >
> > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> > index db769d59951..a8fdd2e177e 100644
> > --- a/gcc/cp/pt.c
> > +++ b/gcc/cp/pt.c
> > @@ -10735,24 +10735,11 @@ any_template_parm_r (tree t, void *data)
> > {
> > /* If T is a member template that shares template parameters with
> > ctx_parms, we need to mark all those parameters for mapping. */
> > - tree dparms = DECL_TEMPLATE_PARMS (t);
> > - tree cparms = ftpi->ctx_parms;
> > - while (TMPL_PARMS_DEPTH (dparms) > ftpi->max_depth)
> > - dparms = TREE_CHAIN (dparms);
> > - while (TMPL_PARMS_DEPTH (cparms) > TMPL_PARMS_DEPTH (dparms))
> > - cparms = TREE_CHAIN (cparms);
> > - while (dparms
> > - && (TREE_TYPE (TREE_VALUE (dparms))
> > - != TREE_TYPE (TREE_VALUE (cparms))))
> > - dparms = TREE_CHAIN (dparms),
> > - cparms = TREE_CHAIN (cparms);
> > - if (dparms)
> > - {
> > - int ddepth = TMPL_PARMS_DEPTH (dparms);
> > - tree dargs = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT
> > (t)));
> > - for (int i = 0; i < ddepth; ++i)
> > - WALK_SUBTREE (TMPL_ARGS_LEVEL (dargs, i+1));
> > - }
> > + if (tree dtmpl = TREE_TYPE (INNERMOST_TEMPLATE_PARMS
> > (ftpi->ctx_parms)))
> > + if (tree com = common_enclosing_class (DECL_CONTEXT (t),
> > + DECL_CONTEXT (dtmpl)))
> > + if (tree ti = CLASSTYPE_TEMPLATE_INFO (com))
> > + WALK_SUBTREE (TI_ARGS (ti));
> > }
> > break;
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl4.C
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl4.C
> > new file mode 100644
> > index 00000000000..625149e5025
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl4.C
> > @@ -0,0 +1,28 @@
> > +// PR c++/101247
> > +// { dg-do compile { target concepts } }
> > +// A variant of concepts-memtmpl3.C where f is defined outside A's
> > definition.
> > +
> > +template <typename> struct A {
> > + template <typename c> static constexpr bool d = true;
> > + struct B;
> > + template <typename> struct C;
> > +};
> > +
> > +template <typename a>
> > +struct A<a>::B {
> > + template <typename c> static void f(c) requires d<c>;
> > +};
> > +
> > +template <typename a>
> > +template <typename b>
> > +struct A<a>::C {
> > + template <typename c> static void f(c) requires d<c>;
> > + static void g() requires d<b>;
> > +};
> > +
> > +int main()
> > +{
> > + A<void>::B::f(0);
> > + A<void>::C<int>::f(0);
> > + // A<void>::C<int>::g();
> > +}
> >
>
>
More information about the Gcc-patches
mailing list