Message ID | 20230913175331.4084179-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: optimize unification of class specializations [PR89231] | expand |
On 9/13/23 13:53, Patrick Palka wrote: > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk? OK. > -- >8 -- > > 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 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 the level of Ps doesn't match 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. Don't unify template arguments if the > template is not primary. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/variadic-partial3.C: New test. > --- > gcc/cp/pt.cc | 17 +++++++++++------ > .../g++.dg/cpp0x/variadic-partial3.C | 19 +++++++++++++++++++ > 2 files changed, 30 insertions(+), 6 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 838179d5fe3..c88e9cd0fa6 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -23999,8 +23999,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 > @@ -24041,8 +24040,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; > } > @@ -25167,11 +25168,15 @@ 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 if (!same_type_ignoring_top_level_qualifiers_p (parm, arg)) > return unify_type_mismatch (explain_p, parm, arg); > + > return unify_success (explain_p); > > case METHOD_TYPE: > diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C > new file mode 100644 > index 00000000000..5af60711320 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C > @@ -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;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 838179d5fe3..c88e9cd0fa6 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -23999,8 +23999,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 @@ -24041,8 +24040,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; } @@ -25167,11 +25168,15 @@ 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 if (!same_type_ignoring_top_level_qualifiers_p (parm, arg)) return unify_type_mismatch (explain_p, parm, arg); + return unify_success (explain_p); case METHOD_TYPE: diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C new file mode 100644 index 00000000000..5af60711320 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-partial3.C @@ -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;