Index: libcxx/docs/Status/Cxx2bIssues.csv =================================================================== --- libcxx/docs/Status/Cxx2bIssues.csv +++ libcxx/docs/Status/Cxx2bIssues.csv @@ -294,7 +294,7 @@ "`3843 `__","``std::expected::value() &`` assumes ``E`` is copy constructible","February 2023","","","" "`3847 `__","``ranges::to`` can still return views","February 2023","","","|ranges|" "`3862 `__","``basic_const_iterator``'s ``common_type`` specialization is underconstrained","February 2023","","","" -"`3865 `__","Sorting a range of ``pairs``","February 2023","","","|ranges|" +"`3865 `__","Sorting a range of ``pairs``","February 2023","|Complete|","17.0","|ranges|" "`3869 `__","Deprecate ``std::errc`` constants related to UNIX STREAMS","February 2023","","","" "`3870 `__","Remove ``voidify``","February 2023","","","" "`3871 `__","Adjust note about ``terminate``","February 2023","","","" Index: libcxx/include/__utility/pair.h =================================================================== --- libcxx/include/__utility/pair.h +++ libcxx/include/__utility/pair.h @@ -424,22 +424,22 @@ // [pairs.spec], specialized algorithms -template +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool -operator==(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y) +operator==(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return __x.first == __y.first && __x.second == __y.second; } #if _LIBCPP_STD_VER >= 20 -template +template _LIBCPP_HIDE_FROM_ABI constexpr common_comparison_category_t< - __synth_three_way_result<_T1>, - __synth_three_way_result<_T2> > -operator<=>(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y) + __synth_three_way_result<_T1, _U1>, + __synth_three_way_result<_T2, _U2> > +operator<=>(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { if (auto __c = std::__synth_three_way(__x.first, __y.first); __c != 0) { return __c; @@ -449,42 +449,42 @@ #else // _LIBCPP_STD_VER >= 20 -template +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool -operator!=(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y) +operator!=(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return !(__x == __y); } -template +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool -operator< (const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y) +operator< (const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return __x.first < __y.first || (!(__y.first < __x.first) && __x.second < __y.second); } -template +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool -operator> (const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y) +operator> (const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return __y < __x; } -template +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool -operator>=(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y) +operator>=(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return !(__x < __y); } -template +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool -operator<=(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y) +operator<=(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return !(__y < __x); } Index: libcxx/include/utility =================================================================== --- libcxx/include/utility +++ libcxx/include/utility @@ -117,22 +117,22 @@ template pair(T1, T2) -> pair; -template -bool operator==(const pair&, const pair&); // constexpr in C++14 -template -bool operator!=(const pair&, const pair&); // constexpr in C++14, removed in C++20 -template -bool operator< (const pair&, const pair&); // constexpr in C++14, removed in C++20 -template -bool operator> (const pair&, const pair&); // constexpr in C++14, removed in C++20 -template -bool operator>=(const pair&, const pair&); // constexpr in C++14, removed in C++20 -template -bool operator<=(const pair&, const pair&); // constexpr in C++14, removed in C++20 -template - constexpr common_comparison_type_t, - synth-three-way-result> - operator<=>(const pair&, const pair&); // C++20 +template +bool operator==(const pair&, const pair&); // constexpr in C++14 +template +bool operator!=(const pair&, const pair&); // constexpr in C++14, removed in C++20 +template +bool operator< (const pair&, const pair&); // constexpr in C++14, removed in C++20 +template +bool operator> (const pair&, const pair&); // constexpr in C++14, removed in C++20 +template +bool operator>=(const pair&, const pair&); // constexpr in C++14, removed in C++20 +template +bool operator<=(const pair&, const pair&); // constexpr in C++14, removed in C++20 +template + constexpr common_comparison_type_t, + synth-three-way-result> + operator<=>(const pair&, const pair&); // C++20 template pair make_pair(T1&&, T2&&); // constexpr in C++14 template Index: libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp =================================================================== --- libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp +++ libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp @@ -61,12 +61,6 @@ return std::make_from_tuple(std::forward(tup)).args == tup; } -// Needed by do_forwarding_test() since it compares pairs of different types. -template -inline bool operator==(const std::pair& lhs, const std::pair& rhs) { - return lhs.first == rhs.first && lhs.second == rhs.second; -} - template bool do_forwarding_test(Tuple&& tup) { using RawTuple = std::decay_t; Index: libcxx/test/std/utilities/utility/pairs/pairs.spec/comparison.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/pairs/pairs.spec/comparison.pass.cpp +++ libcxx/test/std/utilities/utility/pairs/pairs.spec/comparison.pass.cpp @@ -10,12 +10,12 @@ // template struct pair -// template bool operator==(const pair&, const pair&); -// template bool operator!=(const pair&, const pair&); -// template bool operator< (const pair&, const pair&); -// template bool operator> (const pair&, const pair&); -// template bool operator>=(const pair&, const pair&); -// template bool operator<=(const pair&, const pair&); +// template bool operator==(const pair&, const pair&); +// template bool operator!=(const pair&, const pair&); +// template bool operator< (const pair&, const pair&); +// template bool operator> (const pair&, const pair&); +// template bool operator>=(const pair&, const pair&); +// template bool operator<=(const pair&, const pair&); #include #include @@ -24,6 +24,18 @@ int main(int, char**) { + { + typedef std::pair P1; + typedef std::pair P2; + P1 p1(3, static_cast(4)); + P2 p2(3, 4); + assert( (p1 == p2)); + assert(!(p1 != p2)); + assert(!(p1 < p2)); + assert( (p1 <= p2)); + assert(!(p1 > p2)); + assert( (p1 >= p2)); + } { typedef std::pair P; P p1(3, static_cast(4)); Index: libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp +++ libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp @@ -10,7 +10,9 @@ // template struct pair -// template bool operator<=>(const pair&, const pair&); +// template +// constexpr common_comparison_category_t,synth-three-way-result> +// operator<=>(const pair&, const pair&); // UNSUPPORTED: c++03, c++11, c++14, c++17 @@ -19,14 +21,37 @@ #include #include // std::is_constant_evaluated #include +#include #include "test_macros.h" -template concept HasEqual = requires(T t) { t == t; }; -template concept HasLess = requires(T t) { t < t; }; -template concept HasSpaceship = requires(T t) { t <=> t; }; +template +concept HasEqual = requires(T t) { t == t; }; +template +concept HasLess = requires(T t) { t < t; }; +template +concept HasSpaceship = requires(T t, U u) { t <=> u; }; constexpr bool test() { + { + // Pairs of different types should compare with strong ordering. + using P1 = std::pair; + using P2 = std::pair; + ASSERT_SAME_TYPE(decltype(P1() <=> P2()), std::strong_ordering); + assert((P1(1, 1) <=> P2(1, 2)) == std::strong_ordering::less); + assert((P1(2, 1) <=> P2(1, 2)) == std::strong_ordering::greater); + assert((P1(0, 0) <=> P2(0, 0)) == std::strong_ordering::equal); + } + { + // Pairs of different types should compare with partial ordering. + using P1 = std::pair; + using P2 = std::pair; + ASSERT_SAME_TYPE(decltype(P1() <=> P2()), std::partial_ordering); + assert((P1(1, 1) <=> P2(1.0, 2.0)) == std::partial_ordering::less); + assert((P1(2, 1) <=> P2(1.0, 2.0)) == std::partial_ordering::greater); + assert((P1(0, 0) <=> P2(0.0, 0.0)) == std::partial_ordering::equivalent); + } + { static_assert(!HasSpaceship, std::pair>); } { // Pairs of types that both have strong ordering should compare with strong ordering. using P = std::pair; @@ -50,7 +75,7 @@ } { // Pairs of int (strongly ordered) and double (partially ordered) should compare with partial ordering. - using P = std::pair; + using P = std::pair; constexpr double nan = std::numeric_limits::quiet_NaN(); ASSERT_SAME_TYPE(decltype(P() <=> P()), std::partial_ordering); assert((P(1, 1.0) <=> P(1, 2.0)) == std::partial_ordering::less); @@ -62,7 +87,7 @@ assert((P(1, nan) <=> P(1, nan)) == std::partial_ordering::unordered); } { - using P = std::pair; + using P = std::pair; constexpr double nan = std::numeric_limits::quiet_NaN(); ASSERT_SAME_TYPE(decltype(P() <=> P()), std::partial_ordering); assert((P(2.0, 1) <=> P(1.0, 2)) == std::partial_ordering::greater); @@ -93,12 +118,12 @@ #endif { { - using P = std::pair; + using P = std::pair; constexpr double nan = std::numeric_limits::quiet_NaN(); assert((P(1, 2.0) <=> P(1, nan)) == std::partial_ordering::unordered); } { - using P = std::pair; + using P = std::pair; constexpr double nan = std::numeric_limits::quiet_NaN(); assert((P(1.0, 1) <=> P(nan, 2)) == std::partial_ordering::unordered); }