Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/14?

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

While at it, adjust the return type.

        PR c++/96097

gcc/cp/ChangeLog:

        * pt.cc (coerce_template_template_parm): Return bool.  Increment
        processing_template_decl before calling tsubst.

gcc/testsuite/ChangeLog:

        * g++.dg/template/ttp44.C: New test.
---
 gcc/cp/pt.cc                          | 48 ++++++++++++++++-----------
 gcc/testsuite/g++.dg/template/ttp44.C | 13 ++++++++
 2 files changed, 42 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ttp44.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 024fa8a5529..aae57164fcc 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7887,25 +7887,22 @@ convert_nontype_argument (tree type, tree expr, 
tsubst_flags_t complain)
   return convert_from_reference (expr);
 }
 
-/* Subroutine of coerce_template_template_parms, which returns 1 if
-   PARM_PARM and ARG_PARM match using the rule for the template
-   parameters of template template parameters. Both PARM and ARG are
-   template parameters; the rest of the arguments are the same as for
-   coerce_template_template_parms.
- */
-static int
-coerce_template_template_parm (tree parm,
-                              tree arg,
-                              tsubst_flags_t complain,
-                              tree in_decl,
-                              tree outer_args)
+/* Subroutine of coerce_template_template_parms, which returns true if
+   PARM and ARG match using the rule for the template parameters of
+   template template parameters.  Both PARM and ARG are template parameters;
+   the rest of the arguments are the same as for
+   coerce_template_template_parms.  */
+
+static bool
+coerce_template_template_parm (tree parm, tree arg, tsubst_flags_t complain,
+                              tree in_decl, tree outer_args)
 {
   if (arg == NULL_TREE || error_operand_p (arg)
       || parm == NULL_TREE || error_operand_p (parm))
-    return 0;
+    return false;
 
   if (TREE_CODE (arg) != TREE_CODE (parm))
-    return 0;
+    return false;
 
   switch (TREE_CODE (parm))
     {
@@ -7916,7 +7913,7 @@ coerce_template_template_parm (tree parm,
       {
        if (!coerce_template_template_parms
            (parm, arg, complain, in_decl, outer_args))
-         return 0;
+         return false;
       }
       /* Fall through.  */
 
@@ -7924,7 +7921,7 @@ coerce_template_template_parm (tree parm,
       if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (arg))
          && !TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm)))
        /* Argument is a parameter pack but parameter is not.  */
-       return 0;
+       return false;
       break;
 
     case PARM_DECL:
@@ -7937,16 +7934,29 @@ coerce_template_template_parm (tree parm,
         i.e. the parameter list of TT depends on earlier parameters.  */
       if (!uses_template_parms (TREE_TYPE (arg)))
        {
+         /* 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.  */
+         ++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 0;
+           return false;
        }
 
       if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (arg))
          && !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)))
        /* Argument is a parameter pack but parameter is not.  */
-       return 0;
+       return false;
 
       break;
 
@@ -7954,7 +7964,7 @@ coerce_template_template_parm (tree parm,
       gcc_unreachable ();
     }
 
-  return 1;
+  return true;
 }
 
 /* Coerce template argument list ARGLIST for use with template
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: 3775f71c8909b3531fe002138814fa2504ec2e8b
-- 
2.46.0

Reply via email to