-
Notifications
You must be signed in to change notification settings - Fork 13.6k
WIP [libc++]P2944R3: Constrained comparisions - variant
and tuple
#141396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
WIP [libc++]P2944R3: Constrained comparisions - variant
and tuple
#141396
Conversation
…rapper Implements `variant`: https://wg21.link/P2944R3 Closes llvm#136769
You can test this locally with the following command:git-clang-format --diff HEAD~1 HEAD --extensions ,cpp,h -- libcxx/include/tuple libcxx/include/variant libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_comparison.verify.cpp libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp libcxx/test/support/test_comparisons.h View the diff from clang-format here.diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
index baca362f7..779a89b16 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
@@ -36,8 +36,10 @@ static_assert(!std::equality_comparable<std::tuple<NonComparable, EqualityCompar
static_assert(!std::equality_comparable_with<std::tuple<EqualityComparable>, std::tuple<NonComparable>>);
static_assert(!std::equality_comparable_with<std::tuple<NonComparable>, std::tuple<EqualityComparable>>);
// Size mismatch.
-static_assert(!std::equality_comparable_with<std::tuple<EqualityComparable>, std::tuple<EqualityComparable, EqualityComparable>>);
-static_assert(!std::equality_comparable_with<std::tuple<EqualityComparable, EqualityComparable>, std::tuple<EqualityComparable>>);
+static_assert(
+ !std::equality_comparable_with<std::tuple<EqualityComparable>, std::tuple<EqualityComparable, EqualityComparable>>);
+static_assert(
+ !std::equality_comparable_with<std::tuple<EqualityComparable, EqualityComparable>, std::tuple<EqualityComparable>>);
#endif
|
@llvm/pr-subscribers-libcxx Author: Hristo Hristov (H-G-Hristov) ChangesThis is a follow-up and depends on #139368 being merged first. Implements P2944R3 partially, which adds constrained comparisons to The missing overloads introduced in P2165R4 are not implemented. Relates to #136765 Relates to: #139368 ReferencesFull diff: https://github.com/llvm/llvm-project/pull/141396.diff 6 Files Affected:
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 8dd62ae624f5e..35ea37a5ea5ed 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -1161,9 +1161,16 @@ struct __tuple_equal<0> {
};
template <class... _Tp, class... _Up>
+# if _LIBCPP_STD_VER >= 26
+ requires(requires(const _Tp& __t, const _Up& __u) {
+ { __t == __u } -> __boolean_testable;
+ } && ...) && (sizeof...(_Tp) == sizeof...(_Up))
+# endif
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) {
+# if _LIBCPP_STD_VER < 26
static_assert(sizeof...(_Tp) == sizeof...(_Up), "Can't compare tuples of different sizes");
+# endif
return __tuple_equal<sizeof...(_Tp)>()(__x, __y);
}
diff --git a/libcxx/include/variant b/libcxx/include/variant
index bf611aec704ca..f33058b708528 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>
@@ -1453,6 +1454,11 @@ struct __convert_to_bool {
};
template <class... _Types>
+# if _LIBCPP_STD_VER >= 26
+ requires(requires(const _Types& __t) {
+ { __t == __t } -> __core_convertible_to<bool>;
+ } && ...)
+# 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())
@@ -1485,6 +1491,11 @@ operator<=>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
# endif // _LIBCPP_STD_VER >= 20
template <class... _Types>
+# if _LIBCPP_STD_VER >= 26
+ requires(requires(const _Types& __t) {
+ { __t != __t } -> __core_convertible_to<bool>;
+ } && ...)
+# 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())
@@ -1495,6 +1506,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const variant<_Types...>& __lhs,
}
template <class... _Types>
+# if _LIBCPP_STD_VER >= 26
+ requires(requires(const _Types& __t) {
+ { __t < __t } -> __core_convertible_to<bool>;
+ } && ...)
+# 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())
@@ -1509,6 +1525,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const variant<_Types...>& __lhs,
}
template <class... _Types>
+# if _LIBCPP_STD_VER >= 26
+ requires(requires(const _Types& __t) {
+ { __t > __t } -> __core_convertible_to<bool>;
+ } && ...)
+# 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())
@@ -1523,6 +1544,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const variant<_Types...>& __lhs,
}
template <class... _Types>
+# if _LIBCPP_STD_VER >= 26
+ requires(requires(const _Types& __t) {
+ { __t <= __t } -> __core_convertible_to<bool>;
+ } && ...)
+# 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())
@@ -1537,6 +1563,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const variant<_Types...>& __lhs,
}
template <class... _Types>
+# if _LIBCPP_STD_VER >= 26
+ requires(requires(const _Types& __t) {
+ { __t >= __t } -> __core_convertible_to<bool>;
+ } && ...)
+# 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/tuple/tuple.tuple/tuple.rel/eq.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
index a8de656313d45..baca362f7783b 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
@@ -16,12 +16,31 @@
// UNSUPPORTED: c++03
-#include <tuple>
-#include <string>
+#include <array>
#include <cassert>
+#include <tuple>
+#include "test_comparisons.h"
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+
+// Test SFINAE.
+
+static_assert(std::equality_comparable<std::tuple<EqualityComparable>>);
+static_assert(std::equality_comparable<std::tuple<EqualityComparable, EqualityComparable>>);
+
+static_assert(!std::equality_comparable<std::tuple<NonComparable>>);
+static_assert(!std::equality_comparable<std::tuple<EqualityComparable, NonComparable>>);
+static_assert(!std::equality_comparable<std::tuple<NonComparable, EqualityComparable>>);
+static_assert(!std::equality_comparable_with<std::tuple<EqualityComparable>, std::tuple<NonComparable>>);
+static_assert(!std::equality_comparable_with<std::tuple<NonComparable>, std::tuple<EqualityComparable>>);
+// Size mismatch.
+static_assert(!std::equality_comparable_with<std::tuple<EqualityComparable>, std::tuple<EqualityComparable, EqualityComparable>>);
+static_assert(!std::equality_comparable_with<std::tuple<EqualityComparable, EqualityComparable>, std::tuple<EqualityComparable>>);
+
+#endif
+
int main(int, char**)
{
{
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_comparison.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_comparison.verify.cpp
index 851f6fcd1fbac..a5dbb6b313e6a 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_comparison.verify.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.rel/size_incompatible_comparison.verify.cpp
@@ -21,9 +21,15 @@
#include <tuple>
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 26
+// expected-no-diagnostics
+#else
void f(std::tuple<int> t1, std::tuple<int, long> t2) {
// We test only the core comparison operators and trust that the others
// fall back on the same implementations prior to C++20.
static_cast<void>(t1 == t2); // expected-error@*:* {{}}
static_cast<void>(t1 < t2); // expected-error@*:* {{}}
}
+#endif
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 <utility>
#include <variant>
+#include "test_comparisons.h"
#include "test_macros.h"
+#if TEST_STD_VER >= 26
+
+// Test SFINAE.
+
+// ==
+static_assert(HasOperatorEqual<std::variant<EqualityComparable>>);
+static_assert(HasOperatorEqual<std::variant<EqualityComparable, int, long>>);
+
+static_assert(!HasOperatorEqual<std::variant<NonComparable>>);
+static_assert(!HasOperatorEqual<std::variant<NonComparable, EqualityComparable>>);
+
+// >
+static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable>>);
+static_assert(HasOperatorGreaterThan<std::variant<ThreeWayComparable, int, long>>);
+
+static_assert(!HasOperatorGreaterThan<std::variant<NonComparable>>);
+static_assert(!HasOperatorGreaterThan<std::variant<NonComparable, ThreeWayComparable>>);
+
+// >=
+static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable>>);
+static_assert(HasOperatorGreaterThanEqual<std::variant<ThreeWayComparable, int, long>>);
+
+static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable>>);
+static_assert(!HasOperatorGreaterThanEqual<std::variant<NonComparable, ThreeWayComparable>>);
+
+// <
+static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable>>);
+static_assert(HasOperatorLessThan<std::variant<ThreeWayComparable, int, long>>);
+
+static_assert(!HasOperatorLessThan<std::variant<NonComparable>>);
+static_assert(!HasOperatorLessThan<std::variant<NonComparable, ThreeWayComparable>>);
+
+// <=
+static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable>>);
+static_assert(HasOperatorLessThanEqual<std::variant<ThreeWayComparable, int, long>>);
+
+static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable>>);
+static_assert(!HasOperatorLessThanEqual<std::variant<NonComparable, ThreeWayComparable>>);
+
+// !=
+static_assert(HasOperatorNotEqual<std::variant<EqualityComparable>>);
+static_assert(HasOperatorNotEqual<std::variant<EqualityComparable, int, long>>);
+
+static_assert(!HasOperatorNotEqual<std::variant<NonComparable>>);
+static_assert(!HasOperatorNotEqual<std::variant<NonComparable, EqualityComparable>>);
+
+#endif
+
#ifndef TEST_HAS_NO_EXCEPTIONS
struct MakeEmptyT {
MakeEmptyT() = default;
diff --git a/libcxx/test/support/test_comparisons.h b/libcxx/test/support/test_comparisons.h
index db6977a96a2fe..e37ab44828c70 100644
--- a/libcxx/test/support/test_comparisons.h
+++ b/libcxx/test/support/test_comparisons.h
@@ -268,6 +268,70 @@ struct PartialOrder {
}
};
-#endif
+template <typename T1, typename T2 = T1>
+concept HasOperatorEqual = requires(T1 t1, T2 t2) { t1 == t2; };
+
+template <typename T1, typename T2 = T1>
+concept HasOperatorGreaterThan = requires(T1 t1, T2 t2) { t1 > t2; };
+
+template <typename T1, typename T2 = T1>
+concept HasOperatorGreaterThanEqual = requires(T1 t1, T2 t2) { t1 >= t2; };
+template <typename T1, typename T2 = T1>
+concept HasOperatorLessThan = requires(T1 t1, T2 t2) { t1 < t2; };
+
+template <typename T1, typename T2 = T1>
+concept HasOperatorLessThanEqual = requires(T1 t1, T2 t2) { t1 <= t2; };
+
+template <typename T1, typename T2 = T1>
+concept HasOperatorNotEqual = requires(T1 t1, T2 t2) { t1 != t2; };
+
+template <typename T1, typename T2 = T1>
+concept HasOperatorSpaceship = requires(T1 t1, T2 t2) { t1 <=> t2; };
+
+struct NonComparable {};
+static_assert(!std::equality_comparable<NonComparable>);
+static_assert(!HasOperatorEqual<NonComparable>);
+static_assert(!HasOperatorGreaterThan<NonComparable>);
+static_assert(!HasOperatorGreaterThanEqual<NonComparable>);
+static_assert(!HasOperatorLessThan<NonComparable>);
+static_assert(!HasOperatorLessThanEqual<NonComparable>);
+static_assert(!HasOperatorNotEqual<NonComparable>);
+static_assert(!HasOperatorSpaceship<NonComparable>);
+
+class EqualityComparable {
+public:
+ constexpr EqualityComparable(int value) : value_{value} {};
+
+ friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;
+
+private:
+ int value_;
+};
+static_assert(std::equality_comparable<EqualityComparable>);
+static_assert(HasOperatorEqual<EqualityComparable>);
+static_assert(HasOperatorNotEqual<EqualityComparable>);
+
+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<ThreeWayComparable>);
+static_assert(std::three_way_comparable<ThreeWayComparable>);
+static_assert(HasOperatorEqual<ThreeWayComparable>);
+static_assert(HasOperatorGreaterThan<ThreeWayComparable>);
+static_assert(HasOperatorGreaterThanEqual<ThreeWayComparable>);
+static_assert(HasOperatorLessThan<ThreeWayComparable>);
+static_assert(HasOperatorLessThanEqual<ThreeWayComparable>);
+static_assert(HasOperatorNotEqual<ThreeWayComparable>);
+static_assert(HasOperatorSpaceship<ThreeWayComparable>);
+
+#endif // TEST_STD_VER >= 20
#endif // TEST_COMPARISONS_H
|
This is a follow-up and depends on #139368 being merged first.
Implements P2944R3 partially, which adds constrained comparisons to
std::variant
andstd::tuple
.The missing overloads introduced in P2165R4 are not implemented.
Relates to #136765
Closes #136769
Depends on #139368
References
tuple.rel
variant.relops