]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: passing partially inst ttp as ttp [PR110566]
authorPatrick Palka <ppalka@redhat.com>
Wed, 26 Jul 2023 21:21:43 +0000 (17:21 -0400)
committerPatrick Palka <ppalka@redhat.com>
Wed, 26 Jul 2023 21:21:43 +0000 (17:21 -0400)
The previous fix doesn't work for partially instantiated ttps mainly
because most_general_template is a no-op for them.  This patch fixes
this by giving such ttps a DECL_TEMPLATE_INFO (extending the
r11-734-g2fb595f8348e16 fix) with which most_general_template can obtain
the original, unlowered ttp.

This patch additionally makes coerce_template_template_parms use the
correct amount of levels from the scope of a ttp argument.

PR c++/110566
PR c++/108179

gcc/cp/ChangeLog:

* pt.cc (reduce_template_parm_level): Set DECL_TEMPLATE_INFO
on the DECL_TEMPLATE_RESULT of the new ttp.
(add_defaults_to_ttp): Make a copy of the original ttp's
DECL_TEMPLATE_RESULT, and update this copy's DECL_TEMPLATE_INFO
as well.
(coerce_template_template_parms): Make sure 'scope_args' has
the right amount of levels for the ttp argument.
(most_general_template): Handle template template parameters.
(rewrite_template_parm): Set DECL_TEMPLATE_RESULT on the
DECL_TEMPLATE_RESULT of the new ttp.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/class-deduction115.C: New test.
* g++.dg/template/ttp39.C: New test.

gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp1z/class-deduction115.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/ttp39.C [new file with mode: 0644]

index 210d6222ef12f9335a5034ef41bf2e2307211638..9e39fe91986fe10232da1188328b290b23c50644 100644 (file)
@@ -4566,12 +4566,17 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
       tree inner = decl;
       if (TREE_CODE (decl) == TEMPLATE_DECL)
        {
-         inner = build_decl (DECL_SOURCE_LOCATION (decl),
-                             TYPE_DECL, DECL_NAME (decl), type);
+         inner = build_lang_decl_loc (DECL_SOURCE_LOCATION (decl),
+                                      TYPE_DECL, DECL_NAME (decl), type);
          DECL_TEMPLATE_RESULT (decl) = inner;
          DECL_ARTIFICIAL (inner) = true;
-         DECL_TEMPLATE_PARMS (decl) = tsubst_template_parms
-           (DECL_TEMPLATE_PARMS (orig_decl), args, complain);
+         tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (orig_decl),
+                                             args, complain);
+         DECL_TEMPLATE_PARMS (decl) = parms;
+         tree orig_inner = DECL_TEMPLATE_RESULT (orig_decl);
+         DECL_TEMPLATE_INFO (inner)
+           = build_template_info (DECL_TI_TEMPLATE (orig_inner),
+                                  template_parms_to_args (parms));
        }
 
       /* Attach the TPI to the decl.  */
@@ -7936,6 +7941,19 @@ add_defaults_to_ttp (tree otmpl)
        }
     }
 
+  tree oresult = DECL_TEMPLATE_RESULT (otmpl);
+  tree gen_otmpl = DECL_TI_TEMPLATE (oresult);
+  tree gen_ntmpl;
+  if (gen_otmpl == otmpl)
+    gen_ntmpl = ntmpl;
+  else
+    gen_ntmpl = add_defaults_to_ttp (gen_otmpl);
+
+  tree nresult = copy_decl (oresult);
+  DECL_TEMPLATE_INFO (nresult)
+    = build_template_info (gen_ntmpl, TI_ARGS (DECL_TEMPLATE_INFO (oresult)));
+  DECL_TEMPLATE_RESULT (ntmpl) = nresult;
+
   hash_map_safe_put<hm_ggc> (defaulted_ttp_cache, otmpl, ntmpl);
   return ntmpl;
 }
