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
> > 
> > 
> 

Reply via email to