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

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

Reply via email to