-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
While implementing <=> support for std::optional we stumbled across what appears to be constraint recursion for the operator<=> signature specified in [optional.comp.with.t]/25 when the second argument is a specialization of optional. Specifically, checking three_way_comparable_with seems to recurse via checking the constraint that e.g. < is viable for operator<(const optional<T>&, const optional<U>&), which it certainly is if <=> is provided by the first signature. We avoided the recursion by adding an additional constraint to the first signature requiring that U is not a specialization of optional, which is checked before the three_way_comparable_with constraint.
Lines 646 to 650 in 4c862ee
| template <class _Ty1, class _Ty2> | |
| requires (!_Is_specialization_v<_Ty2, optional>) // TRANSITION, GH-1674 | |
| && three_way_comparable_with<_Ty1, _Ty2> | |
| _NODISCARD constexpr compare_three_way_result_t<_Ty1, _Ty2> | |
| operator<=>(const optional<_Ty1>& _Left, const _Ty2& _Right) { |
Looking at it now (with the workaround disabled) the recursion only manifests when compiling with Clang. Given how differently Clang and MSVC handle C++20 relational operator rewrites it's not clear to me if the constraint recursion is real or an artifact of said rewrites in Clang. We need to reduce this to something library-free and then determine whether the bug is in Clang or the C++ Standard and deal with it appropriately. (I will nonetheless tag this "LWG issue needed" for the time being.)