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(); > > +} > > > >