From 002fcac983085257ad28dfa9b45d8a7493e7dccc Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Mon, 25 Nov 2024 23:26:19 -0500 Subject: [PATCH 1/5] [libc++] P3379R1: Constrain 'std::expected' equality operators --- libcxx/include/__expected/expected.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h index 3d3f11967ee74..7dc0248fcd72f 100644 --- a/libcxx/include/__expected/expected.h +++ b/libcxx/include/__expected/expected.h @@ -10,6 +10,7 @@ #define _LIBCPP___EXPECTED_EXPECTED_H #include <__assert> +#include <__concepts/convertible_to.h> #include <__config> #include <__expected/bad_expected_access.h> #include <__expected/unexpect.h> @@ -1139,7 +1140,11 @@ class expected : private __expected_base<_Tp, _Err> { // [expected.object.eq], equality operators template - requires(!is_void_v<_T2>) + requires(!is_void_v<_T2> && + requires(const _Tp& __tp, const _T2& __t2, const _Err& __err, const _E2& __e2) { + { __tp == __t2 } -> convertible_to; + { __err == __e2 } -> convertible_to; + }) _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { if (__x.__has_val() != __y.__has_val()) { return false; @@ -1153,11 +1158,18 @@ class expected : private __expected_base<_Tp, _Err> { } template + requires(!__is_std_expected<_T2>::value && + requires(const _Tp& __tp, const _T2& __t2) { + { __tp == __t2 } -> convertible_to; + }) _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) { return __x.__has_val() && static_cast(__x.__val() == __v); } template + requires requires(const _Err& __err, const _E2& __e2) { + { __err == __e2 } -> convertible_to; + } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) { return !__x.__has_val() && static_cast(__x.__unex() == __e.error()); } @@ -1850,7 +1862,10 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> { // [expected.void.eq], equality operators template - requires is_void_v<_T2> + requires(is_void_v<_T2> && + requires(const _Err& __err, const _E2& __e2) { + { __err == __e2 } -> convertible_to; + }) _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { if (__x.__has_val() != __y.__has_val()) { return false; @@ -1860,6 +1875,9 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> { } template + requires requires(const _Err& __err, const _E2& __e2) { + { __err == __e2 } -> convertible_to; + } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) { return !__x.__has_val() && static_cast(__x.__unex() == __y.error()); } From 408b3315450bf97e4b1c0e23f37dc9462c71578b Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Thu, 28 Nov 2024 01:16:30 -0500 Subject: [PATCH 2/5] [libc++] P3379R1: Constrain 'std::expected' equality operators --- libcxx/include/__expected/expected.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h index 7dc0248fcd72f..ca9dcfb1569e8 100644 --- a/libcxx/include/__expected/expected.h +++ b/libcxx/include/__expected/expected.h @@ -1140,11 +1140,15 @@ class expected : private __expected_base<_Tp, _Err> { // [expected.object.eq], equality operators template +# if _LIBCPP_STD_VER >= 26 requires(!is_void_v<_T2> && requires(const _Tp& __tp, const _T2& __t2, const _Err& __err, const _E2& __e2) { { __tp == __t2 } -> convertible_to; { __err == __e2 } -> convertible_to; }) +# else + requires(!is_void_v<_T2>) +# endif _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { if (__x.__has_val() != __y.__has_val()) { return false; @@ -1158,18 +1162,22 @@ class expected : private __expected_base<_Tp, _Err> { } template +# if _LIBCPP_STD_VER >= 26 requires(!__is_std_expected<_T2>::value && requires(const _Tp& __tp, const _T2& __t2) { { __tp == __t2 } -> convertible_to; }) +# endif _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) { return __x.__has_val() && static_cast(__x.__val() == __v); } template +# if _LIBCPP_STD_VER >= 26 requires requires(const _Err& __err, const _E2& __e2) { { __err == __e2 } -> convertible_to; } +# endif _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) { return !__x.__has_val() && static_cast(__x.__unex() == __e.error()); } @@ -1862,10 +1870,14 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> { // [expected.void.eq], equality operators template +# if _LIBCPP_STD_VER >= 26 requires(is_void_v<_T2> && requires(const _Err& __err, const _E2& __e2) { { __err == __e2 } -> convertible_to; }) +# else + requires is_void_v<_T2> +# endif _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { if (__x.__has_val() != __y.__has_val()) { return false; @@ -1875,9 +1887,11 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> { } template +# if _LIBCPP_STD_VER >= 26 requires requires(const _Err& __err, const _E2& __e2) { { __err == __e2 } -> convertible_to; } +# endif _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) { return !__x.__has_val() && static_cast(__x.__unex() == __y.error()); } From 6d540b6305757133c777a1a768d06e6b4abcc9a8 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sat, 30 Nov 2024 20:51:37 -0500 Subject: [PATCH 3/5] [libc++] P3379R1: Constrain 'std::expected' equality operators --- .../expected.void/equality/equality.other_expected.pass.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp index 8b24875586852..5de9d9b34f0aa 100644 --- a/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp @@ -23,15 +23,12 @@ template concept CanCompare = requires(T1 t1, T2 t2) { t1 == t2; }; -struct Foo{}; +struct Foo {}; static_assert(!CanCompare); static_assert(CanCompare, std::expected>); static_assert(CanCompare, std::expected>); -// Note this is true because other overloads in expected are unconstrained -static_assert(CanCompare, std::expected>); - constexpr bool test() { // x.has_value() && y.has_value() { From 02d1d91bbc52c1059305f7c42a93641b012ed318 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sat, 30 Nov 2024 21:11:37 -0500 Subject: [PATCH 4/5] [libc++] P3379R1: Constrain 'std::expected' equality operators --- libcxx/docs/ReleaseNotes/20.rst | 1 + .../equality/equality.other_expected.pass.cpp | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst index d520c46bae1ef..0c69e76560755 100644 --- a/libcxx/docs/ReleaseNotes/20.rst +++ b/libcxx/docs/ReleaseNotes/20.rst @@ -45,6 +45,7 @@ Implemented Papers - ``std::jthread`` and ```` are not guarded behind ``-fexperimental-library`` anymore - P2674R1: A trait for implicit lifetime types (`Github `__) - P0429R9: A Standard ``flat_map`` is partially implemented and ``flat_map`` is provided (`Github `__) +- P3379R1: Constrain ``std::expected`` equality operators Improvements and New Features ----------------------------- diff --git a/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp index 9325c6c61ad2d..58789f6c421d1 100644 --- a/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp @@ -23,15 +23,12 @@ template concept CanCompare = requires(T1 t1, T2 t2) { t1 == t2; }; -struct Foo{}; +struct Foo {}; static_assert(!CanCompare); static_assert(CanCompare, std::expected>); static_assert(CanCompare, std::expected>); -// Note this is true because other overloads are unconstrained -static_assert(CanCompare, std::expected>); - constexpr bool test() { // x.has_value() && y.has_value() { From 805ac6a8b2ceac7541e991070963963f75f35e4d Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sat, 30 Nov 2024 21:58:04 -0500 Subject: [PATCH 5/5] [libc++] P3379R1: Constrain 'std::expected' equality operators --- .../equality/equality.other_expected.pass.cpp | 11 +++++++++-- .../equality/equality.other_expected.pass.cpp | 9 +++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp index 58789f6c421d1..3a044afe93728 100644 --- a/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.expected/equality/equality.other_expected.pass.cpp @@ -23,12 +23,19 @@ template concept CanCompare = requires(T1 t1, T2 t2) { t1 == t2; }; -struct Foo {}; -static_assert(!CanCompare); +struct NonComparable {}; +static_assert(!CanCompare); static_assert(CanCompare, std::expected>); static_assert(CanCompare, std::expected>); +#if _LIBCPP_STD_VER >= 26 +static_assert(!CanCompare, std::expected>); +static_assert(!CanCompare, std::expected>); +static_assert(!CanCompare, std::expected>); +static_assert(!CanCompare, std::expected>); +#endif + constexpr bool test() { // x.has_value() && y.has_value() { diff --git a/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp index 5de9d9b34f0aa..731368c4d2396 100644 --- a/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp @@ -23,12 +23,17 @@ template concept CanCompare = requires(T1 t1, T2 t2) { t1 == t2; }; -struct Foo {}; -static_assert(!CanCompare); +struct NonComparable {}; +static_assert(!CanCompare); static_assert(CanCompare, std::expected>); static_assert(CanCompare, std::expected>); +#if _LIBCPP_STD_VER >= 26 +static_assert(!CanCompare, std::expected>); +static_assert(!CanCompare, std::expected>); +#endif + constexpr bool test() { // x.has_value() && y.has_value() {