https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104606
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |ASSIGNED Assignee|unassigned at gcc dot gnu.org |redi at gcc dot gnu.org --- Comment #12 from Jonathan Wakely <redi at gcc dot gnu.org> --- std::optional's spaceship operator currently looks like this: template<typename _Tp, typename _Up> requires (!__is_optional_v<_Up>) && three_way_comparable_with<_Tp, _Up> constexpr compare_three_way_result_t<_Tp, _Up> operator<=>(const optional<_Tp>& __x, const _Up& __v) As Jakub noted, if we revert the LWG 3566 change it works: template<typename _Tp, three_way_comparable_with<_Tp> _Up> constexpr compare_three_way_result_t<_Tp, _Up> operator<=>(const optional<_Tp>& __x, const _Up& __v) We can rewrite that to this, which should be exactly equivalent, and it still works: template<typename _Tp, typename _Up> requires three_way_comparable_with<_Up, _Tp> constexpr compare_three_way_result_t<_Tp, _Up> operator<=>(const optional<_Tp>& __x, const _Up& __v) and then we can add the !is-optional<U> constraint back in: template<typename _Tp, typename _Up> requires (!__is_optional_v<_Up>) && three_way_comparable_with<_Up, _Tp> constexpr compare_three_way_result_t<_Tp, _Up> operator<=>(const optional<_Tp>& __x, const _Up& __v) And it still works! The only difference is: three_way_comparable_with<_Up, _Tp> vs three_way_comparable_with<_Tp, _Up> This should not matter, but it does. So there definitely seems to be a front end bug here, but at least there's an easy fix for the library.