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);
> > +}
>
>