On Wed, 17 Dec 2025, Patrick Palka wrote: > Hey Egas, > > Thanks for looking into this recent regression! > > On Wed, 17 Dec 2025, Egas Ribeiro wrote: > > > Regtested on x86_64-pc-linux-gnu. > > > > This fix works, but I believe the real issue is that > > member_like_constrained_friend_p is incorrectly returning false because > > DECL_TEMPLATE_INFO isn't set up for the friend before duplicate_decls is > > called. I tried a few fixes to defer pushdecl_namespace_level after we > > call build_template_info in push_template_decl, but they caused some > > regressions. Suggestions on how i might fix this correctly? > > (also, using && probably goes against [temp.friend]/9 requirements) > > Yeah, one would expect DECL_TEMPLATE_INFO to point back to the template > friend's TEMPLATE_DECL here (whose DECL_TEMPLATE_RESULT points to the > FUNCTION_DECL as expected). We probably should fix that.. > > Luckily I think we can work around this missing DECL_TEMPLATE_INFO for > this PR. The predicate needs to return true for non-template > constrained friends and template friends whose constraints depend on > outer template parameters. In the former case the function must be > templated (since only templated functions can have constraints) and > therefore the class scope must be templated. In the latter case the > class scope must also be templated since we assume there are outer > template parameters on which the constraint can depend. So in either > case the class scope must be templated! > > So I think it should work to add > > CLASSTYPE_TEMPLATE_INFO (DECL_FRIEND_CONTEXT (decl)) > > to the predicate, which will rule out non class template scope friends > such as in the PR?
Actually we probably need to check CLASSTYPE_IMPLICIT_INSTANTIATION instead, so that we return false also when the friend in an explicit specialization scope. > > > > > -- >8 -- > > > > function_requirements_equivalent_p was incorrectly treating a constrained > > friend function template and its namespace-scope forward declaration as > > having inequivalent requirements, causing an ambiguity error. > > > > PR c++/122550 > > > > gcc/cp/ChangeLog: > > > > * decl.cc (function_requirements_equivalent_p): Use && instead > > of || when checking member_like_constrained_friend_p. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/cpp2a/concepts-friend18.C: New test. > > > > Signed-off-by: Egas Ribeiro <[email protected]> > > --- > > gcc/cp/decl.cc | 2 +- > > gcc/testsuite/g++.dg/cpp2a/concepts-friend18.C | 18 ++++++++++++++++++ > > 2 files changed, 19 insertions(+), 1 deletion(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend18.C > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc > > index 74c862ec1c7..689332363aa 100644 > > --- a/gcc/cp/decl.cc > > +++ b/gcc/cp/decl.cc > > @@ -1146,7 +1146,7 @@ function_requirements_equivalent_p (tree newfn, tree > > oldfn) > > same function as a declaration in any other scope." So no need to > > actually compare the requirements. */ > > if (member_like_constrained_friend_p (newfn) > > - || member_like_constrained_friend_p (oldfn)) > > + && member_like_constrained_friend_p (oldfn)) > > return false; > > > > /* Compare only trailing requirements. */ > > 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..5a6b0d67ef7 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend18.C > > @@ -0,0 +1,18 @@ > > +// PR c++/122550 > > +// { dg-do compile { target c++20 } } > > + > > +class 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) {} > > +}; > > + > > +void f(Hasher& hasher, unsigned long integer) { > > + add(hasher, (unsigned int) integer); > > +} > > -- > > 2.52.0 > > > > >
