c++: alias ctad refinements [PR109321]
authorJason Merrill <jason@redhat.com>
Tue, 28 Mar 2023 21:42:23 +0000 (17:42 -0400)
committerJason Merrill <jason@redhat.com>
Wed, 29 Mar 2023 02:23:51 +0000 (22:23 -0400)
The two hunks fix missing handling demonstrated by the two testcases: first,
if we omit one alias template parm but include another, we need to rewrite
the deduced template args to reflect the new position of the included parm.
Second, if we can't deduce any template args for a parameter pack, it is
deduced to an empty pack.

PR c++/109321
PR c++/109320

gcc/cp/ChangeLog:

* pt.cc (alias_ctad_tweaks): Rewrite deduced args.
(type_targs_deducible_from): Handle null pack deduction.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/class-deduction-alias16.C: New test.
* g++.dg/cpp2a/class-deduction-alias17.C: New test.

gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp2a/class-deduction-alias16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/class-deduction-alias17.C [new file with mode: 0644]

index 3bb98eb..e514a27 100644 (file)
@@ -30123,8 +30123,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
            for (unsigned i = 0; i < len; ++i)
              TREE_VEC_ELT (targs, i) = NULL_TREE;
 
-         /* The number of parms for f' is the number of parms for A plus
-            non-deduced parms of f.  */
+         /* The number of parms for f' is the number of parms of A used in
+            the deduced arguments plus non-deduced parms of f.  */
          unsigned ndlen = 0;
          unsigned j;
          for (unsigned i = 0; i < len; ++i)
@@ -30142,22 +30142,34 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
          TREE_VALUE (current_template_parms) = gtparms;
 
          j = 0;
-         /* First copy over the parms of A.  */
+         unsigned level = 1;
+
+         /* First copy over the used parms of A.  */
+         tree atargs = make_tree_vec (natparms);
          for (unsigned i = 0; i < natparms; ++i)
            {
              tree elt = TREE_VEC_ELT (atparms, i);
              if (ftpi.found (elt))
-               TREE_VEC_ELT (gtparms, j++) = elt;
+               {
+                 unsigned index = j++;
+                 tree nelt = rewrite_tparm_list (elt, index, level,
+                                                 atargs, i, complain);
+                 TREE_VEC_ELT (gtparms, index) = nelt;
+               }
            }
          gcc_checking_assert (j == nusedatparms);
 
+         /* Adjust the deduced template args for f to refer to the A parms
+            with their new indexes.  */
+         if (nusedatparms && nusedatparms != natparms)
+           targs = tsubst_template_args (targs, atargs, complain, in_decl);
+
          /* Now rewrite the non-deduced parms of f.  */
          for (unsigned i = 0; ndlen && i < len; ++i)
            if (TREE_VEC_ELT (targs, i) == NULL_TREE)
              {
                --ndlen;
                unsigned index = j++;
-               unsigned level = 1;
                tree oldlist = TREE_VEC_ELT (ftparms, i);
                tree list = rewrite_tparm_list (oldlist, index, level,
                                                targs, i, complain);
@@ -30261,15 +30273,37 @@ type_targs_deducible_from (tree tmpl, tree type)
 
   /* We don't fail on an undeduced targ the second time through (like
      get_partial_spec_bindings) because we're going to try defaults.  */
-  if (!tried_array_deduction)
-    for (int i =  0; i < len; ++i)
-      if (! TREE_VEC_ELT (targs, i))
-       {
-         try_array_deduction (tparms, targs, TREE_TYPE (tmpl));
-         tried_array_deduction = true;
-         if (TREE_VEC_ELT (targs, i))
-           goto again;
-       }
+  for (int i =  0; i < len; ++i)
+    if (! TREE_VEC_ELT (targs, i))
+      {
+       tree tparm = TREE_VEC_ELT (tparms, i);
+       tparm = TREE_VALUE (tparm);
+
+       if (!tried_array_deduction
+           && TREE_CODE (tparm) == TYPE_DECL)
+         {
+           try_array_deduction (tparms, targs, TREE_TYPE (tmpl));
+           tried_array_deduction = true;
+           if (TREE_VEC_ELT (targs, i))
+             goto again;
+         }
+       /* If the type parameter is a parameter pack, then it will be deduced
+          to an empty parameter pack.  This is another case that doesn't model
+          well as partial specialization.  */
+       if (template_parameter_pack_p (tparm))
+         {
+           tree arg;
+           if (TREE_CODE (tparm) == TEMPLATE_PARM_INDEX)
+             {
+               arg = make_node (NONTYPE_ARGUMENT_PACK);
+               TREE_CONSTANT (arg) = 1;
+             }
+           else
+             arg = cxx_make_type (TYPE_ARGUMENT_PACK);
+           ARGUMENT_PACK_ARGS (arg) = make_tree_vec (0);
+           TREE_VEC_ELT (targs, i) = arg;
+         }
+      }
 
   /* Maybe add in default template args.  This seems like a flaw in the
      specification in terms of partial specialization, since it says the
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias16.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias16.C
new file mode 100644 (file)
index 0000000..53d305b
--- /dev/null
@@ -0,0 +1,7 @@
+// PR c++/109321
+// { dg-do compile { target c++20 } }
+
+struct A;
+template<class C1> struct B;
+template<class, class C2=A> using D = B<C2>;
+void f () { D() = 0; }         // { dg-error "deduction failed|no match" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias17.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias17.C
new file mode 100644 (file)
index 0000000..b834689
--- /dev/null
@@ -0,0 +1,9 @@
+// PR c++/109320
+// { dg-do compile { target c++20 } }
+
+template<bool B>
+struct S {};
+template<int... C>
+using u = S<true>;
+struct X {};
+auto a = u {};