diff mbox series

[v2] c++: ICE with TTP [PR96097]

Message ID ZuH_Um_7cp7-fhdb@redhat.com
State New
Headers show
Series [v2] c++: ICE with TTP [PR96097] | expand

Commit Message

Marek Polacek Sept. 11, 2024, 8:36 p.m. UTC
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?

-- >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


base-commit: 670cfd5fe6433ee8f2e86eedb197d2523dbb033b

Comments

Jason Merrill Sept. 12, 2024, 2:18 a.m. UTC | #1
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 mbox series

Patch

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