libstdc++: Define <=> for tuple, optional and variant
authorJonathan Wakely <jwakely@redhat.com>
Fri, 21 Feb 2020 12:02:15 +0000 (12:02 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Fri, 21 Feb 2020 17:12:39 +0000 (17:12 +0000)
Another piece of P1614R2.

* include/std/optional (operator<=>(optional<T>, optional<U>))
(operator<=>(optional<T>, nullopt), operator<=>(optional<T>, U)):
Define for C++20.
* include/std/tuple (__tuple_cmp): New helper function for <=>.
(operator<=>(tuple<T...>, tuple<U>...)): Define for C++20.
* include/std/variant (operator<=>(variant<T...>, variant<T...>))
(operator<=>(monostate, monostate)): Define for C++20.
* testsuite/20_util/optional/relops/three_way.cc: New test.
* testsuite/20_util/tuple/comparison_operators/three_way.cc: New test.
* testsuite/20_util/variant/89851.cc: Move to ...
* testsuite/20_util/variant/relops/89851.cc: ... here.
* testsuite/20_util/variant/90008.cc: Move to ...
* testsuite/20_util/variant/relops/90008.cc: ... here.
* testsuite/20_util/variant/relops/three_way.cc: New test.

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/optional
libstdc++-v3/include/std/tuple
libstdc++-v3/include/std/variant
libstdc++-v3/testsuite/20_util/optional/relops/three_way.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/tuple/comparison_operators/three_way.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/variant/89851.cc [deleted file]
libstdc++-v3/testsuite/20_util/variant/90008.cc [deleted file]
libstdc++-v3/testsuite/20_util/variant/relops/89851.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/variant/relops/90008.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/variant/relops/three_way.cc [new file with mode: 0644]

index 3649864644e505a1b0b125b54d008d4170b4d818..7e065ef3e1dfb46c4088d657a0ed78b846902b0e 100644 (file)
@@ -1,3 +1,20 @@
+2020-02-21  Jonathan Wakely  <jwakely@redhat.com>
+
+       * include/std/optional (operator<=>(optional<T>, optional<U>))
+       (operator<=>(optional<T>, nullopt), operator<=>(optional<T>, U)):
+       Define for C++20.
+       * include/std/tuple (__tuple_cmp): New helper function for <=>.
+       (operator<=>(tuple<T...>, tuple<U>...)): Define for C++20.
+       * include/std/variant (operator<=>(variant<T...>, variant<T...>))
+       (operator<=>(monostate, monostate)): Define for C++20.
+       * testsuite/20_util/optional/relops/three_way.cc: New test.
+       * testsuite/20_util/tuple/comparison_operators/three_way.cc: New test.
+       * testsuite/20_util/variant/89851.cc: Move to ...
+       * testsuite/20_util/variant/relops/89851.cc: ... here.
+       * testsuite/20_util/variant/90008.cc: Move to ...
+       * testsuite/20_util/variant/relops/90008.cc: ... here.
+       * testsuite/20_util/variant/relops/three_way.cc: New test.
+
 2020-02-20  Patrick Palka  <ppalka@redhat.com>
 
        * include/std/ranges (views::__adaptor::__maybe_refwrap): New utility
index b920a1453bad5ed6016e87fd1e3431c1ebd1aa65..37c2ba7a02517b0d4db04c0dd653b3c79b11be92 100644 (file)
@@ -41,6 +41,9 @@
 #include <bits/exception_defines.h>
 #include <bits/functional_hash.h>
 #include <bits/enable_special_members.h>
+#if __cplusplus > 201703L
+# include <compare>
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -1027,12 +1030,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs);
     }
 
+#ifdef __cpp_lib_three_way_comparison
+  template<typename _Tp, three_way_comparable_with<_Tp> _Up>
+    constexpr compare_three_way_result_t<_Tp, _Up>
+    operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y)
+    {
+      return __x && __y ? *__x <=> *__y : bool(__x) <=> bool(__y);
+    }
+#endif
+
   // Comparisons with nullopt.
   template<typename _Tp>
     constexpr bool
     operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept
     { return !__lhs; }
 
