diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 8a0417e120d75..4ad827c72fa54 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -59,7 +59,7 @@ "`P2248R8 `__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","","" "`P2810R4 `__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","","" "`P1068R11 `__","Vector API for random number generation","2024-03 (Tokyo)","","","" -"`P2944R3 `__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional``, ``tuple`` and ``variant`` are not yet implemented" +"`P2944R3 `__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional`` and ``tuple`` are not yet implemented" "`P2642R6 `__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","","" "`P3029R1 `__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19","" "","","","","","" diff --git a/libcxx/include/variant b/libcxx/include/variant index dac6f786cc198..ede9f486ecc2e 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -242,6 +242,7 @@ namespace std { # include <__type_traits/is_assignable.h> # include <__type_traits/is_constructible.h> # include <__type_traits/is_convertible.h> +# include <__type_traits/is_core_convertible.h> # include <__type_traits/is_destructible.h> # include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> @@ -1442,6 +1443,11 @@ struct __convert_to_bool { }; template +# if _LIBCPP_STD_VER >= 26 + requires(requires(const _Types& __t) { + { __t == __t } -> __core_convertible_to; + } && ...) +# endif _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; if (__lhs.index() != __rhs.index()) @@ -1474,6 +1480,11 @@ operator<=>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { # endif // _LIBCPP_STD_VER >= 20 template +# if _LIBCPP_STD_VER >= 26 + requires(requires(const _Types& __t) { + { __t != __t } -> __core_convertible_to; + } && ...) +# endif _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; if (__lhs.index() != __rhs.index()) @@ -1484,6 +1495,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const variant<_Types...>& __lhs, } template +# if _LIBCPP_STD_VER >= 26 + requires(requires(const _Types& __t) { + { __t < __t } -> __core_convertible_to; + } && ...) +# endif _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; if (__rhs.valueless_by_exception()) @@ -1498,6 +1514,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const variant<_Types...>& __lhs, } template +# if _LIBCPP_STD_VER >= 26 + requires(requires(const _Types& __t) { + { __t > __t } -> __core_convertible_to; + } && ...) +# endif _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; if (__lhs.valueless_by_exception()) @@ -1512,6 +1533,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const variant<_Types...>& __lhs, } template +# if _LIBCPP_STD_VER >= 26 + requires(requires(const _Types& __t) { + { __t <= __t } -> __core_convertible_to; + } && ...) +# endif _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; if (__lhs.valueless_by_exception()) @@ -1526,6 +1552,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const variant<_Types...>& __lhs, } template +# if _LIBCPP_STD_VER >= 26 + requires(requires(const _Types& __t) { + { __t >= __t } -> __core_convertible_to; + } && ...) +# endif _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; if (__rhs.valueless_by_exception()) diff --git a/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp b/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp index c1a5b8e474a74..2c00703662687 100644 --- a/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp @@ -39,8 +39,57 @@ #include #include +#include "test_comparisons.h" #include "test_macros.h" +#if TEST_STD_VER >= 26 + +// Test SFINAE. + +// == +static_assert(HasOperatorEqual>); +static_assert(HasOperatorEqual>); + +static_assert(!HasOperatorEqual>); +static_assert(!HasOperatorEqual>); + +// > +static_assert(HasOperatorGreaterThan>); +static_assert(HasOperatorGreaterThan>); + +static_assert(!HasOperatorGreaterThan>); +static_assert(!HasOperatorGreaterThan>); + +// >= +static_assert(HasOperatorGreaterThanEqual>); +static_assert(HasOperatorGreaterThanEqual>); + +static_assert(!HasOperatorGreaterThanEqual>); +static_assert(!HasOperatorGreaterThanEqual>); + +// < +static_assert(HasOperatorLessThan>); +static_assert(HasOperatorLessThan>); + +static_assert(!HasOperatorLessThan>); +static_assert(!HasOperatorLessThan>); + +// <= +static_assert(HasOperatorLessThanEqual>); +static_assert(HasOperatorLessThanEqual>); + +static_assert(!HasOperatorLessThanEqual>); +static_assert(!HasOperatorLessThanEqual>); + +// != +static_assert(HasOperatorNotEqual>); +static_assert(HasOperatorNotEqual>); + +static_assert(!HasOperatorNotEqual>); +static_assert(!HasOperatorNotEqual>); + +#endif + #ifndef TEST_HAS_NO_EXCEPTIONS struct MakeEmptyT { MakeEmptyT() = default; diff --git a/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.verify.cpp b/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.verify.cpp index 64248171d1146..392a234e6a9b2 100644 --- a/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.verify.cpp +++ b/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.verify.cpp @@ -41,7 +41,9 @@ #include "test_macros.h" - +#if TEST_STD_VER >= 26 +// expected-no-diagnostics +#else struct MyBoolExplicit { bool value; constexpr explicit MyBoolExplicit(bool v) : value(v) {} @@ -70,8 +72,7 @@ inline constexpr MyBoolExplicit operator>=(const ComparesToMyBoolExplicit& LHS, return MyBoolExplicit(LHS.value >= RHS.value); } - -int main(int, char**) { +void test() { using V = std::variant; V v1(42); V v2(101); @@ -83,6 +84,6 @@ int main(int, char**) { (void)(v1 <= v2); // expected-note {{here}} (void)(v1 > v2); // expected-note {{here}} (void)(v1 >= v2); // expected-note {{here}} - - return 0; } + +#endif diff --git a/libcxx/test/support/test_comparisons.h b/libcxx/test/support/test_comparisons.h index d9729e0451b49..e37ab44828c70 100644 --- a/libcxx/test/support/test_comparisons.h +++ b/libcxx/test/support/test_comparisons.h @@ -271,12 +271,31 @@ struct PartialOrder { template concept HasOperatorEqual = requires(T1 t1, T2 t2) { t1 == t2; }; +template +concept HasOperatorGreaterThan = requires(T1 t1, T2 t2) { t1 > t2; }; + +template +concept HasOperatorGreaterThanEqual = requires(T1 t1, T2 t2) { t1 >= t2; }; +template +concept HasOperatorLessThan = requires(T1 t1, T2 t2) { t1 < t2; }; + +template +concept HasOperatorLessThanEqual = requires(T1 t1, T2 t2) { t1 <= t2; }; + +template +concept HasOperatorNotEqual = requires(T1 t1, T2 t2) { t1 != t2; }; + template concept HasOperatorSpaceship = requires(T1 t1, T2 t2) { t1 <=> t2; }; struct NonComparable {}; static_assert(!std::equality_comparable); static_assert(!HasOperatorEqual); +static_assert(!HasOperatorGreaterThan); +static_assert(!HasOperatorGreaterThanEqual); +static_assert(!HasOperatorLessThan); +static_assert(!HasOperatorLessThanEqual); +static_assert(!HasOperatorNotEqual); static_assert(!HasOperatorSpaceship); class EqualityComparable { @@ -290,6 +309,28 @@ class EqualityComparable { }; static_assert(std::equality_comparable); static_assert(HasOperatorEqual); +static_assert(HasOperatorNotEqual); + +class ThreeWayComparable { +public: + constexpr ThreeWayComparable(int value) : value_{value} {}; + + friend constexpr bool operator==(const ThreeWayComparable&, const ThreeWayComparable&) noexcept = default; + friend constexpr std::strong_ordering + operator<=>(const ThreeWayComparable&, const ThreeWayComparable&) noexcept = default; + +private: + int value_; +}; +static_assert(std::equality_comparable); +static_assert(std::three_way_comparable); +static_assert(HasOperatorEqual); +static_assert(HasOperatorGreaterThan); +static_assert(HasOperatorGreaterThanEqual); +static_assert(HasOperatorLessThan); +static_assert(HasOperatorLessThanEqual); +static_assert(HasOperatorNotEqual); +static_assert(HasOperatorSpaceship); #endif // TEST_STD_VER >= 20