From eddf626d235030c52f1540573396b74e149f51c4 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 16 Jul 2020 09:44:02 -0700 Subject: [PATCH 01/11] Remove obsolete conditional compilation from Now that EDG has caught up to `__cpp_impl_three_way_comparison == 201907`, we no longer need "downlevel" compatibility for C++20 compilers that either don't define the feature-test macro or define it to a lesser value. --- stl/inc/compare | 52 +------------------ .../tests/P0768R1_spaceship_operator/test.cpp | 16 ++---- 2 files changed, 6 insertions(+), 62 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index 389b5b58aa..e1ee0036fe 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -53,21 +53,7 @@ public: return _Val._Value == 0; } -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator==(const partial_ordering&, const partial_ordering&) noexcept = default; -#else // ^^^ supports <=> and P1185 / supports neither vvv - _NODISCARD friend constexpr bool operator!=(const partial_ordering _Val, _Literal_zero) noexcept { - return _Val._Value != 0; - } - - _NODISCARD friend constexpr bool operator==(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 == _Val._Value; - } - - _NODISCARD friend constexpr bool operator!=(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 != _Val._Value; - } -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator<(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value == static_cast<_Compare_t>(_Compare_ord::less); @@ -101,7 +87,6 @@ public: return 0 >= _Val._Value && _Val._Is_ordered(); } -#ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr partial_ordering operator<=>(const partial_ordering _Val, _Literal_zero) noexcept { return _Val; } @@ -109,7 +94,6 @@ public: _NODISCARD friend constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { return partial_ordering{static_cast<_Compare_ord>(-_Val._Value)}; } -#endif // __cpp_impl_three_way_comparison private: _NODISCARD constexpr bool _Is_ordered() const noexcept { @@ -144,21 +128,7 @@ public: return _Val._Value == 0; } -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator==(const weak_ordering&, const weak_ordering&) noexcept = default; -#else // ^^^ supports <=> and P1185 / supports neither vvv - _NODISCARD friend constexpr bool operator!=(const weak_ordering _Val, _Literal_zero) noexcept { - return _Val._Value != 0; - } - - _NODISCARD friend constexpr bool operator==(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 == _Val._Value; - } - - _NODISCARD friend constexpr bool operator!=(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 != _Val._Value; - } -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator<(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; @@ -192,7 +162,6 @@ public: return 0 >= _Val._Value; } -#ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr weak_ordering operator<=>(const weak_ordering _Val, _Literal_zero) noexcept { return _Val; } @@ -200,7 +169,6 @@ public: _NODISCARD friend constexpr weak_ordering operator<=>(_Literal_zero, const weak_ordering _Val) noexcept { return weak_ordering{static_cast<_Compare_ord>(-_Val._Value)}; } -#endif // __cpp_impl_three_way_comparison private: _Compare_t _Value; @@ -235,21 +203,7 @@ public: return _Val._Value == 0; } -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator==(const strong_ordering&, const strong_ordering&) noexcept = default; -#else // ^^^ supports <=> and P1185 / supports neither vvv - _NODISCARD friend constexpr bool operator!=(const strong_ordering _Val, _Literal_zero) noexcept { - return _Val._Value != 0; - } - - _NODISCARD friend constexpr bool operator==(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 == _Val._Value; - } - - _NODISCARD friend constexpr bool operator!=(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 != _Val._Value; - } -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD friend constexpr bool operator<(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; @@ -283,7 +237,6 @@ public: return 0 >= _Val._Value; } -#ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr strong_ordering operator<=>(const strong_ordering _Val, _Literal_zero) noexcept { return _Val; } @@ -291,7 +244,6 @@ public: _NODISCARD friend constexpr strong_ordering operator<=>(_Literal_zero, const strong_ordering _Val) noexcept { return strong_ordering{static_cast<_Compare_ord>(-_Val._Value)}; } -#endif // __cpp_impl_three_way_comparison private: _Compare_t _Value; @@ -364,7 +316,7 @@ struct common_comparison_category { using type = common_comparison_category_t<_Types...>; }; -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts // clang-format off template concept _Compares_as = same_as, _Cat>; @@ -409,7 +361,7 @@ struct compare_three_way { using is_transparent = int; }; // clang-format on -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts // Other components not yet implemented _STD_END diff --git a/tests/std/tests/P0768R1_spaceship_operator/test.cpp b/tests/std/tests/P0768R1_spaceship_operator/test.cpp index 09a23f15d6..03961c59b2 100644 --- a/tests/std/tests/P0768R1_spaceship_operator/test.cpp +++ b/tests/std/tests/P0768R1_spaceship_operator/test.cpp @@ -15,15 +15,11 @@ constexpr bool test_ord(T val) { assert((0 == val) == (Z == comp::equal)); assert((val != 0) == (Z != comp::equal)); assert((0 != val) == (Z != comp::equal)); -#ifdef __cpp_impl_three_way_comparison assert(((val <=> 0) == 0) == (Z == comp::equal)); assert(((0 <=> val) == 0) == (Z == comp::equal)); -#if __cpp_impl_three_way_comparison >= 201907L assert(val == val); assert(!(val != val)); -#endif // __cpp_impl_three_way_comparison >= 201907L -#endif // __cpp_impl_three_way_comparison assert(std::is_eq(val) == (Z == comp::equal)); assert(std::is_neq(val) == (Z != comp::equal)); @@ -35,15 +31,11 @@ constexpr bool test_ord(T val) { assert((0 >= val) == (Z != comp::greater && Z != comp::unordered)); assert((val >= 0) == (Z != comp::less && Z != comp::unordered)); assert((0 <= val) == (Z != comp::less && Z != comp::unordered)); -#ifdef __cpp_impl_three_way_comparison assert(((val <=> 0) < 0) == (Z == comp::less)); assert(((0 <=> val) < 0) == (Z == comp::greater)); -#if __cpp_impl_three_way_comparison >= 201907L assert(val == val); assert(!(val != val)); -#endif // __cpp_impl_three_way_comparison >= 201907L -#endif // __cpp_impl_three_way_comparison assert(std::is_lt(val) == (Z == comp::less)); assert(std::is_lteq(val) == (Z != comp::greater && Z != comp::unordered)); assert(std::is_gt(val) == (Z == comp::greater)); @@ -121,7 +113,7 @@ static_assert(test_common_type()); static_assert(test_common_type()); static_assert(test_common_type()); -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts constexpr auto my_cmp_three_way = [](const auto& left, const auto& right) { return left <=> right; }; template @@ -187,7 +179,7 @@ void test_algorithm() { assert((test_algorithm2())); assert((test_algorithm2())); } -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts int main() { test_ord(std::partial_ordering::equivalent); @@ -204,12 +196,12 @@ int main() { test_ord(std::strong_ordering::less); test_ord(std::strong_ordering::greater); -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts test_algorithm(); test_algorithm(); test_algorithm(); test_algorithm(); test_algorithm(); test_algorithm(); -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts } From 381d91bb253bb325c33e5d6b6aa5c9c7c7989360 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 16 Jul 2020 13:32:52 -0700 Subject: [PATCH 02/11] Break ABI again, and fix #1050 --- stl/inc/compare | 14 +-- .../tests/P0768R1_spaceship_operator/test.cpp | 94 +++++++++++++++++++ 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index e1ee0036fe..a7110d8417 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -32,7 +32,7 @@ using _Compare_t = signed char; // These "pretty" enumerator names are safe since they reuse names of user-facing entities. enum class _Compare_eq : _Compare_t { equal = 0, equivalent = equal }; enum class _Compare_ord : _Compare_t { less = -1, greater = 1 }; -enum class _Compare_ncmp : _Compare_t { unordered = -127 }; +enum class _Compare_ncmp : _Compare_t { unordered = -128 }; // CLASS partial_ordering class partial_ordering { @@ -64,7 +64,7 @@ public: } _NODISCARD friend constexpr bool operator<=(const partial_ordering _Val, _Literal_zero) noexcept { - return _Val._Value <= 0 && _Val._Is_ordered(); + return static_cast(static_cast(_Val._Value) - 1) < 0; } _NODISCARD friend constexpr bool operator>=(const partial_ordering _Val, _Literal_zero) noexcept { @@ -72,19 +72,19 @@ public: } _NODISCARD friend constexpr bool operator<(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 < _Val._Value; + return _Val._Value > 0; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 > _Val._Value && _Val._Is_ordered(); + return _Val._Value == static_cast<_Compare_t>(_Compare_ord::less); } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 <= _Val._Value; + return _Val._Value >= 0; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 >= _Val._Value && _Val._Is_ordered(); + return static_cast(static_cast(_Val._Value) - 1) < 0; } _NODISCARD friend constexpr partial_ordering operator<=>(const partial_ordering _Val, _Literal_zero) noexcept { @@ -92,7 +92,7 @@ public: } _NODISCARD friend constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { - return partial_ordering{static_cast<_Compare_ord>(-_Val._Value)}; + return partial_ordering{static_cast<_Compare_ord>(0 - static_cast(_Val._Value))}; } private: diff --git a/tests/std/tests/P0768R1_spaceship_operator/test.cpp b/tests/std/tests/P0768R1_spaceship_operator/test.cpp index 03961c59b2..fbcbbfecdc 100644 --- a/tests/std/tests/P0768R1_spaceship_operator/test.cpp +++ b/tests/std/tests/P0768R1_spaceship_operator/test.cpp @@ -181,6 +181,100 @@ void test_algorithm() { } #endif // __cpp_lib_concepts +// Guard against regression of GH-1050: 0 <=> partial_ordering::unordered returns invalid value +static_assert(!(std::partial_ordering::less == 0)); +static_assert(std::partial_ordering::less != 0); +static_assert(std::partial_ordering::less < 0); +static_assert(!(std::partial_ordering::less > 0)); +static_assert(std::partial_ordering::less <= 0); +static_assert(!(std::partial_ordering::less >= 0)); + +static_assert(std::partial_ordering::equivalent == 0); +static_assert(!(std::partial_ordering::equivalent != 0)); +static_assert(!(std::partial_ordering::equivalent < 0)); +static_assert(!(std::partial_ordering::equivalent > 0)); +static_assert(std::partial_ordering::equivalent <= 0); +static_assert(std::partial_ordering::equivalent >= 0); + +static_assert(!(std::partial_ordering::greater == 0)); +static_assert(std::partial_ordering::greater != 0); +static_assert(!(std::partial_ordering::greater < 0)); +static_assert(std::partial_ordering::greater > 0); +static_assert(!(std::partial_ordering::greater <= 0)); +static_assert(std::partial_ordering::greater >= 0); + +static_assert(!(std::partial_ordering::unordered == 0)); +static_assert(std::partial_ordering::unordered != 0); +static_assert(!(std::partial_ordering::unordered < 0)); +static_assert(!(std::partial_ordering::unordered > 0)); +static_assert(!(std::partial_ordering::unordered <= 0)); +static_assert(!(std::partial_ordering::unordered >= 0)); + +static_assert(std::partial_ordering::less <=> 0 == std::partial_ordering::less); +static_assert(0 <=> std::partial_ordering::less == std::partial_ordering::greater); +static_assert(std::partial_ordering::equivalent <=> 0 == std::partial_ordering::equivalent); +static_assert(0 <=> std::partial_ordering::equivalent == std::partial_ordering::equivalent); +static_assert(std::partial_ordering::greater <=> 0 == std::partial_ordering::greater); +static_assert(0 <=> std::partial_ordering::greater == std::partial_ordering::less); +static_assert(std::partial_ordering::unordered <=> 0 == std::partial_ordering::unordered); +static_assert(0 <=> std::partial_ordering::unordered == std::partial_ordering::unordered); + +static_assert(!(std::weak_ordering::less == 0)); +static_assert(std::weak_ordering::less != 0); +static_assert(std::weak_ordering::less < 0); +static_assert(!(std::weak_ordering::less > 0)); +static_assert(std::weak_ordering::less <= 0); +static_assert(!(std::weak_ordering::less >= 0)); + +static_assert(std::weak_ordering::equivalent == 0); +static_assert(!(std::weak_ordering::equivalent != 0)); +static_assert(!(std::weak_ordering::equivalent < 0)); +static_assert(!(std::weak_ordering::equivalent > 0)); +static_assert(std::weak_ordering::equivalent <= 0); +static_assert(std::weak_ordering::equivalent >= 0); + +static_assert(!(std::weak_ordering::greater == 0)); +static_assert(std::weak_ordering::greater != 0); +static_assert(!(std::weak_ordering::greater < 0)); +static_assert(std::weak_ordering::greater > 0); +static_assert(!(std::weak_ordering::greater <= 0)); +static_assert(std::weak_ordering::greater >= 0); + +static_assert(std::weak_ordering::less <=> 0 == std::weak_ordering::less); +static_assert(0 <=> std::weak_ordering::less == std::weak_ordering::greater); +static_assert(std::weak_ordering::equivalent <=> 0 == std::weak_ordering::equivalent); +static_assert(0 <=> std::weak_ordering::equivalent == std::weak_ordering::equivalent); +static_assert(std::weak_ordering::greater <=> 0 == std::weak_ordering::greater); +static_assert(0 <=> std::weak_ordering::greater == std::weak_ordering::less); + +static_assert(!(std::strong_ordering::less == 0)); +static_assert(std::strong_ordering::less != 0); +static_assert(std::strong_ordering::less < 0); +static_assert(!(std::strong_ordering::less > 0)); +static_assert(std::strong_ordering::less <= 0); +static_assert(!(std::strong_ordering::less >= 0)); + +static_assert(std::strong_ordering::equal == 0); +static_assert(!(std::strong_ordering::equal != 0)); +static_assert(!(std::strong_ordering::equal < 0)); +static_assert(!(std::strong_ordering::equal > 0)); +static_assert(std::strong_ordering::equal <= 0); +static_assert(std::strong_ordering::equal >= 0); + +static_assert(!(std::strong_ordering::greater == 0)); +static_assert(std::strong_ordering::greater != 0); +static_assert(!(std::strong_ordering::greater < 0)); +static_assert(std::strong_ordering::greater > 0); +static_assert(!(std::strong_ordering::greater <= 0)); +static_assert(std::strong_ordering::greater >= 0); + +static_assert(std::strong_ordering::less <=> 0 == std::strong_ordering::less); +static_assert(0 <=> std::strong_ordering::less == std::strong_ordering::greater); +static_assert(std::strong_ordering::equal <=> 0 == std::strong_ordering::equal); +static_assert(0 <=> std::strong_ordering::equal == std::strong_ordering::equal); +static_assert(std::strong_ordering::greater <=> 0 == std::strong_ordering::greater); +static_assert(0 <=> std::strong_ordering::greater == std::strong_ordering::less); + int main() { test_ord(std::partial_ordering::equivalent); test_ord(std::partial_ordering::less); From 0803efa4aaf3d34850f60937e246a0325baa57f7 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 16 Jul 2020 17:21:22 -0700 Subject: [PATCH 03/11] Review comments --- stl/inc/compare | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index a7110d8417..9fa1148543 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -72,19 +72,19 @@ public: } _NODISCARD friend constexpr bool operator<(_Literal_zero, const partial_ordering _Val) noexcept { - return _Val._Value > 0; + return _Val > 0; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const partial_ordering _Val) noexcept { - return _Val._Value == static_cast<_Compare_t>(_Compare_ord::less); + return _Val < 0; } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const partial_ordering _Val) noexcept { - return _Val._Value >= 0; + return _Val >= 0; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const partial_ordering _Val) noexcept { - return static_cast(static_cast(_Val._Value) - 1) < 0; + return _Val <= 0; } _NODISCARD friend constexpr partial_ordering operator<=>(const partial_ordering _Val, _Literal_zero) noexcept { @@ -92,7 +92,7 @@ public: } _NODISCARD friend constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { - return partial_ordering{static_cast<_Compare_ord>(0 - static_cast(_Val._Value))}; + return partial_ordering{static_cast<_Compare_ord>(0 - static_cast(_Val._Value))}; } private: @@ -147,19 +147,19 @@ public: } _NODISCARD friend constexpr bool operator<(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 < _Val._Value; + return _Val > 0; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 > _Val._Value; + return _Val < 0; } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 <= _Val._Value; + return _Val >= 0; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 >= _Val._Value; + return _Val <= 0; } _NODISCARD friend constexpr weak_ordering operator<=>(const weak_ordering _Val, _Literal_zero) noexcept { @@ -222,19 +222,19 @@ public: } _NODISCARD friend constexpr bool operator<(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 < _Val._Value; + return _Val > 0; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 > _Val._Value; + return _Val < 0; } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 <= _Val._Value; + return _Val >= 0; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 >= _Val._Value; + return _Val <= 0; } _NODISCARD friend constexpr strong_ordering operator<=>(const strong_ordering _Val, _Literal_zero) noexcept { From 6a1e8d90c8f1f291f08a7f210599da16461ed1a0 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 16 Jul 2020 18:07:15 -0700 Subject: [PATCH 04/11] Audit for all occurrences of __cpp_impl_three_way_comparison --- stl/inc/span | 30 +----------------------------- stl/inc/xutility | 31 ++++++++----------------------- 2 files changed, 9 insertions(+), 52 deletions(-) diff --git a/stl/inc/span b/stl/inc/span index d61d8e375f..8565955bfc 100644 --- a/stl/inc/span +++ b/stl/inc/span @@ -12,13 +12,11 @@ #if !_HAS_CXX20 #pragma message("The contents of are available only with C++20 or later.") #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv +#include #include #include #include -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L -#include -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -153,7 +151,6 @@ struct _Span_iterator { return _Myptr == _Right._Myptr; } -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD constexpr strong_ordering operator<=>(const _Span_iterator& _Right) const noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 _STL_VERIFY( @@ -161,31 +158,6 @@ struct _Span_iterator { #endif // _ITERATOR_DEBUG_LEVEL >= 1 return _Myptr <=> _Right._Myptr; } -#else // ^^^ use spaceship / no spaceship vvv - _NODISCARD constexpr bool operator!=(const _Span_iterator& _Right) const noexcept { - return !(*this == _Right); - } - - _NODISCARD constexpr bool operator<(const _Span_iterator& _Right) const noexcept { -#if _ITERATOR_DEBUG_LEVEL >= 1 - _STL_VERIFY( - _Mybegin == _Right._Mybegin && _Myend == _Right._Myend, "cannot compare incompatible span iterators"); -#endif // _ITERATOR_DEBUG_LEVEL >= 1 - return _Myptr < _Right._Myptr; - } - - _NODISCARD constexpr bool operator>(const _Span_iterator& _Right) const noexcept { - return _Right < *this; - } - - _NODISCARD constexpr bool operator<=(const _Span_iterator& _Right) const noexcept { - return !(_Right < *this); - } - - _NODISCARD constexpr bool operator>=(const _Span_iterator& _Right) const noexcept { - return !(*this < _Right); - } -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L #if _ITERATOR_DEBUG_LEVEL >= 1 friend constexpr void _Verify_range(const _Span_iterator& _First, const _Span_iterator& _Last) noexcept { diff --git a/stl/inc/xutility b/stl/inc/xutility index 26299d2612..e136b2d0b4 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2105,13 +2105,13 @@ _NODISCARD _CONSTEXPR17 bool operator>=(const reverse_iterator<_BidIt1>& _Left, #endif // __cpp_lib_concepts { return _Left._Get_current() <= _Right._Get_current(); } -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts template _BidIt2> _NODISCARD constexpr compare_three_way_result_t<_BidIt1, _BidIt2> operator<=>( const reverse_iterator<_BidIt1>& _Left, const reverse_iterator<_BidIt2>& _Right) { return _Right._Get_current() <=> _Left._Get_current(); } -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts template _NODISCARD _CONSTEXPR17 auto operator-(const reverse_iterator<_BidIt1>& _Left, const reverse_iterator<_BidIt2>& _Right) @@ -4103,12 +4103,12 @@ _NODISCARD _CONSTEXPR17 bool operator==(const move_iterator<_Iter1>& _Left, cons #endif // __cpp_lib_concepts { return _Left.base() == _Right.base(); } -#if !_HAS_CXX20 || __cpp_impl_three_way_comparison < 201902L +#if !_HAS_CXX20 template _NODISCARD _CONSTEXPR17 bool operator!=(const move_iterator<_Iter1>& _Left, const move_iterator<_Iter2>& _Right) { return !(_Left == _Right); } -#endif // !_HAS_CXX20 || __cpp_impl_three_way_comparison < 201902L +#endif // !_HAS_CXX20 template _NODISCARD _CONSTEXPR17 bool operator<(const move_iterator<_Iter1>& _Left, const move_iterator<_Iter2>& _Right) @@ -4148,13 +4148,13 @@ _NODISCARD _CONSTEXPR17 bool operator>=(const move_iterator<_Iter1>& _Left, cons #endif // __cpp_lib_concepts { return !(_Left < _Right); } -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts template _Iter2> _NODISCARD constexpr compare_three_way_result_t<_Iter1, _Iter2> operator<=>( const move_iterator<_Iter1>& _Left, const move_iterator<_Iter2>& _Right) { return _Left.base() <=> _Right.base(); } -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts template _NODISCARD _CONSTEXPR17 auto operator-(const move_iterator<_Iter1>& _Left, const move_iterator<_Iter2>& _Right) @@ -4195,21 +4195,6 @@ namespace _Unreachable_sentinel_detail { _NODISCARD friend constexpr bool operator==(const unreachable_sentinel_t&, const _Winc&) noexcept { return false; } -#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L - template - _NODISCARD friend constexpr bool operator==(const _Winc&, const unreachable_sentinel_t&) noexcept { - return false; - } - - template - _NODISCARD friend constexpr bool operator!=(const unreachable_sentinel_t&, const _Winc&) noexcept { - return true; - } - template - _NODISCARD friend constexpr bool operator!=(const _Winc&, const unreachable_sentinel_t&) noexcept { - return true; - } -#endif // !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L }; } // namespace _Unreachable_sentinel_detail struct unreachable_sentinel_t : _Unreachable_sentinel_detail::_Base {}; // TRANSITION, /permissive- @@ -5231,7 +5216,7 @@ _NODISCARD bool lexicographical_compare( } #endif // _HAS_CXX17 -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts // FUNCTION TEMPLATE lexicographical_compare_three_way template _NODISCARD constexpr auto lexicographical_compare_three_way( @@ -5289,7 +5274,7 @@ _NODISCARD constexpr auto lexicographical_compare_three_way( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { return _STD lexicographical_compare_three_way(_First1, _Last1, _First2, _Last2, compare_three_way{}); } -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts // FUNCTION TEMPLATE find template From 7dffee7c329daab5fcf2956bc6202788ef705c29 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 16 Jul 2020 18:52:06 -0700 Subject: [PATCH 05/11] Test 0 < MEOW --- .../tests/P0768R1_spaceship_operator/test.cpp | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/std/tests/P0768R1_spaceship_operator/test.cpp b/tests/std/tests/P0768R1_spaceship_operator/test.cpp index fbcbbfecdc..fce2c6bb7f 100644 --- a/tests/std/tests/P0768R1_spaceship_operator/test.cpp +++ b/tests/std/tests/P0768R1_spaceship_operator/test.cpp @@ -210,6 +210,34 @@ static_assert(!(std::partial_ordering::unordered > 0)); static_assert(!(std::partial_ordering::unordered <= 0)); static_assert(!(std::partial_ordering::unordered >= 0)); +static_assert(!(0 == std::partial_ordering::less)); +static_assert(0 != std::partial_ordering::less); +static_assert(!(0 < std::partial_ordering::less)); +static_assert(0 > std::partial_ordering::less); +static_assert(!(0 <= std::partial_ordering::less)); +static_assert(0 >= std::partial_ordering::less); + +static_assert(0 == std::partial_ordering::equivalent); +static_assert(!(0 != std::partial_ordering::equivalent)); +static_assert(!(0 < std::partial_ordering::equivalent)); +static_assert(!(0 > std::partial_ordering::equivalent)); +static_assert(0 <= std::partial_ordering::equivalent); +static_assert(0 >= std::partial_ordering::equivalent); + +static_assert(!(0 == std::partial_ordering::greater)); +static_assert(0 != std::partial_ordering::greater); +static_assert(0 < std::partial_ordering::greater); +static_assert(!(0 > std::partial_ordering::greater)); +static_assert(0 <= std::partial_ordering::greater); +static_assert(!(0 >= std::partial_ordering::greater)); + +static_assert(!(0 == std::partial_ordering::unordered)); +static_assert(0 != std::partial_ordering::unordered); +static_assert(!(0 < std::partial_ordering::unordered)); +static_assert(!(0 > std::partial_ordering::unordered)); +static_assert(!(0 <= std::partial_ordering::unordered)); +static_assert(!(0 >= std::partial_ordering::unordered)); + static_assert(std::partial_ordering::less <=> 0 == std::partial_ordering::less); static_assert(0 <=> std::partial_ordering::less == std::partial_ordering::greater); static_assert(std::partial_ordering::equivalent <=> 0 == std::partial_ordering::equivalent); @@ -240,6 +268,27 @@ static_assert(std::weak_ordering::greater > 0); static_assert(!(std::weak_ordering::greater <= 0)); static_assert(std::weak_ordering::greater >= 0); +static_assert(!(0 == std::weak_ordering::less)); +static_assert(0 != std::weak_ordering::less); +static_assert(!(0 < std::weak_ordering::less)); +static_assert(0 > std::weak_ordering::less); +static_assert(!(0 <= std::weak_ordering::less)); +static_assert(0 >= std::weak_ordering::less); + +static_assert(0 == std::weak_ordering::equivalent); +static_assert(!(0 != std::weak_ordering::equivalent)); +static_assert(!(0 < std::weak_ordering::equivalent)); +static_assert(!(0 > std::weak_ordering::equivalent)); +static_assert(0 <= std::weak_ordering::equivalent); +static_assert(0 >= std::weak_ordering::equivalent); + +static_assert(!(0 == std::weak_ordering::greater)); +static_assert(0 != std::weak_ordering::greater); +static_assert(0 < std::weak_ordering::greater); +static_assert(!(0 > std::weak_ordering::greater)); +static_assert(0 <= std::weak_ordering::greater); +static_assert(!(0 >= std::weak_ordering::greater)); + static_assert(std::weak_ordering::less <=> 0 == std::weak_ordering::less); static_assert(0 <=> std::weak_ordering::less == std::weak_ordering::greater); static_assert(std::weak_ordering::equivalent <=> 0 == std::weak_ordering::equivalent); @@ -268,6 +317,27 @@ static_assert(std::strong_ordering::greater > 0); static_assert(!(std::strong_ordering::greater <= 0)); static_assert(std::strong_ordering::greater >= 0); +static_assert(!(0 == std::strong_ordering::less)); +static_assert(0 != std::strong_ordering::less); +static_assert(!(0 < std::strong_ordering::less)); +static_assert(0 > std::strong_ordering::less); +static_assert(!(0 <= std::strong_ordering::less)); +static_assert(0 >= std::strong_ordering::less); + +static_assert(0 == std::strong_ordering::equal); +static_assert(!(0 != std::strong_ordering::equal)); +static_assert(!(0 < std::strong_ordering::equal)); +static_assert(!(0 > std::strong_ordering::equal)); +static_assert(0 <= std::strong_ordering::equal); +static_assert(0 >= std::strong_ordering::equal); + +static_assert(!(0 == std::strong_ordering::greater)); +static_assert(0 != std::strong_ordering::greater); +static_assert(0 < std::strong_ordering::greater); +static_assert(!(0 > std::strong_ordering::greater)); +static_assert(0 <= std::strong_ordering::greater); +static_assert(!(0 >= std::strong_ordering::greater)); + static_assert(std::strong_ordering::less <=> 0 == std::strong_ordering::less); static_assert(0 <=> std::strong_ordering::less == std::strong_ordering::greater); static_assert(std::strong_ordering::equal <=> 0 == std::strong_ordering::equal); From 3b2ec709e1dd6bdf67ead66e0a2dc813e884774e Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 17 Jul 2020 10:10:55 -0700 Subject: [PATCH 06/11] Statementreply's review comments; eliminate redundant coverage --- stl/inc/compare | 10 +- .../tests/P0768R1_spaceship_operator/test.cpp | 261 ++++-------------- 2 files changed, 64 insertions(+), 207 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index 9fa1148543..ec8e5ae519 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -53,7 +53,7 @@ public: return _Val._Value == 0; } - _NODISCARD friend constexpr bool operator==(const partial_ordering&, const partial_ordering&) noexcept = default; + _NODISCARD friend constexpr bool operator==(partial_ordering, partial_ordering) noexcept = default; _NODISCARD friend constexpr bool operator<(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value == static_cast<_Compare_t>(_Compare_ord::less); @@ -96,10 +96,6 @@ public: } private: - _NODISCARD constexpr bool _Is_ordered() const noexcept { - return _Value != static_cast<_Compare_t>(_Compare_ncmp::unordered); - } - _Compare_t _Value; }; @@ -128,7 +124,7 @@ public: return _Val._Value == 0; } - _NODISCARD friend constexpr bool operator==(const weak_ordering&, const weak_ordering&) noexcept = default; + _NODISCARD friend constexpr bool operator==(weak_ordering, weak_ordering) noexcept = default; _NODISCARD friend constexpr bool operator<(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; @@ -203,7 +199,7 @@ public: return _Val._Value == 0; } - _NODISCARD friend constexpr bool operator==(const strong_ordering&, const strong_ordering&) noexcept = default; + _NODISCARD friend constexpr bool operator==(strong_ordering, strong_ordering) noexcept = default; _NODISCARD friend constexpr bool operator<(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; diff --git a/tests/std/tests/P0768R1_spaceship_operator/test.cpp b/tests/std/tests/P0768R1_spaceship_operator/test.cpp index fce2c6bb7f..8db594bf54 100644 --- a/tests/std/tests/P0768R1_spaceship_operator/test.cpp +++ b/tests/std/tests/P0768R1_spaceship_operator/test.cpp @@ -10,53 +10,86 @@ enum class comp { equal, nonequal, less, greater, unordered }; template -constexpr bool test_ord(T val) { +constexpr bool test_order(T val) { + // Validate that val is ordered relative to literal zero according to Z assert((val == 0) == (Z == comp::equal)); assert((0 == val) == (Z == comp::equal)); + assert((val != 0) == (Z != comp::equal)); assert((0 != val) == (Z != comp::equal)); - assert(((val <=> 0) == 0) == (Z == comp::equal)); - assert(((0 <=> val) == 0) == (Z == comp::equal)); - - assert(val == val); - assert(!(val != val)); - assert(std::is_eq(val) == (Z == comp::equal)); - assert(std::is_neq(val) == (Z != comp::equal)); assert((val < 0) == (Z == comp::less)); assert((0 > val) == (Z == comp::less)); + assert((val > 0) == (Z == comp::greater)); assert((0 < val) == (Z == comp::greater)); + assert((val <= 0) == (Z != comp::greater && Z != comp::unordered)); assert((0 >= val) == (Z != comp::greater && Z != comp::unordered)); + assert((val >= 0) == (Z != comp::less && Z != comp::unordered)); assert((0 <= val) == (Z != comp::less && Z != comp::unordered)); - assert(((val <=> 0) < 0) == (Z == comp::less)); - assert(((0 <=> val) < 0) == (Z == comp::greater)); - assert(val == val); - assert(!(val != val)); + assert(std::is_eq(val) == (Z == comp::equal)); + assert(std::is_neq(val) == (Z != comp::equal)); assert(std::is_lt(val) == (Z == comp::less)); assert(std::is_lteq(val) == (Z != comp::greater && Z != comp::unordered)); assert(std::is_gt(val) == (Z == comp::greater)); assert(std::is_gteq(val) == (Z != comp::less && Z != comp::unordered)); + // Validate that equality is reflexive for comparison category types + assert(val == val); + assert(!(val != val)); + return true; } -static_assert(test_ord(std::partial_ordering::equivalent)); -static_assert(test_ord(std::partial_ordering::less)); -static_assert(test_ord(std::partial_ordering::greater)); -static_assert(test_ord(std::partial_ordering::unordered)); +constexpr bool test_orderings() { + assert(test_order(std::partial_ordering::equivalent)); + assert(test_order(std::partial_ordering::less)); + assert(test_order(std::partial_ordering::greater)); + assert(test_order(std::partial_ordering::unordered)); + + assert(test_order(std::weak_ordering::equivalent)); + assert(test_order(std::weak_ordering::less)); + assert(test_order(std::weak_ordering::greater)); + + assert(test_order(std::strong_ordering::equal)); + assert(test_order(std::strong_ordering::equivalent)); + assert(test_order(std::strong_ordering::less)); + assert(test_order(std::strong_ordering::greater)); + + return true; +} -static_assert(test_ord(std::weak_ordering::equivalent)); -static_assert(test_ord(std::weak_ordering::less)); -static_assert(test_ord(std::weak_ordering::greater)); +constexpr bool test_spaceships() { + // Exhaustively validate x <=> 0 and 0 <=> x for all values of each comparison category type. + // Guards against regression of GH-1050: "0 <=> partial_ordering::unordered returns invalid value". + assert(std::partial_ordering::less <=> 0 == std::partial_ordering::less); + assert(0 <=> std::partial_ordering::less == std::partial_ordering::greater); + assert(std::partial_ordering::equivalent <=> 0 == std::partial_ordering::equivalent); + assert(0 <=> std::partial_ordering::equivalent == std::partial_ordering::equivalent); + assert(std::partial_ordering::greater <=> 0 == std::partial_ordering::greater); + assert(0 <=> std::partial_ordering::greater == std::partial_ordering::less); + assert(std::partial_ordering::unordered <=> 0 == std::partial_ordering::unordered); + assert(0 <=> std::partial_ordering::unordered == std::partial_ordering::unordered); + + assert(std::weak_ordering::less <=> 0 == std::weak_ordering::less); + assert(0 <=> std::weak_ordering::less == std::weak_ordering::greater); + assert(std::weak_ordering::equivalent <=> 0 == std::weak_ordering::equivalent); + assert(0 <=> std::weak_ordering::equivalent == std::weak_ordering::equivalent); + assert(std::weak_ordering::greater <=> 0 == std::weak_ordering::greater); + assert(0 <=> std::weak_ordering::greater == std::weak_ordering::less); + + assert(std::strong_ordering::less <=> 0 == std::strong_ordering::less); + assert(0 <=> std::strong_ordering::less == std::strong_ordering::greater); + assert(std::strong_ordering::equal <=> 0 == std::strong_ordering::equal); + assert(0 <=> std::strong_ordering::equal == std::strong_ordering::equal); + assert(std::strong_ordering::greater <=> 0 == std::strong_ordering::greater); + assert(0 <=> std::strong_ordering::greater == std::strong_ordering::less); -static_assert(test_ord(std::strong_ordering::equal)); -static_assert(test_ord(std::strong_ordering::equivalent)); -static_assert(test_ord(std::strong_ordering::less)); -static_assert(test_ord(std::strong_ordering::greater)); + return true; +} template constexpr bool test_common_cc = std::is_same_v, Expected>; @@ -181,184 +214,12 @@ void test_algorithm() { } #endif // __cpp_lib_concepts -// Guard against regression of GH-1050: 0 <=> partial_ordering::unordered returns invalid value -static_assert(!(std::partial_ordering::less == 0)); -static_assert(std::partial_ordering::less != 0); -static_assert(std::partial_ordering::less < 0); -static_assert(!(std::partial_ordering::less > 0)); -static_assert(std::partial_ordering::less <= 0); -static_assert(!(std::partial_ordering::less >= 0)); - -static_assert(std::partial_ordering::equivalent == 0); -static_assert(!(std::partial_ordering::equivalent != 0)); -static_assert(!(std::partial_ordering::equivalent < 0)); -static_assert(!(std::partial_ordering::equivalent > 0)); -static_assert(std::partial_ordering::equivalent <= 0); -static_assert(std::partial_ordering::equivalent >= 0); - -static_assert(!(std::partial_ordering::greater == 0)); -static_assert(std::partial_ordering::greater != 0); -static_assert(!(std::partial_ordering::greater < 0)); -static_assert(std::partial_ordering::greater > 0); -static_assert(!(std::partial_ordering::greater <= 0)); -static_assert(std::partial_ordering::greater >= 0); - -static_assert(!(std::partial_ordering::unordered == 0)); -static_assert(std::partial_ordering::unordered != 0); -static_assert(!(std::partial_ordering::unordered < 0)); -static_assert(!(std::partial_ordering::unordered > 0)); -static_assert(!(std::partial_ordering::unordered <= 0)); -static_assert(!(std::partial_ordering::unordered >= 0)); - -static_assert(!(0 == std::partial_ordering::less)); -static_assert(0 != std::partial_ordering::less); -static_assert(!(0 < std::partial_ordering::less)); -static_assert(0 > std::partial_ordering::less); -static_assert(!(0 <= std::partial_ordering::less)); -static_assert(0 >= std::partial_ordering::less); - -static_assert(0 == std::partial_ordering::equivalent); -static_assert(!(0 != std::partial_ordering::equivalent)); -static_assert(!(0 < std::partial_ordering::equivalent)); -static_assert(!(0 > std::partial_ordering::equivalent)); -static_assert(0 <= std::partial_ordering::equivalent); -static_assert(0 >= std::partial_ordering::equivalent); - -static_assert(!(0 == std::partial_ordering::greater)); -static_assert(0 != std::partial_ordering::greater); -static_assert(0 < std::partial_ordering::greater); -static_assert(!(0 > std::partial_ordering::greater)); -static_assert(0 <= std::partial_ordering::greater); -static_assert(!(0 >= std::partial_ordering::greater)); - -static_assert(!(0 == std::partial_ordering::unordered)); -static_assert(0 != std::partial_ordering::unordered); -static_assert(!(0 < std::partial_ordering::unordered)); -static_assert(!(0 > std::partial_ordering::unordered)); -static_assert(!(0 <= std::partial_ordering::unordered)); -static_assert(!(0 >= std::partial_ordering::unordered)); - -static_assert(std::partial_ordering::less <=> 0 == std::partial_ordering::less); -static_assert(0 <=> std::partial_ordering::less == std::partial_ordering::greater); -static_assert(std::partial_ordering::equivalent <=> 0 == std::partial_ordering::equivalent); -static_assert(0 <=> std::partial_ordering::equivalent == std::partial_ordering::equivalent); -static_assert(std::partial_ordering::greater <=> 0 == std::partial_ordering::greater); -static_assert(0 <=> std::partial_ordering::greater == std::partial_ordering::less); -static_assert(std::partial_ordering::unordered <=> 0 == std::partial_ordering::unordered); -static_assert(0 <=> std::partial_ordering::unordered == std::partial_ordering::unordered); - -static_assert(!(std::weak_ordering::less == 0)); -static_assert(std::weak_ordering::less != 0); -static_assert(std::weak_ordering::less < 0); -static_assert(!(std::weak_ordering::less > 0)); -static_assert(std::weak_ordering::less <= 0); -static_assert(!(std::weak_ordering::less >= 0)); - -static_assert(std::weak_ordering::equivalent == 0); -static_assert(!(std::weak_ordering::equivalent != 0)); -static_assert(!(std::weak_ordering::equivalent < 0)); -static_assert(!(std::weak_ordering::equivalent > 0)); -static_assert(std::weak_ordering::equivalent <= 0); -static_assert(std::weak_ordering::equivalent >= 0); - -static_assert(!(std::weak_ordering::greater == 0)); -static_assert(std::weak_ordering::greater != 0); -static_assert(!(std::weak_ordering::greater < 0)); -static_assert(std::weak_ordering::greater > 0); -static_assert(!(std::weak_ordering::greater <= 0)); -static_assert(std::weak_ordering::greater >= 0); - -static_assert(!(0 == std::weak_ordering::less)); -static_assert(0 != std::weak_ordering::less); -static_assert(!(0 < std::weak_ordering::less)); -static_assert(0 > std::weak_ordering::less); -static_assert(!(0 <= std::weak_ordering::less)); -static_assert(0 >= std::weak_ordering::less); - -static_assert(0 == std::weak_ordering::equivalent); -static_assert(!(0 != std::weak_ordering::equivalent)); -static_assert(!(0 < std::weak_ordering::equivalent)); -static_assert(!(0 > std::weak_ordering::equivalent)); -static_assert(0 <= std::weak_ordering::equivalent); -static_assert(0 >= std::weak_ordering::equivalent); - -static_assert(!(0 == std::weak_ordering::greater)); -static_assert(0 != std::weak_ordering::greater); -static_assert(0 < std::weak_ordering::greater); -static_assert(!(0 > std::weak_ordering::greater)); -static_assert(0 <= std::weak_ordering::greater); -static_assert(!(0 >= std::weak_ordering::greater)); - -static_assert(std::weak_ordering::less <=> 0 == std::weak_ordering::less); -static_assert(0 <=> std::weak_ordering::less == std::weak_ordering::greater); -static_assert(std::weak_ordering::equivalent <=> 0 == std::weak_ordering::equivalent); -static_assert(0 <=> std::weak_ordering::equivalent == std::weak_ordering::equivalent); -static_assert(std::weak_ordering::greater <=> 0 == std::weak_ordering::greater); -static_assert(0 <=> std::weak_ordering::greater == std::weak_ordering::less); - -static_assert(!(std::strong_ordering::less == 0)); -static_assert(std::strong_ordering::less != 0); -static_assert(std::strong_ordering::less < 0); -static_assert(!(std::strong_ordering::less > 0)); -static_assert(std::strong_ordering::less <= 0); -static_assert(!(std::strong_ordering::less >= 0)); - -static_assert(std::strong_ordering::equal == 0); -static_assert(!(std::strong_ordering::equal != 0)); -static_assert(!(std::strong_ordering::equal < 0)); -static_assert(!(std::strong_ordering::equal > 0)); -static_assert(std::strong_ordering::equal <= 0); -static_assert(std::strong_ordering::equal >= 0); - -static_assert(!(std::strong_ordering::greater == 0)); -static_assert(std::strong_ordering::greater != 0); -static_assert(!(std::strong_ordering::greater < 0)); -static_assert(std::strong_ordering::greater > 0); -static_assert(!(std::strong_ordering::greater <= 0)); -static_assert(std::strong_ordering::greater >= 0); - -static_assert(!(0 == std::strong_ordering::less)); -static_assert(0 != std::strong_ordering::less); -static_assert(!(0 < std::strong_ordering::less)); -static_assert(0 > std::strong_ordering::less); -static_assert(!(0 <= std::strong_ordering::less)); -static_assert(0 >= std::strong_ordering::less); - -static_assert(0 == std::strong_ordering::equal); -static_assert(!(0 != std::strong_ordering::equal)); -static_assert(!(0 < std::strong_ordering::equal)); -static_assert(!(0 > std::strong_ordering::equal)); -static_assert(0 <= std::strong_ordering::equal); -static_assert(0 >= std::strong_ordering::equal); - -static_assert(!(0 == std::strong_ordering::greater)); -static_assert(0 != std::strong_ordering::greater); -static_assert(0 < std::strong_ordering::greater); -static_assert(!(0 > std::strong_ordering::greater)); -static_assert(0 <= std::strong_ordering::greater); -static_assert(!(0 >= std::strong_ordering::greater)); - -static_assert(std::strong_ordering::less <=> 0 == std::strong_ordering::less); -static_assert(0 <=> std::strong_ordering::less == std::strong_ordering::greater); -static_assert(std::strong_ordering::equal <=> 0 == std::strong_ordering::equal); -static_assert(0 <=> std::strong_ordering::equal == std::strong_ordering::equal); -static_assert(std::strong_ordering::greater <=> 0 == std::strong_ordering::greater); -static_assert(0 <=> std::strong_ordering::greater == std::strong_ordering::less); - int main() { - test_ord(std::partial_ordering::equivalent); - test_ord(std::partial_ordering::less); - test_ord(std::partial_ordering::greater); - test_ord(std::partial_ordering::unordered); - - test_ord(std::weak_ordering::equivalent); - test_ord(std::weak_ordering::less); - test_ord(std::weak_ordering::greater); - - test_ord(std::strong_ordering::equal); - test_ord(std::strong_ordering::equivalent); - test_ord(std::strong_ordering::less); - test_ord(std::strong_ordering::greater); + static_assert(test_orderings()); + test_orderings(); + + static_assert(test_spaceships()); + test_spaceships(); #ifdef __cpp_lib_concepts test_algorithm(); From 89b380b756f50cf94634f0a5477af781092addfa Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 17 Jul 2020 13:39:41 -0700 Subject: [PATCH 07/11] Review comments --- tests/std/tests/P0768R1_spaceship_operator/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0768R1_spaceship_operator/test.cpp b/tests/std/tests/P0768R1_spaceship_operator/test.cpp index 8db594bf54..33a1218f7d 100644 --- a/tests/std/tests/P0768R1_spaceship_operator/test.cpp +++ b/tests/std/tests/P0768R1_spaceship_operator/test.cpp @@ -7,10 +7,10 @@ #include #include -enum class comp { equal, nonequal, less, greater, unordered }; +enum class comp { equal, less, greater, unordered }; template -constexpr bool test_order(T val) { +constexpr bool test_order(const T val) { // Validate that val is ordered relative to literal zero according to Z assert((val == 0) == (Z == comp::equal)); assert((0 == val) == (Z == comp::equal)); From 0209d3e689c9277dabd76058a2653b904f11500a Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 17 Jul 2020 19:45:30 -0700 Subject: [PATCH 08/11] Workaround DevCom-1117991 and document partial_ordering::operator<= --- stl/inc/compare | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/stl/inc/compare b/stl/inc/compare index ec8e5ae519..1b978aae49 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -64,7 +64,16 @@ public: } _NODISCARD friend constexpr bool operator<=(const partial_ordering _Val, _Literal_zero) noexcept { + // The stored value is either less (0xff), equivalent (0x00), greater (0x01) or unordered (0x80). Subtracting + // 1 produces either 0xfe, 0xff, 0x00, or 0x79. The high bit is set in the result only if the initial value was + // less or equivalent, for which we want to return true. +#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1117991 return static_cast(static_cast(_Val._Value) - 1) < 0; +#else // ^^^ no workaround / workaround vvv + auto _Tmp = static_cast(_Val._Value); + --_Tmp; + return static_cast(_Tmp >> 7); +#endif // TRANSITION, DevCom-1117991 } _NODISCARD friend constexpr bool operator>=(const partial_ordering _Val, _Literal_zero) noexcept { From b6013a96afa79f67d4ccf146ab4a8d2310e64e77 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 17 Jul 2020 19:47:59 -0700 Subject: [PATCH 09/11] Document partial_ordering::operator<=> as well --- stl/inc/compare | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stl/inc/compare b/stl/inc/compare index 1b978aae49..cb64bc0baa 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -101,6 +101,9 @@ public: } _NODISCARD friend constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { + // The stored value is either less (0xff), equivalent (0x00), greater (0x01) or unordered (0x80). Subtracting + // from 0 produces either 0x01, 0x00, 0xff, or 0x80. Note that the effect is to exchange less for greater (and + // vice versa), while leaving equivalent and unordered unchanged. return partial_ordering{static_cast<_Compare_ord>(0 - static_cast(_Val._Value))}; } From 262caaaaae2e022ac2d0adb408031bbfc359b5db Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 17 Jul 2020 19:55:19 -0700 Subject: [PATCH 10/11] Fix math (0x80 - 1 == 0x7f), Oxford commas, iff, rewrap. --- stl/inc/compare | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index cb64bc0baa..bfaf778f3a 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -64,9 +64,9 @@ public: } _NODISCARD friend constexpr bool operator<=(const partial_ordering _Val, _Literal_zero) noexcept { - // The stored value is either less (0xff), equivalent (0x00), greater (0x01) or unordered (0x80). Subtracting - // 1 produces either 0xfe, 0xff, 0x00, or 0x79. The high bit is set in the result only if the initial value was - // less or equivalent, for which we want to return true. + // The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80). + // Subtracting 1 produces either 0xfe, 0xff, 0x00, or 0x7f. The high bit is set in the result + // if and only if the initial value was less or equivalent, for which we want to return true. #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1117991 return static_cast(static_cast(_Val._Value) - 1) < 0; #else // ^^^ no workaround / workaround vvv @@ -101,9 +101,9 @@ public: } _NODISCARD friend constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { - // The stored value is either less (0xff), equivalent (0x00), greater (0x01) or unordered (0x80). Subtracting - // from 0 produces either 0x01, 0x00, 0xff, or 0x80. Note that the effect is to exchange less for greater (and - // vice versa), while leaving equivalent and unordered unchanged. + // The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80). + // Subtracting from 0 produces either 0x01, 0x00, 0xff, or 0x80. Note that the effect is to + // exchange less for greater (and vice versa), while leaving equivalent and unordered unchanged. return partial_ordering{static_cast<_Compare_ord>(0 - static_cast(_Val._Value))}; } From 9bb982cf91b82c103cae37ddb3d101111954ddf4 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Jul 2020 00:01:49 -0700 Subject: [PATCH 11/11] Simplify compiler bug workaround Co-authored-by: statementreply --- stl/inc/compare | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/stl/inc/compare b/stl/inc/compare index bfaf778f3a..717e7b4b78 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -65,15 +65,9 @@ public: _NODISCARD friend constexpr bool operator<=(const partial_ordering _Val, _Literal_zero) noexcept { // The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80). - // Subtracting 1 produces either 0xfe, 0xff, 0x00, or 0x7f. The high bit is set in the result + // Subtracting from 0 produces either 0x01, 0x00, 0xff, or 0x80. The result is greater than or equal to 0 // if and only if the initial value was less or equivalent, for which we want to return true. -#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-1117991 - return static_cast(static_cast(_Val._Value) - 1) < 0; -#else // ^^^ no workaround / workaround vvv - auto _Tmp = static_cast(_Val._Value); - --_Tmp; - return static_cast(_Tmp >> 7); -#endif // TRANSITION, DevCom-1117991 + return static_cast(0 - static_cast(_Val._Value)) >= 0; } _NODISCARD friend constexpr bool operator>=(const partial_ordering _Val, _Literal_zero) noexcept {