+#ifdef __cpp_lib_three_way_comparison
+  template<typename _Tp>
+    constexpr strong_ordering
+    operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept
+    { return bool(__x) <=> false; }
+#else
   template<typename _Tp>
     constexpr bool
     operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept
@@ -1087,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr bool
     operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept
     { return !__rhs; }
+#endif // three-way-comparison
 
   // Comparisons with value type.
   template<typename _Tp, typename _Up>
@@ -1161,6 +1180,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     -> __optional_relop_t<decltype(declval<_Up>() >= declval<_Tp>())>
     { return !__rhs || __lhs >= *__rhs; }
 
+#ifdef __cpp_lib_three_way_comparison
+  template<typename _Tp, typename _Up>
+    constexpr compare_three_way_result_t<_Tp, _Up>
+    operator<=>(const optional<_Tp>& __x, const _Up& __v)
+    { return bool(__x) ? *__x <=> __v : strong_ordering::less; }
+#endif
+
   // Swap and creation functions.
 
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
index 3829d844e0b33d46f1d26310d1d246a66409e280..808947781aed4f56090127fb7fb0e99a086664a6 100644 (file)
@@ -39,6 +39,9 @@
 #include <array>
 #include <bits/uses_allocator.h>
 #include <bits/invoke.h>
+#if __cplusplus > 201703L
+# include <compare>
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -1397,6 +1400,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __compare::__eq(__t, __u);
     }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Cat, typename _Tp, typename _Up>
+    constexpr _Cat
+    __tuple_cmp(const _Tp&, const _Up&, index_sequence<>)
+    { return _Cat::equivalent; }
+
+  template<typename _Cat, typename _Tp, typename _Up,
+          size_t _Idx0, size_t... _Idxs>
+    constexpr _Cat
+    __tuple_cmp(const _Tp& __t, const _Up& __u,
+               index_sequence<_Idx0, _Idxs...>)
+    {
+      auto __c
+       = __detail::__synth3way(std::get<_Idx0>(__t), std::get<_Idx0>(__u));
+      if (__c != 0)
+       return __c;
+      return std::__tuple_cmp<_Cat>(__t, __u, index_sequence<_Idxs...>());
+    }
+
+  template<typename... _Tps, typename... _Ups>
+    constexpr
+    common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>
+    operator<=>(const tuple<_Tps...>& __t, const tuple<_Ups...>& __u)
+    {
+      using _Cat
+       = common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>;
+      return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Tps...>());
+    }
+#else
   template<typename... _TElements, typename... _UElements>
     constexpr bool
     operator<(const tuple<_TElements...>& __t,
@@ -1433,6 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     operator>=(const tuple<_TElements...>& __t,
               const tuple<_UElements...>& __u)
     { return !(__t < __u); }
+#endif // three_way_comparison
 
   // NB: DR 705.
   template<typename... _Elements>
index 9568b718f53700ef17f61902e16a123c174140b6..258a5fb18bdc3ca3e4d2f7bc3f89f121bee3d709 100644 (file)
@@ -45,6 +45,9 @@
 #include <bits/stl_iterator_base_types.h>
 #include <bits/stl_iterator_base_funcs.h>
 #include <bits/stl_construct.h>
+#if __cplusplus > 201703L
+# include <compare>
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -1181,10 +1184,7 @@ namespace __variant
             __ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \
        }, __rhs); \
       return __ret; \
-    } \
-\
-  constexpr bool operator __OP(monostate, monostate) noexcept \
-  { return 0 __OP 0; }
+    }
 
   _VARIANT_RELATION_FUNCTION_TEMPLATE(<, less)
   _VARIANT_RELATION_FUNCTION_TEMPLATE(<=, less_equal)
