[committed] libstdc++: Add comparison operators to sequence containers

Jonathan Wakely jwakely@redhat.com
Fri Apr 17 22:42:19 GMT 2020


Some more C++20 changes from P1614R2, "The Mothership has Landed".

This implements <=> for sequence containers (and the __normal_iterator
and _Pointer_adapter class templates).

	* include/bits/forward_list.h (forward_list): Define operator<=> and
	remove redundant comparison operators for C++20.
	* include/bits/stl_bvector.h (vector<bool, Alloc>): Likewise.
	* include/bits/stl_deque.h (deque): Likewise.
	* include/bits/stl_iterator.h (__normal_iterator): Likewise.
	* include/bits/stl_list.h (list): Likewise.
	* include/bits/stl_vector.h (vector): Likewise.
	* include/debug/deque (__gnu_debug::deque): Likewise.
	* include/debug/forward_list (__gnu_debug::forward_list): Likewise.
	* include/debug/list (__gnu_debug::list): Likewise.
	* include/debug/safe_iterator.h (__gnu_debug::_Safe_iterator):
	Likewise.
	* include/debug/vector (__gnu_debug::vector): Likewise.
	* include/ext/pointer.h (__gnu_cxx::_Pointer_adapter): Define
	operator<=> for C++20.
	* testsuite/23_containers/deque/operators/cmp_c++20.cc: New test.
	* testsuite/23_containers/forward_list/cmp_c++20.cc: New test.
	* testsuite/23_containers/list/cmp_c++20.cc: New test.
	* testsuite/23_containers/vector/bool/cmp_c++20.cc: New test.
	* testsuite/23_containers/vector/cmp_c++20.cc: New test.

Tested powerpc64le-linux, committed to master.

I have patches on the way for associative containers and <chrono>,
after which the only parts of P1614R2 missing are the unordered
containers and container adaptors, which are both easy.


-------------- next part --------------
commit bd2420f8faaf4bb33310e82f7dd45c5e33476c87
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Apr 17 23:41:04 2020 +0100

    libstdc++: Add comparison operators to sequence containers
    
    Some more C++20 changes from P1614R2, "The Mothership has Landed".
    
    This implements <=> for sequence containers (and the __normal_iterator
    and _Pointer_adapter class templates).
    
            * include/bits/forward_list.h (forward_list): Define operator<=> and
            remove redundant comparison operators for C++20.
            * include/bits/stl_bvector.h (vector<bool, Alloc>): Likewise.
            * include/bits/stl_deque.h (deque): Likewise.
            * include/bits/stl_iterator.h (__normal_iterator): Likewise.
            * include/bits/stl_list.h (list): Likewise.
            * include/bits/stl_vector.h (vector): Likewise.
            * include/debug/deque (__gnu_debug::deque): Likewise.
            * include/debug/forward_list (__gnu_debug::forward_list): Likewise.
            * include/debug/list (__gnu_debug::list): Likewise.
            * include/debug/safe_iterator.h (__gnu_debug::_Safe_iterator):
            Likewise.
            * include/debug/vector (__gnu_debug::vector): Likewise.
            * include/ext/pointer.h (__gnu_cxx::_Pointer_adapter): Define
            operator<=> for C++20.
            * testsuite/23_containers/deque/operators/cmp_c++20.cc: New test.
            * testsuite/23_containers/forward_list/cmp_c++20.cc: New test.
            * testsuite/23_containers/list/cmp_c++20.cc: New test.
            * testsuite/23_containers/vector/bool/cmp_c++20.cc: New test.
            * testsuite/23_containers/vector/cmp_c++20.cc: New test.

diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h
index b926d45f205..49b2a973718 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -180,13 +180,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       operator==(const _Self& __x, const _Self& __y) noexcept
       { return __x._M_node == __y._M_node; }
 
-
+#if __cpp_impl_three_way_comparison < 201907L
       /**
        *  @brief  Forward list iterator inequality comparison.
        */
       friend bool
       operator!=(const _Self& __x, const _Self& __y) noexcept
       { return __x._M_node != __y._M_node; }
+#endif
 
       _Self
       _M_next() const noexcept
@@ -258,12 +259,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       operator==(const _Self& __x, const _Self& __y) noexcept
       { return __x._M_node == __y._M_node; }
 
+#if __cpp_impl_three_way_comparison < 201907L
       /**
        *  @brief  Forward list const_iterator inequality comparison.
        */
       friend bool
       operator!=(const _Self& __x, const _Self& __y) noexcept
       { return __x._M_node != __y._M_node; }
+#endif
 
       _Self
       _M_next() const noexcept
@@ -1426,6 +1429,28 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     operator==(const forward_list<_Tp, _Alloc>& __lx,
 	       const forward_list<_Tp, _Alloc>& __ly);
 
