[libcxx-commits] [libcxx] f2f4b55 - [libc++] P2944R3: Constrained comparisions - `variant` (#141396)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jun 25 02:12:27 PDT 2025


Author: Hristo Hristov
Date: 2025-06-25T12:12:23+03:00
New Revision: f2f4b557aa7a957898c15dac3c2edd32f06581df

URL: https://github.com/llvm/llvm-project/commit/f2f4b557aa7a957898c15dac3c2edd32f06581df
DIFF: https://github.com/llvm/llvm-project/commit/f2f4b557aa7a957898c15dac3c2edd32f06581df.diff

LOG: [libc++] P2944R3: Constrained comparisions - `variant` (#141396)

This is a follow-up and depends on #139368 being merged first.

Implements [P2944R3](https://wg21.link/P2944R3) partially, which adds
constrained comparisons to `std::variant`

Closes #136769

Depends on #139368

# References

[variant.relops](https://wg21.link/variant.relops)

Added: 
    

Modified: 
    libcxx/docs/Status/Cxx2cPapers.csv
    libcxx/include/variant
    libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp
    libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.verify.cpp
    libcxx/test/support/test_comparisons.h

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 2eb1921069776..00fad3ff802a8 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -59,7 +59,7 @@
 "`P2248R8 <https://wg21.link/P2248R8>`__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","",""
 "`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","",""
 "`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","",""
-"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional``, ``tuple`` and ``variant`` are not yet implemented"
+"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Partial|","","The changes to ``optional`` and ``tuple`` are not yet implemented"
 "`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","",""
 "`P3029R1 <https://wg21.link/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 <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())
@@ -1474,6 +1480,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())
@@ -1484,6 +1495,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())
@@ -1498,6 +1514,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())
@@ -1512,6 +1533,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())
@@ -1526,6 +1552,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/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/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<int, ComparesToMyBoolExplicit>;
   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 <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 {
@@ -290,6 +309,28 @@ class EqualityComparable {
 };
 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
 


        


More information about the libcxx-commits mailing list