]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: optimize unifying nested templated classes [PR89231]
authorPatrick Palka <ppalka@redhat.com>
Mon, 18 Sep 2023 18:54:45 +0000 (14:54 -0400)
committerPatrick Palka <ppalka@redhat.com>
Mon, 18 Sep 2023 18:54:45 +0000 (14:54 -0400)
Since the LHS of a qualified-id is a non-deduced context, it effectively
means we can't deduce from outer template arguments of a class template
specialization.  And checking for equality between the TI_TEMPLATE of a
class specialization parm/arg already implies that the outer template
arguments are the same.  Hence recursing into outer template arguments
during unification of class specializations is redundant, so this patch
makes unify recurse only into innermost arguments.

This incidentally fixes the testcase from PR89231 because there
more_specialized_partial_inst wrongly considers the two partial
specializations to be unordered ultimately because unify for identical
parm=arg=A<Ps...>::Collect<N...> gets confused when it recurses into
parm=arg={Ps...} since Ps is outside the (innermost) level of tparms
that we're actually deducing.

PR c++/89231

gcc/cp/ChangeLog:

* pt.cc (try_class_unification): Strengthen TI_TEMPLATE equality
test by not calling most_general_template.  Only unify the
innermost levels of template arguments.
(unify) <case CLASS_TYPE>: Only unify the innermost levels of
template arguments, and only if the template is primary.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/variadic-partial3.C: New test.

gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C [new file with mode: 0644]

index 31ff80ea6e74f32207066850cef74e2e493bca62..777ff5927897f1abc851320764a353a65b6aa124 100644 (file)
@@ -23990,8 +23990,7 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg,
     return NULL_TREE;
   else if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
     /* Matches anything.  */;
-  else if (most_general_template (CLASSTYPE_TI_TEMPLATE (arg))
-          != most_general_template (CLASSTYPE_TI_TEMPLATE (parm)))
+  else if (CLASSTYPE_TI_TEMPLATE (arg) != CLASSTYPE_TI_TEMPLATE (parm))
     return NULL_TREE;
 
   /* We need to make a new template argument vector for the call to
@@ -24032,8 +24031,10 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg,
   if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
     err = unify_bound_ttp_args (tparms, targs, parm, arg, explain_p);
   else
-    err = unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
-                CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE, explain_p);
+    err = unify (tparms, targs,
+                INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (parm)),
+                INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (arg)),
+                UNIFY_ALLOW_NONE, explain_p);
 
   return err ? NULL_TREE : arg;
 }
@@ -25159,8 +25160,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
            /* There's no chance of unification succeeding.  */
            return unify_type_mismatch (explain_p, parm, arg);
 
-         return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
-                       CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE, explain_p);
+         if (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))
+           return unify (tparms, targs,
+                         INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (parm)),
+                         INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (t)),
+                         UNIFY_ALLOW_NONE, explain_p);
+         else
+           return unify_success (explain_p);
        }
       else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg))
        return unify_type_mismatch (explain_p, parm, arg);
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C
new file mode 100644 (file)
index 0000000..5af6071
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/89231
+// { dg-do compile { target c++11 } }
+
+template<class... Ps>
+struct A {
+  template<int... Ns>
+  struct Collect { };
+
+  template<int C, int I = 0, class S = Collect<>>
+  struct Seq;
+
+  template<int C, int I, int... N>
+  struct Seq<C, I, Collect<N...>> : Seq<C - 1, I + 1, Collect<N..., I>> { };
+
+  template<int I, int... N>
+  struct Seq<0, I, Collect<N...>> : Collect<N...> { };
+};
+
+A<int>::Seq<4> test;