+#if __cpp_lib_three_way_comparison
+  /**
+   *  @brief  Forward list ordering relation.
+   *  @param  __x  A `forward_list`.
+   *  @param  __y  A `forward_list` of the same type as `__x`.
+   *  @return  A value indicating whether `__x` is less than, equal to,
+   *           greater than, or incomparable with `__y`.
+   *
+   *  See `std::lexicographical_compare_three_way()` for how the determination
+   *  is made. This operator is used to synthesize relational operators like
+   *  `<` and `>=` etc.
+  */
+  template<typename _Tp, typename _Alloc>
+    inline __detail::__synth3way_t<_Tp>
+    operator<=>(const forward_list<_Tp, _Alloc>& __x,
+		const forward_list<_Tp, _Alloc>& __y)
+    {
+      return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
+						    __y.begin(), __y.end(),
+						    __detail::__synth3way);
+    }
+#else
   /**
    *  @brief  Forward list ordering relation.
    *  @param  __lx  A %forward_list.
@@ -1472,6 +1497,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     operator<=(const forward_list<_Tp, _Alloc>& __lx,
 	       const forward_list<_Tp, _Alloc>& __ly)
     { return !(__ly < __lx); }
+#endif // three-way comparison
 
   /// See std::forward_list::swap().
   template<typename _Tp, typename _Alloc>
diff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h
index 1b16bc3b7d8..f245e52b25d 100644
--- a/libstdc++-v3/include/bits/stl_bvector.h
+++ b/libstdc++-v3/include/bits/stl_bvector.h
@@ -182,10 +182,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       _M_offset = static_cast<unsigned int>(__n);
     }
 
-    friend bool
+    friend _GLIBCXX20_CONSTEXPR bool
     operator==(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y)
     { return __x._M_p == __y._M_p && __x._M_offset == __y._M_offset; }
 
+#if __cpp_lib_three_way_comparison
+    friend constexpr strong_ordering
+    operator<=>(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y)
+    noexcept
+    {
+      if (const auto __cmp = __x._M_p <=> __y._M_p; __cmp != 0)
+	return __cmp;
+      return __x._M_offset <=> __y._M_offset;
+    }
+#else
     friend bool
     operator<(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y)
     {
@@ -208,6 +218,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     friend bool
     operator>=(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y)
     { return !(__x < __y); }
+#endif // three-way comparison
 
     friend ptrdiff_t
     operator-(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y)
diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h
index c1af637f67b..3959dd7899d 100644
--- a/libstdc++-v3/include/bits/stl_deque.h
+++ b/libstdc++-v3/include/bits/stl_deque.h
@@ -63,6 +63,9 @@
 #include <initializer_list>
 #include <bits/stl_uninitialized.h> // for __is_bitwise_relocatable
 #endif
+#if __cplusplus > 201703L
+# include <compare>
+#endif
 
 #include <debug/assertions.h>
 
@@ -266,14 +269,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       { return __x._M_cur == __y._M_cur; }
 
       // Note: we also provide overloads whose operands are of the same type in
-      // order to avoid ambiguous overload resolution when std::rel_ops operators
-      // are in scope (for additional details, see libstdc++/3628)
+      // order to avoid ambiguous overload resolution when std::rel_ops
+      // operators are in scope (for additional details, see libstdc++/3628)
       template<typename _RefR, typename _PtrR>
 	friend bool
 	operator==(const _Self& __x,
-		   const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT
+		   const _Deque_iterator<_Tp, _RefR, _PtrR>& __y)
+	_GLIBCXX_NOEXCEPT
 	{ return __x._M_cur == __y._M_cur; }
 
+#if __cpp_lib_three_way_comparison
+      friend strong_ordering
+      operator<=>(const _Self& __x, const _Self& __y) noexcept
+      {
+	if (const auto __cmp = __x._M_node <=> __y._M_node; __cmp != 0)
+	  return __cmp;
+	return __x._M_cur <=> __y._M_cur;
+      }
+#else
       friend bool
       operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return !(__x == __y); }
@@ -281,7 +294,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _RefR, typename _PtrR>
 	friend bool
 	operator!=(const _Self& __x,
-		   const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT
+		   const _Deque_iterator<_Tp, _RefR, _PtrR>& __y)
+	_GLIBCXX_NOEXCEPT
 	{ return !(__x == __y); }
 
       friend bool
@@ -294,7 +308,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _RefR, typename _PtrR>
 	friend bool
 	operator<(const _Self& __x,
-		  const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT
+		  const _Deque_iterator<_Tp, _RefR, _PtrR>& __y)
+	_GLIBCXX_NOEXCEPT
 	{
 	  return (__x._M_node == __y._M_node)
 	    ? (__x._M_cur < __y._M_cur) : (__x._M_node < __y._M_node);
@@ -307,7 +322,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _RefR, typename _PtrR>
 	friend bool
 	operator>(const _Self& __x,
-		  const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT
+		  const _Deque_iterator<_Tp, _RefR, _PtrR>& __y)
+	_GLIBCXX_NOEXCEPT
 	{ return __y < __x; }
 
       friend bool
@@ -317,7 +333,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _RefR, typename _PtrR>
 	friend bool
 	operator<=(const _Self& __x,
-		   const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT
+		   const _Deque_iterator<_Tp, _RefR, _PtrR>& __y)
+	_GLIBCXX_NOEXCEPT
 	{ return !(__y < __x); }
 
       friend bool
@@ -327,8 +344,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _RefR, typename _PtrR>
 	friend bool
 	operator>=(const _Self& __x,
-		   const _Deque_iterator<_Tp, _RefR, _PtrR>& __y) _GLIBCXX_NOEXCEPT
+		   const _Deque_iterator<_Tp, _RefR, _PtrR>& __y)
+	_GLIBCXX_NOEXCEPT
 	{ return !(__x < __y); }
+#endif // three-way comparison
 
       friend difference_type
       operator-(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
@@ -2223,6 +2242,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     { return __x.size() == __y.size()
 	     && std::equal(__x.begin(), __x.end(), __y.begin()); }
 
+#if __cpp_lib_three_way_comparison
+  /**
+   *  @brief  Deque ordering relation.
+   *  @param  __x  A `deque`.
+   *  @param  __y  A `deque` of the same type as `__x`.
+   *  @return  A value indicating whether `__x` is less than, equal to,
+   *           greater than, or incomparable with `__y`.
+   *
+   *  See `std::lexicographical_compare_three_way()` for how the determination
+   *  is made. This operator is used to synthesize relational operators like
+   *  `<` and `>=` etc.
+  */
+  template<typename _Tp, typename _Alloc>
+    inline __detail::__synth3way_t<_Tp>
+    operator<=>(const deque<_Tp, _Alloc>& __x, const deque<_Tp, _Alloc>& __y)
+    {
+      return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
+						    __y.begin(), __y.end(),
+						    __detail::__synth3way);
+    }
+#else
   /**
    *  @brief  Deque ordering relation.
    *  @param  __x  A %deque.
@@ -2263,6 +2303,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     inline bool
     operator>=(const deque<_Tp, _Alloc>& __x, const deque<_Tp, _Alloc>& __y)
     { return !(__x < __y); }
+#endif // three-way comparison
 
   /// See std::deque::swap().
   template<typename _Tp, typename _Alloc>
diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index d7972b71998..5bfdce6af2d 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1037,7 +1037,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // provide overloads whose operands are of the same type.  Can someone
   // remind me what generic programming is about? -- Gaby
 
-  // Forward iterator requirements
+#if __cpp_lib_three_way_comparison
+  template<typename _IteratorL, typename _IteratorR, typename _Container>
+    requires requires (_IteratorL __lhs, _IteratorR __rhs)
+    { { __lhs == __rhs } -> std::convertible_to<bool>; }
+    constexpr bool
+    operator==(const __normal_iterator<_IteratorL, _Container>& __lhs,
+	       const __normal_iterator<_IteratorR, _Container>& __rhs)
+    noexcept(noexcept(__lhs.base() == __rhs.base()))
+    { return __lhs.base() == __rhs.base(); }
+
+  template<typename _IteratorL, typename _IteratorR, typename _Container>
+    constexpr auto
+    operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs,
+		const __normal_iterator<_IteratorR, _Container>& __rhs)
+    noexcept(noexcept(__lhs.base() <=> __rhs.base()))
+    -> decltype(__lhs.base() <=> __rhs.base())
+    { return __lhs.base() <=> __rhs.base(); }
+#else
+   // Forward iterator requirements
   template<typename _IteratorL, typename _IteratorR, typename _Container>
     _GLIBCXX20_CONSTEXPR
     inline bool
@@ -1072,11 +1090,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Random access iterator requirements
   template<typename _IteratorL, typename _IteratorR, typename _Container>
-#if __cplusplus > 201703L
-    constexpr auto
-#else
     inline bool
-#endif
     operator<(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	      const __normal_iterator<_IteratorR, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
@@ -1091,11 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() < __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
-#if __cplusplus > 201703L
-    constexpr auto
-#else
     inline bool
-#endif
     operator>(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	      const __normal_iterator<_IteratorR, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
@@ -1110,11 +1120,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() > __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
-#if __cplusplus > 201703L
-    constexpr auto
-#else
     inline bool
-#endif
     operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	       const __normal_iterator<_IteratorR, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
@@ -1129,11 +1135,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() <= __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
-#if __cplusplus > 201703L
-    constexpr auto
-#else
     inline bool
-#endif
     operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	       const __normal_iterator<_IteratorR, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
@@ -1146,6 +1148,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	       const __normal_iterator<_Iterator, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
     { return __lhs.base() >= __rhs.base(); }
+#endif // three-way comparison
 
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // According to the resolution of DR179 not only the various comparison
diff --git a/libstdc++-v3/include/bits/stl_list.h b/libstdc++-v3/include/bits/stl_list.h
index 97b8fb549b5..e7135e3e7ed 100644
--- a/libstdc++-v3/include/bits/stl_list.h
+++ b/libstdc++-v3/include/bits/stl_list.h
@@ -247,9 +247,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return __x._M_node == __y._M_node; }
 
+#if __cpp_impl_three_way_comparison < 201907L
       friend bool
       operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return __x._M_node != __y._M_node; }
+#endif
 
       // The only member points to the %list element.
       __detail::_List_node_base* _M_node;
@@ -331,9 +333,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return __x._M_node == __y._M_node; }
 
+#if __cpp_impl_three_way_comparison < 201907L
       friend bool
       operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return __x._M_node != __y._M_node; }
+#endif
 
       // The only member points to the %list element.
       const __detail::_List_node_base* _M_node;
@@ -2009,6 +2013,27 @@ _GLIBCXX_END_NAMESPACE_CXX11
       return __i1 == __end1 && __i2 == __end2;
     }
 
+#if __cpp_lib_three_way_comparison
+/**
+   *  @brief  List ordering relation.
+   *  @param  __x  A `list`.
+   *  @param  __y  A `list` of the same type as `__x`.
+   *  @return  A value indicating whether `__x` is less than, equal to,
+   *           greater than, or incomparable with `__y`.
+   *
+   *  See `std::lexicographical_compare_three_way()` for how the determination
+   *  is made. This operator is used to synthesize relational operators like
+   *  `<` and `>=` etc.
+  */
+  template<typename _Tp, typename _Alloc>
+    inline __detail::__synth3way_t<_Tp>
+    operator<=>(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y)
+    {
+      return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
+						    __y.begin(), __y.end(),
+						    __detail::__synth3way);
+    }
+#else
   /**
    *  @brief  List ordering relation.
    *  @param  __x  A %list.
@@ -2049,6 +2074,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
     inline bool
     operator>=(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y)
     { return !(__x < __y); }
+#endif // three-way comparison
 
   /// See std::list::swap().
   template<typename _Tp, typename _Alloc>
diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 14308a37770..d3f1b1fae5c 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -62,6 +62,9 @@
 #if __cplusplus >= 201103L
 #include <initializer_list>
 #endif
+#if __cplusplus > 201703L
+# include <compare>
+#endif
 
 #include <debug/assertions.h>
 
@@ -1890,6 +1893,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     { return (__x.size() == __y.size()
 	      && std::equal(__x.begin(), __x.end(), __y.begin())); }
 
+#if __cpp_lib_three_way_comparison
+  /**
+   *  @brief  Vector ordering relation.
+   *  @param  __x  A `vector`.
+   *  @param  __y  A `vector` of the same type as `__x`.
+   *  @return  A value indicating whether `__x` is less than, equal to,
+   *           greater than, or incomparable with `__y`.
+   *
+   *  See `std::lexicographical_compare_three_way()` for how the determination
+   *  is made. This operator is used to synthesize relational operators like
+   *  `<` and `>=` etc.
+  */
+  template<typename _Tp, typename _Alloc>
+    inline __detail::__synth3way_t<_Tp>
+    operator<=>(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y)
+    {
+      return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
+						    __y.begin(), __y.end(),
+						    __detail::__synth3way);
+    }
+#else
   /**
    *  @brief  Vector ordering relation.
    *  @param  __x  A %vector.
@@ -1930,6 +1954,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     inline bool
     operator>=(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y)
     { return !(__x < __y); }
+#endif // three-way comparison
 
   /// See std::vector::swap().
   template<typename _Tp, typename _Alloc>
diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque
index 8c6b4d14c2b..4d525bfc0aa 100644
--- a/libstdc++-v3/include/debug/deque
+++ b/libstdc++-v3/include/debug/deque
@@ -648,6 +648,12 @@ namespace __debug
 	       const deque<_Tp, _Alloc>& __rhs)
     { return __lhs._M_base() == __rhs._M_base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Tp, typename _Alloc>
+    constexpr __detail::__synth3way_t<_Tp>
+    operator<=>(const deque<_Tp, _Alloc>& __x, const deque<_Tp, _Alloc>& __y)
+    { return __x._M_base() <=> __y._M_base(); }
+#else
   template<typename _Tp, typename _Alloc>
     inline bool
     operator!=(const deque<_Tp, _Alloc>& __lhs,
@@ -677,6 +683,7 @@ namespace __debug
     operator>(const deque<_Tp, _Alloc>& __lhs,
 	      const deque<_Tp, _Alloc>& __rhs)
     { return __lhs._M_base() > __rhs._M_base(); }
+#endif // three-way comparison
 
   template<typename _Tp, typename _Alloc>
     inline void
diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list
index f0ff62c8cb1..2fd03e70499 100644
--- a/libstdc++-v3/include/debug/forward_list
+++ b/libstdc++-v3/include/debug/forward_list
@@ -838,6 +838,13 @@ namespace __debug
 	       const forward_list<_Tp, _Alloc>& __ly)
     { return __lx._M_base() == __ly._M_base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Tp, typename _Alloc>
+    constexpr __detail::__synth3way_t<_Tp>
+    operator<=>(const forward_list<_Tp, _Alloc>& __x,
+		const forward_list<_Tp, _Alloc>& __y)
+    { return __x._M_base() <=> __y._M_base(); }
+#else
   template<typename _Tp, typename _Alloc>
     inline bool
     operator<(const forward_list<_Tp, _Alloc>& __lx,
@@ -870,6 +877,7 @@ namespace __debug
     operator<=(const forward_list<_Tp, _Alloc>& __lx,
 	       const forward_list<_Tp, _Alloc>& __ly)
     { return !(__ly < __lx); }
+#endif // three-way comparison
 
   /// See std::forward_list::swap().
   template<typename _Tp, typename _Alloc>
diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list
index ee54ef27e57..6dd85741f81 100644
--- a/libstdc++-v3/include/debug/list
+++ b/libstdc++-v3/include/debug/list
@@ -864,6 +864,12 @@ namespace __debug
 	       const list<_Tp, _Alloc>& __rhs)
     { return __lhs._M_base() == __rhs._M_base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Tp, typename _Alloc>
+    constexpr __detail::__synth3way_t<_Tp>
+    operator<=>(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y)
+    { return __x._M_base() <=> __y._M_base(); }
+#else
   template<typename _Tp, typename _Alloc>
     inline bool
     operator!=(const list<_Tp, _Alloc>& __lhs,
@@ -893,6 +899,7 @@ namespace __debug
     operator>(const list<_Tp, _Alloc>& __lhs,
 	      const list<_Tp, _Alloc>& __rhs)
     { return __lhs._M_base() > __rhs._M_base(); }
+#endif // three-way comparison
 
   template<typename _Tp, typename _Alloc>
     inline void
diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
index f746cca5fb3..687b844fd75 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -35,6 +35,9 @@
 #include <debug/safe_base.h>
 #include <bits/stl_pair.h>
 #include <ext/type_traits.h>
+#if __cplusplus > 201703L
+# include <compare>
+#endif
 
 #define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, _BadMsgId, _DiffMsgId) \
   _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular(),	\
@@ -469,6 +472,7 @@ namespace __gnu_debug
 	  return __lhs.base() == __rhs.base();
 	}
 
+#if ! __cpp_lib_three_way_comparison
       friend bool
       operator!=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -485,6 +489,7 @@ namespace __gnu_debug
 	  _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS(__lhs, __rhs);
 	  return __lhs.base() != __rhs.base();
 	}
+#endif // three-way comparison
     };
 
   template<typename _Iterator, typename _Sequence>
@@ -805,6 +810,21 @@ namespace __gnu_debug
 	return *this;
       }
 
+#if __cpp_lib_three_way_comparison
+      friend auto
+      operator<=>(const _Self& __lhs, const _Self& __rhs) noexcept
+      {
+	_GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
+	return __lhs.base() <=> __rhs.base();
+      }
+
+      friend auto
+      operator<=>(const _Self& __lhs, const _OtherSelf& __rhs) noexcept
+      {
+	_GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
+	return __lhs.base() <=> __rhs.base();
+      }
+#else
       friend bool
       operator<(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -860,6 +880,7 @@ namespace __gnu_debug
 	_GLIBCXX_DEBUG_VERIFY_REL_OPERANDS(__lhs, __rhs);
 	return __lhs.base() >= __rhs.base();
       }
+#endif // three-way comparison
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // According to the resolution of DR179 not only the various comparison
diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
index 96772f72643..4c08ab61ce8 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -731,6 +731,12 @@ namespace __debug
 	       const vector<_Tp, _Alloc>& __rhs)
     { return __lhs._M_base() == __rhs._M_base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Tp, typename _Alloc>
+    constexpr __detail::__synth3way_t<_Tp>
+    operator<=>(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y)
+    { return __x._M_base() <=> __y._M_base(); }
+#else
   template<typename _Tp, typename _Alloc>
     inline bool
     operator!=(const vector<_Tp, _Alloc>& __lhs,
@@ -760,6 +766,7 @@ namespace __debug
     operator>(const vector<_Tp, _Alloc>& __lhs,
 	      const vector<_Tp, _Alloc>& __rhs)
     { return __lhs._M_base() > __rhs._M_base(); }
+#endif // three-way comparison
 
   template<typename _Tp, typename _Alloc>
     inline void
diff --git a/libstdc++-v3/include/ext/pointer.h b/libstdc++-v3/include/ext/pointer.h
index aef622e2e23..a0ade4a677e 100644
--- a/libstdc++-v3/include/ext/pointer.h
+++ b/libstdc++-v3/include/ext/pointer.h
@@ -479,7 +479,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         _Storage_policy::set(_Storage_policy::get() - 1);
         return __tmp;
       }
-  
+
+#if __cpp_lib_three_way_comparison
+      friend std::strong_ordering
+      operator<=>(const _Pointer_adapter& __lhs, const _Pointer_adapter& __rhs)
+      noexcept
+      { return __lhs.get() <=> __rhs.get(); }
+#endif
     }; // class _Pointer_adapter
 
 
diff --git a/libstdc++-v3/testsuite/23_containers/deque/operators/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/deque/operators/cmp_c++20.cc
new file mode 100644
index 00000000000..77668fcd1f6
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/operators/cmp_c++20.cc
@@ -0,0 +1,161 @@
+// 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 run { target c++2a } }
+
+#include <deque>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::deque<int> c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 };
+  VERIFY( c1 == c1 );
+  VERIFY( std::is_eq(c1 <=> c1) );
+  VERIFY( c1 < c2 );
+  VERIFY( std::is_lt(c1 <=> c2) );
+  VERIFY( c1 < c3 );
+  VERIFY( std::is_lt(c1 <=> c3) );
+  VERIFY( c2 < c3 );
+  VERIFY( std::is_lt(c2 <=> c3) );
+
+  static_assert( std::totally_ordered<std::deque<int>> );
+
+  static_assert( std::three_way_comparable<std::deque<int>,
+					   std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::deque<float>,
+					     std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::deque<float>,
+					     std::weak_ordering> );
+  static_assert( std::three_way_comparable<std::deque<float>,
+					   std::partial_ordering> );
+
+  struct E
+  {
+    bool operator==(E) { return true; }
+  };
+  static_assert( ! std::totally_ordered<std::deque<E>> );
+  static_assert( ! std::three_way_comparable<E> );
+  static_assert( ! std::three_way_comparable<std::deque<E>> );
+}
+
+void
+test02()
+{
+  struct W
+  {
+    int value = 0;
+
+    bool operator==(W rhs) const noexcept
+    { return (value | 1) == (rhs.value | 1); }
+
+    std::weak_ordering
+    operator<=>(W rhs) const noexcept
+    { return (value | 1) <=> (rhs.value | 1); }
+  };
+
+  static_assert( std::totally_ordered<std::deque<W>> );
+
+  std::deque<W> c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} };
+  static_assert( std::same_as<decltype(c1 <=> c1), std::weak_ordering> );
+  VERIFY( c1 == c2 );
+  VERIFY( std::is_eq(c1 <=> c2) );
+}
+
+void
+test03()
+{
+  struct P
+  {
+    int value = 0;
+
+    bool operator==(P rhs) const noexcept
+    {
+      if (value < 0 || rhs.value < 0)
+	return false;
+      return value == rhs.value;
+    }
+
+    std::partial_ordering
+    operator<=>(P rhs) const noexcept
+    {
+      if (value < 0 || rhs.value < 0)
+	return std::partial_ordering::unordered;
+      return value <=> rhs.value;
+    }
+  };
+
+  static_assert( std::totally_ordered<std::deque<P>> );
+
+  std::deque<P> c{ {1}, {2}, {-3} };
+  static_assert( std::three_way_comparable<P> );
+  static_assert( std::same_as<decltype(c <=> c), std::partial_ordering> );
+  VERIFY( (c <=> c) == std::partial_ordering::unordered );
+}
+
+void
+test04()
+{
+  struct L
+  {
+    int value = 0;
+
+    bool operator<(L rhs) const noexcept { return value < rhs.value; }
+  };
+
+  static_assert( std::totally_ordered<std::deque<L>> );
+
+  std::deque<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} };
+  static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
+  VERIFY( std::is_lt(c <=> d) );
+}
+
+void
+test05()
+{
+  // deque iterators are random access, so should support <=>
+
+  std::deque<int> c{ 1, 2, 3 };
+  VERIFY( c.begin() == c.cbegin() );
+  VERIFY( std::is_eq(c.begin() <=> c.cbegin()) );
+
+  VERIFY( c.begin() < c.end() );
+  VERIFY( std::is_lt(c.begin() <=> c.end()) );
+
+  VERIFY( c.begin() < c.cend() );
+  VERIFY( std::is_lt(c.begin() <=> c.cend()) );
+
+  VERIFY( c.crbegin() == c.rbegin() );
+  VERIFY( std::is_eq(c.crbegin() <=> c.rbegin()) );
+
+  VERIFY( c.rend() > c.rbegin() );
+  VERIFY( std::is_gt(c.rend() <=> c.rbegin()) );
+
+  static_assert( std::same_as<decltype(c.begin() <=> c.begin()),
+			      std::strong_ordering> );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/forward_list/cmp_c++20.cc
new file mode 100644
index 00000000000..5a26d497ea6
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/cmp_c++20.cc
@@ -0,0 +1,138 @@
+// 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 run { target c++2a } }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::forward_list<int> c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 };
+  VERIFY( c1 == c1 );
+  VERIFY( std::is_eq(c1 <=> c1) );
+  VERIFY( c1 < c2 );
+  VERIFY( std::is_lt(c1 <=> c2) );
+  VERIFY( c1 < c3 );
+  VERIFY( std::is_lt(c1 <=> c3) );
+  VERIFY( c2 < c3 );
+  VERIFY( std::is_lt(c2 <=> c3) );
+
+  static_assert( std::totally_ordered<std::forward_list<int>> );
+
+  static_assert( std::three_way_comparable<std::forward_list<int>,
+					   std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::forward_list<float>,
+					     std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::forward_list<float>,
+					     std::weak_ordering> );
+  static_assert( std::three_way_comparable<std::forward_list<float>,
+					   std::partial_ordering> );
+
+  struct E
+  {
+    bool operator==(E) { return true; }
+  };
+  static_assert( ! std::totally_ordered<std::forward_list<E>> );
+  static_assert( ! std::three_way_comparable<E> );
+  static_assert( ! std::three_way_comparable<std::forward_list<E>> );
+}
+
+void
+test02()
+{
+  struct W
+  {
+    int value = 0;
+
+    bool operator==(W rhs) const noexcept
+    { return (value | 1) == (rhs.value | 1); }
+
+    std::weak_ordering
+    operator<=>(W rhs) const noexcept
+    { return (value | 1) <=> (rhs.value | 1); }
+  };
+
+  static_assert( std::totally_ordered<std::forward_list<W>> );
+
+  std::forward_list<W> c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} };
+  static_assert( std::same_as<decltype(c1 <=> c1), std::weak_ordering> );
+  VERIFY( c1 == c2 );
+  VERIFY( std::is_eq(c1 <=> c2) );
+}
+
+void
+test03()
+{
+  struct P
+  {
+    int value = 0;
+
+    bool operator==(P rhs) const noexcept
+    {
+      if (value < 0 || rhs.value < 0)
+	return false;
+      return value == rhs.value;
+    }
+
+    std::partial_ordering
+    operator<=>(P rhs) const noexcept
+    {
+      if (value < 0 || rhs.value < 0)
+	return std::partial_ordering::unordered;
+      return value <=> rhs.value;
+    }
+  };
+
+  static_assert( std::totally_ordered<std::forward_list<P>> );
+
+  std::forward_list<P> c{ {1}, {2}, {-3} };
+  static_assert( std::three_way_comparable<P> );
+  static_assert( std::same_as<decltype(c <=> c), std::partial_ordering> );
+  VERIFY( (c <=> c) == std::partial_ordering::unordered );
+}
+
+void
+test04()
+{
+  struct L
+  {
+    int value = 0;
+
+    bool operator<(L rhs) const noexcept { return value < rhs.value; }
+  };
+
+  static_assert( std::totally_ordered<std::forward_list<L>> );
+
+  std::forward_list<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} };
+  static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
+  VERIFY( std::is_lt(c <=> d) );
+}
+
+static_assert( ! std::totally_ordered<std::forward_list<int>::iterator> );
+static_assert( ! std::three_way_comparable<std::forward_list<int>::iterator> );
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/list/cmp_c++20.cc
new file mode 100644
index 00000000000..a5b9f8f5459
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/cmp_c++20.cc
@@ -0,0 +1,138 @@
+// 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 run { target c++2a } }
+
+#include <list>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::list<int> c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 };
+  VERIFY( c1 == c1 );
+  VERIFY( std::is_eq(c1 <=> c1) );
+  VERIFY( c1 < c2 );
+  VERIFY( std::is_lt(c1 <=> c2) );
+  VERIFY( c1 < c3 );
+  VERIFY( std::is_lt(c1 <=> c3) );
+  VERIFY( c2 < c3 );
+  VERIFY( std::is_lt(c2 <=> c3) );
+
+  static_assert( std::totally_ordered<std::list<int>> );
+
+  static_assert( std::three_way_comparable<std::list<int>,
+					   std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::list<float>,
+					     std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::list<float>,
+					     std::weak_ordering> );
+  static_assert( std::three_way_comparable<std::list<float>,
+					   std::partial_ordering> );
+
+  struct E
+  {
+    bool operator==(E) { return true; }
+  };
+  static_assert( ! std::totally_ordered<std::list<E>> );
+  static_assert( ! std::three_way_comparable<E> );
+  static_assert( ! std::three_way_comparable<std::list<E>> );
+}
+
+void
+test02()
+{
+  struct W
+  {
+    int value = 0;
+
+    bool operator==(W rhs) const noexcept
+    { return (value | 1) == (rhs.value | 1); }
+
+    std::weak_ordering
+    operator<=>(W rhs) const noexcept
+    { return (value | 1) <=> (rhs.value | 1); }
+  };
+
+  static_assert( std::totally_ordered<std::list<W>> );
+
+  std::list<W> c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} };
+  static_assert( std::same_as<decltype(c1 <=> c1), std::weak_ordering> );
+  VERIFY( c1 == c2 );
+  VERIFY( std::is_eq(c1 <=> c2) );
+}
+
+void
+test03()
+{
+  struct P
+  {
+    int value = 0;
+
+    bool operator==(P rhs) const noexcept
+    {
+      if (value < 0 || rhs.value < 0)
+	return false;
+      return value == rhs.value;
+    }
+
+    std::partial_ordering
+    operator<=>(P rhs) const noexcept
+    {
+      if (value < 0 || rhs.value < 0)
+	return std::partial_ordering::unordered;
+      return value <=> rhs.value;
+    }
+  };
+
+  static_assert( std::totally_ordered<std::list<P>> );
+
+  std::list<P> c{ {1}, {2}, {-3} };
+  static_assert( std::three_way_comparable<P> );
+  static_assert( std::same_as<decltype(c <=> c), std::partial_ordering> );
+  VERIFY( (c <=> c) == std::partial_ordering::unordered );
+}
+
+void
+test04()
+{
+  struct L
+  {
+    int value = 0;
+
+    bool operator<(L rhs) const noexcept { return value < rhs.value; }
+  };
+
+  static_assert( std::totally_ordered<std::list<L>> );
+
+  std::list<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} };
+  static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
+  VERIFY( std::is_lt(c <=> d) );
+}
+
+static_assert( ! std::totally_ordered<std::list<int>::iterator> );
+static_assert( ! std::three_way_comparable<std::list<int>::iterator> );
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc
new file mode 100644
index 00000000000..a586ab65cd7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc
@@ -0,0 +1,73 @@
+// 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 run { target c++2a } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::vector<bool> c1{ 1, 0, 1 }, c2{ 1, 0, 1, 0 }, c3{ 1, 1, 1 };
+  VERIFY( c1 == c1 );
+  VERIFY( std::is_eq(c1 <=> c1) );
+  VERIFY( c1 < c2 );
+  VERIFY( std::is_lt(c1 <=> c2) );
+  VERIFY( c1 < c3 );
+  VERIFY( std::is_lt(c1 <=> c3) );
+  VERIFY( c2 < c3 );
+  VERIFY( std::is_lt(c2 <=> c3) );
+
+  static_assert( std::totally_ordered<std::vector<bool>> );
+
+  static_assert( std::three_way_comparable<std::vector<bool>,
+					   std::strong_ordering> );
+}
+
+void
+test05()
+{
+  // vector<bool> iterators are random access, so should support <=>
+
+  std::vector<bool> c{ 1, 1, 1 };
+  VERIFY( c.begin() == c.cbegin() );
+  VERIFY( std::is_eq(c.begin() <=> c.cbegin()) );
+
+  VERIFY( c.begin() < c.end() );
+  VERIFY( std::is_lt(c.begin() <=> c.end()) );
+
+  VERIFY( c.begin() < c.cend() );
+  VERIFY( std::is_lt(c.begin() <=> c.cend()) );
+
+  VERIFY( c.crbegin() == c.rbegin() );
+  VERIFY( std::is_eq(c.crbegin() <=> c.rbegin()) );
+
+  VERIFY( c.rend() > c.rbegin() );
+  VERIFY( std::is_gt(c.rend() <=> c.rbegin()) );
+
+  static_assert( std::same_as<decltype(c.begin() <=> c.begin()),
+			      std::strong_ordering> );
+}
+
+int
+main()
+{
+  test01();
+  test05();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc
new file mode 100644
index 00000000000..ca6a4f43e22
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc
@@ -0,0 +1,161 @@
+// 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 run { target c++2a } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::vector<int> c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 };
+  VERIFY( c1 == c1 );
+  VERIFY( std::is_eq(c1 <=> c1) );
+  VERIFY( c1 < c2 );
+  VERIFY( std::is_lt(c1 <=> c2) );
+  VERIFY( c1 < c3 );
+  VERIFY( std::is_lt(c1 <=> c3) );
+  VERIFY( c2 < c3 );
+  VERIFY( std::is_lt(c2 <=> c3) );
+
+  static_assert( std::totally_ordered<std::vector<int>> );
+
+  static_assert( std::three_way_comparable<std::vector<int>,
+					   std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::vector<float>,
+					     std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::vector<float>,
+					     std::weak_ordering> );
+  static_assert( std::three_way_comparable<std::vector<float>,
+					   std::partial_ordering> );
+
+  struct E
+  {
+    bool operator==(E) { return true; }
+  };
+  static_assert( ! std::totally_ordered<std::vector<E>> );
+  static_assert( ! std::three_way_comparable<E> );
+  static_assert( ! std::three_way_comparable<std::vector<E>> );
+}
+
+void
+test02()
+{
+  struct W
+  {
+    int value = 0;
+
+    bool operator==(W rhs) const noexcept
+    { return (value | 1) == (rhs.value | 1); }
+
+    std::weak_ordering
+    operator<=>(W rhs) const noexcept
+    { return (value | 1) <=> (rhs.value | 1); }
+  };
+
+  static_assert( std::totally_ordered<std::vector<W>> );
+
+  std::vector<W> c1{ {1}, {2}, {3} }, c2{ {0}, {3}, {3} };
+  static_assert( std::same_as<decltype(c1 <=> c1), std::weak_ordering> );
+  VERIFY( c1 == c2 );
+  VERIFY( std::is_eq(c1 <=> c2) );
+}
+
+void
+test03()
+{
+  struct P
+  {
+    int value = 0;
+
+    bool operator==(P rhs) const noexcept
+    {
+      if (value < 0 || rhs.value < 0)
+	return false;
+      return value == rhs.value;
+    }
+
+    std::partial_ordering
+    operator<=>(P rhs) const noexcept
+    {
+      if (value < 0 || rhs.value < 0)
+	return std::partial_ordering::unordered;
+      return value <=> rhs.value;
+    }
+  };
+
+  static_assert( std::totally_ordered<std::vector<P>> );
+
+  std::vector<P> c{ {1}, {2}, {-3} };
+  static_assert( std::three_way_comparable<P> );
+  static_assert( std::same_as<decltype(c <=> c), std::partial_ordering> );
+  VERIFY( (c <=> c) == std::partial_ordering::unordered );
+}
+
+void
+test04()
+{
+  struct L
+  {
+    int value = 0;
+
+    bool operator<(L rhs) const noexcept { return value < rhs.value; }
+  };
+
+  static_assert( std::totally_ordered<std::vector<L>> );
+
+  std::vector<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} };
+  static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
+  VERIFY( std::is_lt(c <=> d) );
+}
+
+void
+test05()
+{
+  // vector iterators are random access, so should support <=>
+
+  std::vector<int> c{ 1, 2, 3 };
+  VERIFY( c.begin() == c.cbegin() );
+  VERIFY( std::is_eq(c.begin() <=> c.cbegin()) );
+
+  VERIFY( c.begin() < c.end() );
+  VERIFY( std::is_lt(c.begin() <=> c.end()) );
+
+  VERIFY( c.begin() < c.cend() );
+  VERIFY( std::is_lt(c.begin() <=> c.cend()) );
+
+  VERIFY( c.crbegin() == c.rbegin() );
+  VERIFY( std::is_eq(c.crbegin() <=> c.rbegin()) );
+
+  VERIFY( c.rend() > c.rbegin() );
+  VERIFY( std::is_gt(c.rend() <=> c.rbegin()) );
+
+  static_assert( std::same_as<decltype(c.begin() <=> c.begin()),
+			      std::strong_ordering> );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+}


More information about the Libstdc++ mailing list