From f92213266e68f4833be022c78af72c5e4550866a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 23 Mar 2024 23:37:53 +0800 Subject: [PATCH 1/2] Implement LWG-3950 --- stl/inc/xstring | 66 +++++++++--------- tests/std/tests/P0220R1_string_view/test.cpp | 73 ++++++++++++++++++++ 2 files changed, 104 insertions(+), 35 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 55834e972ad..3b8a62ba6b8 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -1643,27 +1643,53 @@ namespace ranges { } // namespace ranges #endif // _HAS_CXX20 +#if _HAS_CXX20 +_EXPORT_STD template +_NODISCARD constexpr bool operator==(const basic_string_view<_Elem, _Traits> _Lhs, + const type_identity_t> _Rhs) noexcept { + return _Lhs._Equal(_Rhs); +} + +template +struct _Get_comparison_category { + using type = weak_ordering; +}; + +template +struct _Get_comparison_category<_Traits, void_t> { + using type = _Traits::comparison_category; + + static_assert(_Is_any_of_v, + "N4971 [string.view.comparison]/4: Mandates: R denotes a comparison category type."); +}; + +template +using _Get_comparison_category_t = _Get_comparison_category<_Traits>::type; + _EXPORT_STD template +_NODISCARD constexpr _Get_comparison_category_t<_Traits> operator<=>(const basic_string_view<_Elem, _Traits> _Lhs, + const type_identity_t> _Rhs) noexcept { + return static_cast<_Get_comparison_category_t<_Traits>>(_Lhs.compare(_Rhs) <=> 0); +} +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +template _NODISCARD constexpr bool operator==( const basic_string_view<_Elem, _Traits> _Lhs, const basic_string_view<_Elem, _Traits> _Rhs) noexcept { return _Lhs._Equal(_Rhs); } -#if !_HAS_CXX20 template // TRANSITION, VSO-409326 _NODISCARD constexpr bool operator==( const _Identity_t> _Lhs, const basic_string_view<_Elem, _Traits> _Rhs) noexcept { return _Lhs._Equal(_Rhs); } -#endif // !_HAS_CXX20 -_EXPORT_STD template // TRANSITION, VSO-409326 +template // TRANSITION, VSO-409326 _NODISCARD constexpr bool operator==( const basic_string_view<_Elem, _Traits> _Lhs, const _Identity_t> _Rhs) noexcept { return _Lhs._Equal(_Rhs); } -#if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=( const basic_string_view<_Elem, _Traits> _Lhs, const basic_string_view<_Elem, _Traits> _Rhs) noexcept { @@ -1753,37 +1779,7 @@ _NODISCARD constexpr bool operator>=( const basic_string_view<_Elem, _Traits> _Lhs, const _Identity_t> _Rhs) noexcept { return _Lhs.compare(_Rhs) >= 0; } -#endif // !_HAS_CXX20 - -#if _HAS_CXX20 -template -struct _Get_comparison_category { - using type = weak_ordering; -}; - -template -struct _Get_comparison_category<_Traits, void_t> { - using type = _Traits::comparison_category; - - static_assert(_Is_any_of_v, - "N4950 [string.view.comparison]/4: Mandates: R denotes a comparison category type."); -}; - -template -using _Get_comparison_category_t = _Get_comparison_category<_Traits>::type; - -_EXPORT_STD template -_NODISCARD constexpr _Get_comparison_category_t<_Traits> operator<=>( - const basic_string_view<_Elem, _Traits> _Lhs, const basic_string_view<_Elem, _Traits> _Rhs) noexcept { - return static_cast<_Get_comparison_category_t<_Traits>>(_Lhs.compare(_Rhs) <=> 0); -} - -_EXPORT_STD template // TRANSITION, VSO-409326 -_NODISCARD constexpr _Get_comparison_category_t<_Traits> operator<=>( - const basic_string_view<_Elem, _Traits> _Lhs, const _Identity_t> _Rhs) noexcept { - return static_cast<_Get_comparison_category_t<_Traits>>(_Lhs.compare(_Rhs) <=> 0); -} -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ _EXPORT_STD using string_view = basic_string_view; #ifdef __cpp_lib_char8_t diff --git a/tests/std/tests/P0220R1_string_view/test.cpp b/tests/std/tests/P0220R1_string_view/test.cpp index f6db52ddb21..a98d29c946d 100644 --- a/tests/std/tests/P0220R1_string_view/test.cpp +++ b/tests/std/tests/P0220R1_string_view/test.cpp @@ -1261,6 +1261,79 @@ void test_C6510_warning() { // compile-only (void) sv; } +#if _HAS_CXX20 +// LWG-3950 "std::basic_string_view comparison operators are overspecified" +namespace test_lwg_3950 { + template + struct get_string_comparison_category { + using type = weak_ordering; + }; + + template + requires requires { typename Traits::comparison_category; } + struct get_string_comparison_category { + using type = Traits::comparison_category; + + static_assert(disjunction_v, is_same, + is_same>); + }; + + template + using get_string_comparison_category_t = get_string_comparison_category::type; + + template + concept characterized_traits = requires { typename Traits::is_characterized; }; + +#ifdef __clang__ // TRANSITION, LLVM-75404 +#define CONST_PARAM const +#else // ^^^ workaround / no workaround vvv +#define CONST_PARAM +#endif // ^^^ no workaround ^^^ + + template + constexpr bool operator==(CONST_PARAM basic_string_view x, + CONST_PARAM type_identity_t> y) noexcept { + return x.size() == y.size() && x.compare(y) == 0; + } + template + constexpr get_string_comparison_category_t operator<=>(CONST_PARAM basic_string_view x, + CONST_PARAM type_identity_t> y) noexcept { + return static_cast>(x.compare(y) <=> 0); + } + + template + struct test_traits : char_traits { + using is_characterized = void; + }; + + using test_string_view = basic_string_view>; + + static_assert(test_string_view{} == test_string_view{}); + static_assert(!(test_string_view{} != test_string_view{})); + static_assert(!(test_string_view{} < test_string_view{})); + static_assert(!(test_string_view{} > test_string_view{})); + static_assert(test_string_view{} <= test_string_view{}); + static_assert(test_string_view{} >= test_string_view{}); + static_assert(test_string_view{} <=> test_string_view{} == strong_ordering::equal); + + static_assert(test_string_view{} == ""); + static_assert(!(test_string_view{} != "")); + static_assert(!(test_string_view{} < "")); + static_assert(!(test_string_view{} > "")); + static_assert(test_string_view{} <= ""); + static_assert(test_string_view{} >= ""); + static_assert(test_string_view{} <=> "" == strong_ordering::equal); + + static_assert("" == test_string_view{}); + static_assert(!("" != test_string_view{})); + static_assert(!("" < test_string_view{})); + static_assert(!("" > test_string_view{})); + static_assert("" <= test_string_view{}); + static_assert("" >= test_string_view{}); + static_assert("" <=> test_string_view{} == strong_ordering::equal); +} // namespace test_lwg_3950 +#endif // _HAS_CXX20 + int main() { test_case_default_constructor(); test_case_ntcts_constructor(); From a1438436b260331c17952a593a26c512bfb714bd Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 25 Mar 2024 23:36:07 -0700 Subject: [PATCH 2/2] `_Traits` => `Traits` --- tests/std/tests/P0220R1_string_view/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0220R1_string_view/test.cpp b/tests/std/tests/P0220R1_string_view/test.cpp index a98d29c946d..a03ff3a220d 100644 --- a/tests/std/tests/P0220R1_string_view/test.cpp +++ b/tests/std/tests/P0220R1_string_view/test.cpp @@ -1264,7 +1264,7 @@ void test_C6510_warning() { // compile-only #if _HAS_CXX20 // LWG-3950 "std::basic_string_view comparison operators are overspecified" namespace test_lwg_3950 { - template + template struct get_string_comparison_category { using type = weak_ordering; };