@@ -8121,18 +8139,40 @@ coerce_template_template_parms (tree parm_tmpl,
         OUTER_ARGS are not the right outer levels in this case, as they are
         the args we're building up for PARM, and for the coercion we want the
         args for ARG.  If DECL_CONTEXT isn't set for a template template
-        parameter, we can assume that it's in the current scope.  In that case
-        we might end up adding more levels than needed, but that shouldn't be
-        a problem; any args we need to refer to are at the right level.  */
+        parameter, we can assume that it's in the current scope.  */
       tree ctx = DECL_CONTEXT (arg_tmpl);
       if (!ctx && DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
        ctx = current_scope ();
       tree scope_args = NULL_TREE;
       if (tree tinfo = get_template_info (ctx))
        scope_args = TI_ARGS (tinfo);
-      pargs = add_to_template_args (scope_args, pargs);
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg_tmpl))
+       {
+         int level = TEMPLATE_TYPE_LEVEL (TREE_TYPE (gen_arg_tmpl));
+         int scope_depth = TMPL_ARGS_DEPTH (scope_args);
+         tree full_pargs = make_tree_vec (level + 1);
+
+       /* Only use as many levels from the scope as needed
+          (excluding the level of ARG).  */
+         for (int i = 0; i < level - 1; ++i)
+           if (i < scope_depth)
+             TREE_VEC_ELT (full_pargs, i) = TMPL_ARGS_LEVEL (scope_args, i + 1);
+           else
+             TREE_VEC_ELT (full_pargs, i) = make_tree_vec (0);
 
-      pargs = coerce_template_parms (gen_arg_parms, pargs, NULL_TREE, tf_none);
+         /* Add the arguments that appear at the levels of ARG.  */
+         tree adjacent = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (arg_tmpl));
+         adjacent = TMPL_ARGS_LEVEL (adjacent, TMPL_ARGS_DEPTH (adjacent) - 1);
+         TREE_VEC_ELT (full_pargs, level - 1) = adjacent;
+
+         TREE_VEC_ELT (full_pargs, level) = pargs;
+         pargs = full_pargs;
+       }
+      else
+       pargs = add_to_template_args (scope_args, pargs);
+
+      pargs = coerce_template_parms (gen_arg_parms, pargs,
+                                    NULL_TREE, tf_none);
       if (pargs != error_mark_node)
        {
          tree targs = make_tree_vec (nargs);
@@ -25988,6 +26028,9 @@ most_general_template (tree decl)
        return NULL_TREE;
     }
 
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (decl))
+    return DECL_TI_TEMPLATE (DECL_TEMPLATE_RESULT (decl));
+
   /* Look for more and more general templates.  */
   while (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
     {
@@ -29703,10 +29746,11 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
 
       if (TREE_CODE (olddecl) == TEMPLATE_DECL)
        {
-         DECL_TEMPLATE_RESULT (newdecl)
-           = build_decl (DECL_SOURCE_LOCATION (olddecl), TYPE_DECL,
-                         DECL_NAME (olddecl), newtype);
-         DECL_ARTIFICIAL (DECL_TEMPLATE_RESULT (newdecl)) = true;
+         tree newresult
+           = build_lang_decl_loc (DECL_SOURCE_LOCATION (olddecl), TYPE_DECL,
+                                  DECL_NAME (olddecl), newtype);
+         DECL_ARTIFICIAL (newresult) = true;
+         DECL_TEMPLATE_RESULT (newdecl) = newresult;
          // First create a copy (ttargs) of tsubst_args with an
          // additional level for the template template parameter's own
          // template parameters (ttparms).
@@ -29740,6 +29784,8 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
          TREE_VALUE (TREE_CHAIN (ttparms)) = make_tree_vec (0);
          // All done.
          DECL_TEMPLATE_PARMS (newdecl) = ttparms;
+         DECL_TEMPLATE_INFO (newresult)
+           = build_template_info (newdecl, template_parms_to_args (ttparms));
        }
 
       if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (olddecl)))
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction115.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction115.C
new file mode 100644 (file)
index 0000000..5c9aa83
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++17 } }
+
+template<template<class> class>
+struct A { };
+
+template<class T>
+struct B {
+  template<template<class> class TT, A<TT>* = nullptr>
+  B(TT<T>);
+};
+
+template<class T>
+struct C { };
+
+using type = decltype(B{C<int>{}});
+using type = B<int>;
diff --git a/gcc/testsuite/g++.dg/template/ttp39.C b/gcc/testsuite/g++.dg/template/ttp39.C
new file mode 100644 (file)
index 0000000..03d7c50
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/110566
+// { dg-do compile { target c++20 } }
+
+template<template<int N, int M> class>
+struct A;
+
+template<class U>
+struct B {
+  template<class T>
+  struct C {
+    template<template<auto X, auto Y> class TT>
+    using type = A<TT>;
+  };
+};
+
+template struct B<int>::C<int>;