On Thu, Feb 11, 2021 at 02:24:22PM -0500, Marek Polacek via Gcc-patches wrote: > On Thu, Feb 11, 2021 at 11:30:07AM -0500, Jason Merrill via Gcc-patches wrote: > > On 2/9/21 5:41 PM, Marek Polacek wrote: > > > My r10-7007 patch tweaked tsubst not to reduce the template level of > > > template parameters when tf_partial. That caused infinite looping in > > > is_specialization_of: we ended up with a class template specialization > > > whose TREE_TYPE (CLASSTYPE_TI_TEMPLATE (t)) == t, so the second for > > > loop in is_specialization_of never finished. > > > > > > There's a lot going on in this test, but essentially: the template fn > > > here has two template parameters, we call it with one explicitly > > > provided, the other one has to be deduced. So we'll find ourselves > > > in fn_type_unification which uses tf_partial when tsubsting the > > > *explicit* template arguments into the function type. That leads to > > > tsubstituting the return type, C<T>. C is a member template; its > > > most general template is > > > > > > template<class U> template<class V> struct B<U>::C > > > > > > we figure out (tsubst_template_args) that the template argument list > > > is <int, int>. They come from different levels, one comes from B<int>, > > > the other one from fn<int>. > > > > > > So now we lookup_template_class to see if we have C<int, int>. We > > > do the > > > /* This is a full instantiation of a member template. Find > > > the partial instantiation of which this is an instance. */ > > > TREE_VEC_LENGTH (arglist)--; > > > // arglist is now <int>, not <int, int> > > > found = tsubst (gen_tmpl, arglist, complain, NULL_TREE); > > > TREE_VEC_LENGTH (arglist)++; > > > > > > magic which is looking for the partial instantiation, in this case, > > > that would be template<class V> struct B<int>::C. Note we're still > > > in a tf_partial context! So the tsubst_template_args in the tsubst > > > (which tries to substitute <int> into <U, V>) returns <int, V>, but > > > V's template level hasn't been reduced! After tsubst_template_args, > > > tsubst_template_decl looks to see if we already have this specialization: > > > > > > // t = template_decl C > > > // full_args = <int, V> > > > spec = retrieve_specialization (t, full_args, hash); > > > > > > but doesn't find the one we created a while ago, when processing > > > B<int> b; in the test, because V's levels don't match. Whereupon > > > tsubst_template_decl creates a new TEMPLATE_DECL, one that leads to > > > the infinite looping problem. > > > > > > I think let's clear tf_partial when looking for an existing partial > > > instantiation. > > > > > > It also occurred to me that I should be able to trigger a similar > > > problem with 'auto', since r10-7007 removed an is_auto check. And lo, > > > I constructed deduce10.C which exhibits the same issue with pre-r10-7007 > > > compilers. This patch fixes that problem as well. I'm ecstatic. > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10? Also > > > built cmcstl2. > > > > Perhaps the mistake here is using the complain parm at all; this > > substitution is not in the "immediate context" of deduction. Either tf_none > > or tf_warning_or_error should be fine, as we know this substitution has > > previously succeeded. > > Yeah, that makes sense to me too: > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10? > > -- >8 -- > My r10-7007 patch tweaked tsubst not to reduce the template level of > template parameters when tf_partial. That caused infinite looping in > is_specialization_of: we ended up with a class template specialization > whose TREE_TYPE (CLASSTYPE_TI_TEMPLATE (t)) == t, so the second for > loop in is_specialization_of never finished. > > There's a lot going on in this test, but essentially: the template fn > here has two template parameters, we call it with one explicitly > provided, the other one has to be deduced. So we'll find ourselves > in fn_type_unification which uses tf_partial when tsubsting the > *explicit* template arguments into the function type. That leads to > tsubstituting the return type, C<T>. C is a member template; its > most general template is > > template<class U> template<class V> struct B<U>::C > > we figure out (tsubst_template_args) that the template argument list > is <int, int>. They come from different levels, one comes from B<int>, > the other one from fn<int>. > > So now we lookup_template_class to see if we have C<int, int>. We > do the > /* This is a full instantiation of a member template. Find > the partial instantiation of which this is an instance. */ > TREE_VEC_LENGTH (arglist)--; > // arglist is now <int>, not <int, int> > found = tsubst (gen_tmpl, arglist, complain, NULL_TREE); > TREE_VEC_LENGTH (arglist)++; > > magic which is looking for the partial instantiation, in this case, > that would be template<class V> struct B<int>::C. Note we're still > in a tf_partial context! So the tsubst_template_args in the tsubst > (which tries to substitute <int> into <U, V>) returns <int, V>, but > V's template level hasn't been reduced! After tsubst_template_args, > tsubst_template_decl looks to see if we already have this specialization: > > // t = template_decl C > // full_args = <int, V> > spec = retrieve_specialization (t, full_args, hash); > > but doesn't find the one we created a while ago, when processing > B<int> b; in the test, because V's levels don't match. Whereupon > tsubst_template_decl creates a new TEMPLATE_DECL, one that leads to > the infinite looping problem. > > Fixed by using tf_none when looking for an existing partial instantiation. > > It also occurred to me that I should be able to trigger a similar > problem with 'auto', since r10-7007 removed an is_auto check. And lo, > I constructed deduce10.C which exhibits the same issue with pre-r10-7007 > compilers. This patch fixes that problem as well. I'm ecstatic. > > gcc/cp/ChangeLog: > > PR c++/95888 > * pt.c (lookup_template_class_1): Clear tf_partial when looking for > the partial instantiation.
And clearly this CL needs to be updated to reflect the changes in v2. Marek