Message ID | ZuH_Um_7cp7-fhdb@redhat.com |
---|---|
State | New |
Headers | show |
Series | [v2] c++: ICE with TTP [PR96097] | expand |
On 9/11/24 4:36 PM, Marek Polacek wrote: > On Wed, Sep 11, 2024 at 11:26:56AM -0400, Jason Merrill wrote: >> On 9/11/24 10:53 AM, Patrick Palka wrote: >>> On Wed, 11 Sep 2024, Patrick Palka wrote: >>> >>>> On Wed, 11 Sep 2024, Patrick Palka wrote: >>>> >>>>> On Wed, 4 Sep 2024, Marek Polacek wrote: >>>>> >>>>>> On Wed, Sep 04, 2024 at 10:58:25AM -0400, Jason Merrill wrote: >>>>>>> On 9/3/24 6:12 PM, Marek Polacek wrote: >>>>>>>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/14? >>>>>>> >>>>>>> The change to return bool seems like unrelated cleanup; please push that >>>>>>> separately on trunk only. >>>>>> >>>>>> Done. >>>>>>>> + /* We can also have: >>>>>>>> + >>>>>>>> + template <template <typename T, typename T::type TT> typename X> >>>>>>>> + void func() {} >>>>>>>> + template <typename U, int I> >>>>>>>> + struct Y {}; >>>>>>>> + void g() { func<Y>(); } >>>>>>>> + >>>>>>>> + where we are not in a template, but the type of PARM is T::type >>>>>>>> + and dependent_type_p doesn't want to see a TEMPLATE_TYPE_PARM >>>>>>>> + outside a template. */ >>>> >>>> ... so the patch LGTM, except I'd prefer to not have this comment >>>> containing an embedded specific testcase. IMHO it's "understood" that >>>> processing_template_decl needs to be set when substituting using an >>>> incomplete set of arguments since in that case the result must be >>>> templated. >>> >>> ... and the comment might make this instance of the pattern seem more >>> like an exceptional case rather than a general rule, which paradoxically >>> could make the code seem more complex than it is at first glance. >> >> Makes sense to me. > > Thank you both. Here's a version without the cleanups and the comment. > > Ran dg.exp on x86_64-pc-linux-gnu, OK for trunk? OK. > -- >8 -- > We crash when dependent_type_p gets a TEMPLATE_TYPE_PARM outside > a template. That happens here because in > > template <template <typename T, typename T::type TT> typename X> > void func() {} > template <typename U, int I> > struct Y {}; > void g() { func<Y>(); } > > when performing overload resolution for func<Y>() we have to check > if U matches T and I matches TT. So we wind up in > coerce_template_template_parm/PARM_DECL. TREE_TYPE (arg) is int > so we try to substitute TT's type, which is T::type. But we have > nothing to substitute T with. And we call make_typename_type where > ctx is still T, which checks dependent_scope_p and we trip the assert. > > It should work to always perform the substitution in a template context. > If the result still contains template parameters, we cannot say if they > match. > > PR c++/96097 > > gcc/cp/ChangeLog: > > * pt.cc (coerce_template_template_parm): Increment > processing_template_decl before calling tsubst. > > gcc/testsuite/ChangeLog: > > * g++.dg/template/ttp44.C: New test. > --- > gcc/cp/pt.cc | 2 ++ > gcc/testsuite/g++.dg/template/ttp44.C | 13 +++++++++++++ > 2 files changed, 15 insertions(+) > create mode 100644 gcc/testsuite/g++.dg/template/ttp44.C > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 310e5dfff03..e4de5451f19 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -7951,7 +7951,9 @@ coerce_template_template_parm (tree parm, tree arg, tsubst_flags_t complain, > i.e. the parameter list of TT depends on earlier parameters. */ > if (!uses_template_parms (TREE_TYPE (arg))) > { > + ++processing_template_decl; > tree t = tsubst (TREE_TYPE (parm), outer_args, complain, in_decl); > + --processing_template_decl; > if (!uses_template_parms (t) > && !same_type_p (t, TREE_TYPE (arg))) > return false; > diff --git a/gcc/testsuite/g++.dg/template/ttp44.C b/gcc/testsuite/g++.dg/template/ttp44.C > new file mode 100644 > index 00000000000..2a412975243 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/ttp44.C > @@ -0,0 +1,13 @@ > +// PR c++/96097 > +// { dg-do compile } > + > +template <template <typename T, typename T::type TT> class X> > +void func() {} > + > +template <typename U, int I> > +struct Y {}; > + > +void test() > +{ > + func<Y>(); > +} > > base-commit: 670cfd5fe6433ee8f2e86eedb197d2523dbb033b
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 310e5dfff03..e4de5451f19 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -7951,7 +7951,9 @@ coerce_template_template_parm (tree parm, tree arg, tsubst_flags_t complain, i.e. the parameter list of TT depends on earlier parameters. */ if (!uses_template_parms (TREE_TYPE (arg))) { + ++processing_template_decl; tree t = tsubst (TREE_TYPE (parm), outer_args, complain, in_decl); + --processing_template_decl; if (!uses_template_parms (t) && !same_type_p (t, TREE_TYPE (arg))) return false; diff --git a/gcc/testsuite/g++.dg/template/ttp44.C b/gcc/testsuite/g++.dg/template/ttp44.C new file mode 100644 index 00000000000..2a412975243 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp44.C @@ -0,0 +1,13 @@ +// PR c++/96097 +// { dg-do compile } + +template <template <typename T, typename T::type TT> class X> +void func() {} + +template <typename U, int I> +struct Y {}; + +void test() +{ + func<Y>(); +}