On Fri, 19 Dec 2025, Egas Ribeiro wrote: > member_like_constrained_friend_p was incorrectly returning true for > constrained friend function templates declared in non-template classes, > causing them to be treated as distinct from their forward declarations. > This led to ambiguity errors at call sites. > > Per [temp.friend]/9, a constrained friend is only "member-like" (and thus > declares a different function) in two cases: > 1. Non-template friends with constraints (must be in a templated class) > 2. Template friends whose constraints depend on outer template parameters > > In both cases, the enclosing class scope must be templated. The fix adds > a check for CLASSTYPE_IMPLICIT_INSTANTIATION to ensure the friend's > context is actually a class template, not a plain class or explicit > specialization. > > PR c++/122550 > > gcc/cp/ChangeLog: > > * decl.cc (member_like_constrained_friend_p): Check that the > friend's enclosing class is an implicit instantiation. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-friend18.C: New test. > * g++.dg/cpp2a/concepts-friend18a.C: New test.
Looks good, pushed! > > Signed-off-by: Egas Ribeiro <[email protected]> > --- > gcc/cp/decl.cc | 1 + > .../g++.dg/cpp2a/concepts-friend18.C | 19 ++++++++++++++++ > .../g++.dg/cpp2a/concepts-friend18a.C | 22 +++++++++++++++++++ > 3 files changed, 42 insertions(+) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend18.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend18a.C > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > index 30f38f1e099..f41b3fc0471 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -1129,6 +1129,7 @@ member_like_constrained_friend_p (tree decl) > && DECL_UNIQUE_FRIEND_P (decl) > && DECL_FRIEND_CONTEXT (decl) > && get_constraints (decl) > + && CLASSTYPE_IMPLICIT_INSTANTIATION (DECL_FRIEND_CONTEXT (decl)) > && (!DECL_TEMPLATE_INFO (decl) > || !PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)) > || (uses_outer_template_parms_in_constraints > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend18.C > b/gcc/testsuite/g++.dg/cpp2a/concepts-friend18.C > new file mode 100644 > index 00000000000..bd1bac6cdac > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend18.C > @@ -0,0 +1,19 @@ > +// PR c++/122550 > +// { dg-do compile { target c++20 } } > + > +struct Hasher; > +template <class a> > +concept C = true; > + > +template<C T> > +void add(Hasher&, T); > + > +struct Hasher { > + template<C T> > + friend void add(Hasher& hasher, T integer) {} > +}; > + > +int main() { > + Hasher h; > + add(h, 0); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend18a.C > b/gcc/testsuite/g++.dg/cpp2a/concepts-friend18a.C > new file mode 100644 > index 00000000000..d29a2fba037 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend18a.C > @@ -0,0 +1,22 @@ > +// PR c++/122550 > +// { dg-do compile { target c++20 } } > + > +template<typename U> > +struct Hasher; > + > +template <class a> > +concept C = true; > + > +template<C T> > +void add(Hasher<int>&, T); > + > +template<> > +struct Hasher<int> { > + template<C T> > + friend void add(Hasher& hasher, T integer) {} > +}; > + > +int main() { > + Hasher<int> h; > + add(h, 0); > +} > -- > 2.52.0 > >
