https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98822
Bug ID: 98822
Summary: Rejects-valid: instantiation of class template
instantiates (all) constrained non-template friend
definitions (, even those) with unsatisfied
constraints
Product: gcc
Version: 11.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: davveston at gmail dot com
Target Milestone: ---
(All standard references below refer to N4861).
Constrained hidden non-template friends was added as per NS US115 of P2103R0
(adding [temp.friend]/9), meaning the following program is (afaict)
well-formed:
template<int N>
struct S {
friend void f(int) requires (N == 0) { }
operator int() const { return 0; }
};
int main() {
f(S<0>{});
}
whereas the following is ill-formed, as overload resolution rejects the friend
due to unsatisfied constraints:
template<int N>
struct S {
friend void f(int) requires (N == 0) { }
operator int() const { return 0; }
};
int main() {
f(S<1>{});
// error: no matching function for call to 'f'
// candidate function not viable: constraints not satisfied
}
and GCC correctly accepts and rejects these two examples, respectively.
However, the following program is also rejected by GCC:
template<int N>
struct S {
friend void f(int) requires (N == 0) { }
operator int() const { return 0; }
};
S<1> s1{};
S<2> s2{};
// error: redefinition of 'void foo(int) requires N == 0'
implying that GCC, for each instantiation of the class template S, also
instantiates its constrained friend definitions, even those where the
associated constraints are not satisfied, meaning more than a single
instantiation in a single TU fails due to and ODR-violation
([basic.def.odr]/1). It basically acts the same way as for hidden friend
definitions prior to constrained (non-templated) friends.
I have not been able to sort out whether the final example above is actually
well-formed as per N4861, but it's arguably weird if US115 added support for
constrained non-template (hidden) friends whilst not allowing overloading
solely on the constraint. As per [temp.friend]/9 each constrained hidden friend
is indeed unique (to its specialization), which is also supported by
[defns.signature.friend].
Constraint satisfaction should arguably be checked in the context of the
template instantiation and not only during overload resolution.
---
(MSVC accepts the final example above, but fails with ambiguous call errors
during overload resolution if we start overloading constrainded non-template
friends solely on their constraints. Clang has fails this feature for other
reasons; failing [defns.signature.friend] w.r.t. unique mangled names if we add
another overload with another constraint).