On Wed, 14 May 2025, Jason Merrill wrote: > On 5/12/25 7:53 PM, Patrick Palka wrote: > > Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look OK > > for trunk/15/14? > > > > -- >8 -- > > > > Here unification of P=Wrap<int>::type, A=Wrap<long>::type wrongly > > succeeds ever since r14-4112 which made the RECORD_TYPE case of unify > > no longer recurse into template arguments for non-primary templates > > (since they're a non-deduced context) and so the int/long mismatch that > > makes the two types distinct goes unnoticed. > > > > In the case of (comparing specializations of) a non-primary template, > > unify should still go on to compare the types directly before returning > > success. > > Should the PRIMARY_TEMPLATE_P check instead move up to join the > CLASSTYPE_TEMPLATE_INFO check? try_class_deduction also doesn't seem > applicable to non-primary templates.
I don't think that'd work, for either the CLASSTYPE_TEMPLATE_INFO (parm) check or the earlier CLASSTYPE_TEMPLATE_INFO (arg) check. While try_class_deduction directly doesn't apply to non-primary templates, get_template_base still might, so if we move up the PRIMARY_TEMPLATE_P to join the C_T_I (parm) check, then we wouldn't try get_template_base anymore which would break e.g. template<class T> struct B { }; template<class T> struct A { struct C : B<int> { }; }; template<class T> void f(B<T>*); int main() { A<int>::C c; f(&c); } If we move the PRIMARY_TEMPLATE_P check up to the C_T_I (arg) check, then that'd mean we still don't check same_type_p on the two types in the non-primary case, which seems wrong (although it'd fix the PR thanks to the parm == arg early exit in unify). > > > PR c++/120161 > > > > gcc/cp/ChangeLog: > > > > * pt.cc (unify) <case RECORD_TYPE>: When comparing specializations > > of a non-primary template, still perform a type comparison. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/template/unify13.C: New test. > > --- > > gcc/cp/pt.cc | 6 +++--- > > gcc/testsuite/g++.dg/template/unify13.C | 18 ++++++++++++++++++ > > 2 files changed, 21 insertions(+), 3 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/template/unify13.C > > > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > > index 0d64a1cfb128..868dd0e2b3ff 100644 > > --- a/gcc/cp/pt.cc > > +++ b/gcc/cp/pt.cc > > @@ -25785,10 +25785,10 @@ unify (tree tparms, tree targs, tree parm, tree > > arg, int strict, > > 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); > > + gcc_checking_assert (t == arg); > > } > > - else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg)) > > + > > + if (!same_type_ignoring_top_level_qualifiers_p (parm, arg)) > > return unify_type_mismatch (explain_p, parm, arg); > > return unify_success (explain_p); > > diff --git a/gcc/testsuite/g++.dg/template/unify13.C > > b/gcc/testsuite/g++.dg/template/unify13.C > > new file mode 100644 > > index 000000000000..ec7ca9d17a44 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/template/unify13.C > > @@ -0,0 +1,18 @@ > > +// PR c++/120161 > > + > > +template<class T, class U> > > +struct mp_list { }; > > + > > +template<class T> > > +struct Wrap { struct type { }; }; > > + > > +struct A : mp_list<Wrap<int>::type, void> > > + , mp_list<Wrap<long>::type, void> { }; > > + > > +template<class U> > > +void f(mp_list<Wrap<int>::type, U>*); > > + > > +int main() { > > + A a; > > + f(&a); > > +} > >