@@ -1195,6 +1195,45 @@ namespace __variant
 
 #undef _VARIANT_RELATION_FUNCTION_TEMPLATE
 
+  constexpr bool operator==(monostate, monostate) noexcept { return true; }
+
+#ifdef __cpp_lib_three_way_comparison
+  template<typename... _Types>
+    requires (three_way_comparable<_Types> && ...)
+    constexpr
+    common_comparison_category_t<compare_three_way_result_t<_Types>...>
+    operator<=>(const variant<_Types...>& __v, const variant<_Types...>& __w)
+    {
+      common_comparison_category_t<compare_three_way_result_t<_Types>...> __ret
+       = strong_ordering::equal;
+
+      __detail::__variant::__raw_idx_visit(
+       [&__ret, &__v] (auto&& __w_mem, auto __w_index) mutable
+       {
+         if constexpr (__w_index != variant_npos)
+           {
+             if (__v.index() == __w_index)
+               {
+                 auto& __this_mem = std::get<__w_index>(__v);
+                 __ret = __this_mem <=> __w_mem;
+                 return;
+               }
+           }
+         __ret = (__v.index() + 1) <=> (__w_index + 1);
+       }, __w);
+      return __ret;
+    }
+
+  constexpr strong_ordering
+  operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; }
+#else
+  constexpr bool operator!=(monostate, monostate) noexcept { return false; }
+  constexpr bool operator<(monostate, monostate) noexcept { return false; }
+  constexpr bool operator>(monostate, monostate) noexcept { return false; }
+  constexpr bool operator<=(monostate, monostate) noexcept { return true; }
+  constexpr bool operator>=(monostate, monostate) noexcept { return true; }
+#endif
+
   template<typename _Visitor, typename... _Variants>
     constexpr decltype(auto) visit(_Visitor&&, _Variants&&...);
 
diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/three_way.cc b/libstdc++-v3/testsuite/20_util/optional/relops/three_way.cc
new file mode 100644 (file)
index 0000000..d7bd16b
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <optional>
+
+void
+test01()
+{
+  using O = std::optional<int>;
+
+  static_assert( std::is_eq(O{} <=> O{}) );
+  static_assert( std::is_lt(O{} <=> O{1}) );
+  static_assert( std::is_gt(O{1} <=> O{}) );
+  static_assert( std::is_eq(O{1} <=> O{1}) );
+  static_assert( std::is_lt(O{1} <=> O{2}) );
+
+  static_assert( O{} == O{} );
+  static_assert( O{} < O{1} );
+  static_assert( O{1} > O{} );
+  static_assert( O{1} == O{1} );
+  static_assert( O{1} != O{2} );
+  static_assert( O{1} < O{2} );
+
+  using Os = std::optional<short>;
+  static_assert( std::is_eq(O{} <=> Os{}) );
+  static_assert( std::is_lt(O{} <=> Os{1}) );
+  static_assert( std::is_gt(O{1} <=> Os{}) );
+  static_assert( std::is_eq(O{1} <=> Os{1}) );
+  static_assert( std::is_lt(O{1} <=> Os{2}) );
+
+  static_assert( O{} == Os{} );
+  static_assert( O{} < Os{1} );
+  static_assert( O{1} > Os{} );
+  static_assert( O{1} == Os{1} );
+  static_assert( O{1} != Os{2} );
+  static_assert( O{1} < Os{2} );
+
+  // Would requires narrowing conversion to make operands the same type:
+  static_assert( !std::three_way_comparable_with<O, std::optional<unsigned>> );
+}
+
+void
+test02()
+{
+  using O = std::optional<int>;
+  using std::nullopt;
+
+  static_assert( std::is_eq(O{} <=> nullopt) );
+  static_assert( std::is_gt(O{1} <=> nullopt) );
+  static_assert( std::is_lt(nullopt <=> O{1}) );
+
+  static_assert( O{} == nullopt );
+  static_assert( O{1} != nullopt );
+  static_assert( nullopt != O{1} );
+  static_assert( O{1} > nullopt );
+  static_assert( nullopt < O{1} );
+  static_assert( nullopt <= O{} );
+  static_assert( nullopt <= O{1} );
+}
diff --git a/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/three_way.cc b/libstdc++-v3/testsuite/20_util/tuple/comparison_operators/three_way.cc
new file mode 100644 (file)
index 0000000..f8752d7
--- /dev/null
@@ -0,0 +1,102 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// Tuple
+
+#include <tuple>
+#include <testsuite_hooks.h>
+
+using namespace std;
+
+template<typename T>
+bool self_consistent(const T& x)
+{
+  return std::is_eq(x <=> x) && x == x && !(x != x) && x <= x && !(x < x);
+}
+
+void
+test01()
+{
+  int i=0;
+  int j=0;
+  int k=2;
+  tuple<int, int, int> a(0, 0, 0);
+  tuple<int, int, int> b(0, 0, 1);
+  tuple<int& , int& , int&> c(i,j,k);
+  tuple<const int&, const int&, const int&> d(c);
+  VERIFY( self_consistent(a) );
+  VERIFY( self_consistent(b) );
+  VERIFY( self_consistent(c) );
+  VERIFY( self_consistent(d) );
+  VERIFY( !(a > a) && !(b > b) );
+  VERIFY( a >= a && b >= b );
+  VERIFY( a < b && !(b < a) && a <= b && !(b <= a) );
+  VERIFY( b > a && !(a > b) && b >= a && !(a >= b) );
+
+  VERIFY( std::is_lt(a <=> b) );
+  VERIFY( std::is_gt(b <=> a) );
+  VERIFY( std::is_gt(c <=> a) );
+  VERIFY( std::is_eq(c <=> d) );
+
+  static_assert( std::is_same_v<decltype(a <=> d), std::strong_ordering> );
+}
+
+template<typename T, typename U, typename C>
+constexpr bool
+check_compare(T&& t, U&& u, C c)
+{
+  using R = std::compare_three_way_result_t<T, U>;
+  static_assert( std::same_as<C, R> );
+  return (t <=> u) == c;
+}
+
+void
+test02()
+{
+  using std::strong_ordering;
+  using std::weak_ordering;
+  using std::partial_ordering;
+
+  using T0 = std::tuple<>;
+  static_assert( check_compare(T0(), T0(), strong_ordering::equal) );
+
+  using Ti = std::tuple<int>;
+  using Tu = std::tuple<unsigned>;
+  static_assert( check_compare(Ti(1), Tu(1u), weak_ordering::equivalent) );
+  static_assert( check_compare(Ti(1), Tu(2u), weak_ordering::less) );
+  static_assert( check_compare(Ti(-1), Tu(1u), weak_ordering::greater) );
+
+  using Tii = std::tuple<int, int>;
+  using Tlu = std::tuple<long, unsigned>;
+  static_assert( check_compare(Tii(1, 2), Tlu(2l, 1u), weak_ordering::less) );
+
+  using Tid = std::tuple<int, double>;
+  static_assert( check_compare(Tii(3, 4), Tid(2, 0.9), partial_ordering::greater) );
+
+  static_assert( !std::three_way_comparable_with<T0, Ti> );
+  static_assert( !std::three_way_comparable_with<Ti, Tii> );
+  static_assert( !std::three_way_comparable_with<Ti, Tid> );
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/89851.cc b/libstdc++-v3/testsuite/20_util/variant/89851.cc
deleted file mode 100644 (file)
index 264f58c..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (C) 2019-2020 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library.  This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License along
-// with this library; see the file COPYING3.  If not see
-// <http://www.gnu.org/licenses/>.
-
-// { dg-options "-std=gnu++17" }
-// { dg-do run { target c++17 } }
-
-#include <variant>
-#include <testsuite_hooks.h>
-
-// PR libstdc++/89851
-
-void
-test01()
-{
-  using V = std::variant<int, int>;
-  V v1{std::in_place_index<0>, 0};
-  V v2{std::in_place_index<1>, 0};
-  VERIFY(   v1 != v2  );
-  VERIFY( !(v1 == v2) );
-}
-
-int
-main()
-{
-  test01();
-}
diff --git a/libstdc++-v3/testsuite/20_util/variant/90008.cc b/libstdc++-v3/testsuite/20_util/variant/90008.cc
deleted file mode 100644 (file)
index 4f4e969..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2019-2020 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library.  This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License along
-// with this library; see the file COPYING3.  If not see
-// <http://www.gnu.org/licenses/>.
-
-// { dg-options "-std=gnu++17" }
-// { dg-do compile { target c++17 } }
-
-#include <variant>
-
-struct NoCopy
-{
-  NoCopy();
-  NoCopy(const NoCopy&) = delete;
-};
-
-bool operator==(const NoCopy&, const NoCopy&);
-
-using V = std::variant<NoCopy, int>;
-
-bool
-test01(const V& lhs, const V& rhs)
-{
-  return lhs == rhs;
-}
diff --git a/libstdc++-v3/testsuite/20_util/variant/relops/89851.cc b/libstdc++-v3/testsuite/20_util/variant/relops/89851.cc
new file mode 100644 (file)
index 0000000..264f58c
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <variant>
+#include <testsuite_hooks.h>
+
+// PR libstdc++/89851
+
+void
+test01()
+{
+  using V = std::variant<int, int>;
+  V v1{std::in_place_index<0>, 0};
+  V v2{std::in_place_index<1>, 0};
+  VERIFY(   v1 != v2  );
+  VERIFY( !(v1 == v2) );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/relops/90008.cc b/libstdc++-v3/testsuite/20_util/variant/relops/90008.cc
new file mode 100644 (file)
index 0000000..4f4e969
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <variant>
+
+struct NoCopy
+{
+  NoCopy();
+  NoCopy(const NoCopy&) = delete;
+};
+
+bool operator==(const NoCopy&, const NoCopy&);
+
+using V = std::variant<NoCopy, int>;
+
+bool
+test01(const V& lhs, const V& rhs)
+{
+  return lhs == rhs;
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/relops/three_way.cc b/libstdc++-v3/testsuite/20_util/variant/relops/three_way.cc
new file mode 100644 (file)
index 0000000..b4f78e8
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <variant>
+
+void
+test01()
+{
+  using V = std::variant<int, int>;
+  constexpr auto I0 = std::in_place_index<0>;
+  constexpr auto I1 = std::in_place_index<1>;
+
+  static_assert( std::is_eq(V{I0, 0} <=> V{I0, 0})  );
+  static_assert( std::is_eq(V{I0, 1} <=> V{I0, 1})  );
+
+  static_assert( std::is_lt(V{I0, 0} <=> V{I1, 0})  );
+  static_assert( std::is_lt(V{I0, 1} <=> V{I1, 0})  );
+
+  static_assert( std::is_gt(V{I0, 1} <=> V{I0, 0})  );
+  static_assert( std::is_gt(V{I1, 0} <=> V{I0, 1})  );
+
+  static_assert( V{I0, 0} == V{I0, 0}  );
+  static_assert( V{I0, 0} != V{I1, 0}  );
+  static_assert( V{I1, 0} != V{I1, 1}  );
+}
+
+void
+test02()
+{
+  static_assert( std::is_eq(std::monostate{} <=> std::monostate{}) );
+  static_assert( std::monostate{} == std::monostate{} );
+  static_assert( std::monostate{} <= std::monostate{} );
+  static_assert( std::monostate{} >= std::monostate{} );
+  static_assert( !(std::monostate{} != std::monostate{}) );
+  static_assert( !(std::monostate{} < std::monostate{}) );
+  static_assert( !(std::monostate{} > std::monostate{}) );
+}