[gcc(refs/vendors/redhat/heads/gcc-10-branch)] libstdc++: Add comparison operators to associative containers

Jakub Jelinek jakub@gcc.gnu.org
Thu Apr 30 21:58:40 GMT 2020


https://gcc.gnu.org/g:93843da69772d271a7247ab2536280646086a5ce

commit 93843da69772d271a7247ab2536280646086a5ce
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Apr 20 17:50:10 2020 +0100

    libstdc++: Add comparison operators to associative containers
    
    The last C++20 changes from P1614R2, "The Mothership has Landed"
    
            * include/bits/stl_map.h (map): Define operator<=> and remove
            operator< for C++20.
            * include/bits/stl_multimap.h (multimap): Likewise.
            * include/bits/stl_multiset.h (multiset): Likewise.
            * include/bits/stl_set.h (set): Likewise.
            * include/bits/stl_tree.h (_Rb_tree): Likewise.
            (_Rb_tree_iterator, _Rb_tree_const_iterator): Remove redundant
            operator!= for C++20.
            * include/debug/map.h (__gnu_debug::map): Define operator<=> for C++20.
            * include/debug/multimap.h (__gnu_debug::multimap): Likewise.
            * include/debug/multiset.h (__gnu_debug::multiset): Likewise.
            * include/debug/set.h (__gnu_debug::set): Likewise.
            * testsuite/23_containers/map/operators/cmp_c++20.cc: New test.
            * testsuite/23_containers/multimap/operators/cmp_c++20.cc: New test.
            * testsuite/23_containers/multiset/operators/cmp_c++20.cc: New test.
            * testsuite/23_containers/set/operators/cmp_c++20.cc: New test.

Diff:
---
 libstdc++-v3/ChangeLog                             |  19 ++++
 libstdc++-v3/include/bits/stl_map.h                |  31 +++++-
 libstdc++-v3/include/bits/stl_multimap.h           |  31 +++++-
 libstdc++-v3/include/bits/stl_multiset.h           |  31 +++++-
 libstdc++-v3/include/bits/stl_set.h                |  30 +++++-
 libstdc++-v3/include/bits/stl_tree.h               |  15 +++
 libstdc++-v3/include/debug/map.h                   |  10 +-
 libstdc++-v3/include/debug/multimap.h              |   8 ++
 libstdc++-v3/include/debug/multiset.h              |  10 +-
 libstdc++-v3/include/debug/set.h                   |  10 +-
 .../23_containers/map/operators/cmp_c++20.cc       | 111 +++++++++++++++++++++
 .../23_containers/multimap/operators/cmp_c++20.cc  | 111 +++++++++++++++++++++
 .../23_containers/multiset/operators/cmp_c++20.cc  | 107 ++++++++++++++++++++
 .../23_containers/set/operators/cmp_c++20.cc       | 107 ++++++++++++++++++++
 14 files changed, 624 insertions(+), 7 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index b30b1d096e8..3d0ddf5f36e 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,22 @@
+2020-04-20  Jonathan Wakely  <jwakely@redhat.com>
+
+	* include/bits/stl_map.h (map): Define operator<=> and remove
+	operator< for C++20.
+	* include/bits/stl_multimap.h (multimap): Likewise.
+	* include/bits/stl_multiset.h (multiset): Likewise.
+	* include/bits/stl_set.h (set): Likewise.
+	* include/bits/stl_tree.h (_Rb_tree): Likewise.
+	(_Rb_tree_iterator, _Rb_tree_const_iterator): Remove redundant
+	operator!= for C++20.
+	* include/debug/map.h (__gnu_debug::map): Define operator<=> for C++20.
+	* include/debug/multimap.h (__gnu_debug::multimap): Likewise.
+	* include/debug/multiset.h (__gnu_debug::multiset): Likewise.
+	* include/debug/set.h (__gnu_debug::set): Likewise.
+	* testsuite/23_containers/map/operators/cmp_c++20.cc: New test.
+	* testsuite/23_containers/multimap/operators/cmp_c++20.cc: New test.
+	* testsuite/23_containers/multiset/operators/cmp_c++20.cc: New test.
+	* testsuite/23_containers/set/operators/cmp_c++20.cc: New test.
+
 2020-04-20  Matthias Kretz  <kretz@kde.org>
 
 	* testsuite/lib/libstdc++.exp: Avoid illegal argument to verbose.
diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h
index fe930c15757..5039efd86b7 100644
--- a/libstdc++-v3/include/bits/stl_map.h
+++ b/libstdc++-v3/include/bits/stl_map.h
@@ -1400,10 +1400,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	operator==(const map<_K1, _T1, _C1, _A1>&,
 		   const map<_K1, _T1, _C1, _A1>&);
 
+#if __cpp_lib_three_way_comparison
+      template<typename _K1, typename _T1, typename _C1, typename _A1>
+	friend __detail::__synth3way_t<pair<const _K1, _T1>>
+	operator<=>(const map<_K1, _T1, _C1, _A1>&,
+		    const map<_K1, _T1, _C1, _A1>&);
+#else
       template<typename _K1, typename _T1, typename _C1, typename _A1>
 	friend bool
 	operator<(const map<_K1, _T1, _C1, _A1>&,
 		  const map<_K1, _T1, _C1, _A1>&);
+#endif
     };
 
 
@@ -1440,7 +1447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     map(initializer_list<pair<_Key, _Tp>>, _Allocator)
     -> map<_Key, _Tp, less<_Key>, _Allocator>;
 
-#endif
+#endif // deduction guides
 
   /**
    *  @brief  Map equality comparison.
@@ -1458,6 +1465,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	       const map<_Key, _Tp, _Compare, _Alloc>& __y)
     { return __x._M_t == __y._M_t; }
 
+#if __cpp_lib_three_way_comparison
+  /**
+   *  @brief  Map ordering relation.
+   *  @param  __x  A `map`.
+   *  @param  __y  A `map` of the same type as `x`.
+   *  @return  A value indicating whether `__x` is less than, equal to,
+   *           greater than, or incomparable with `__y`.
+   *
+   *  This is a total ordering relation.  It is linear in the size of the
+   *  maps.  The elements must be comparable with @c <.
+   *
+   *  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 _Key, typename _Tp, typename _Compare, typename _Alloc>
+    inline __detail::__synth3way_t<pair<const _Key, _Tp>>
+    operator<=>(const map<_Key, _Tp, _Compare, _Alloc>& __x,
+		const map<_Key, _Tp, _Compare, _Alloc>& __y)
+    { return __x._M_t <=> __y._M_t; }
+#else
   /**
    *  @brief  Map ordering relation.
    *  @param  __x  A %map.
@@ -1502,6 +1530,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     operator>=(const map<_Key, _Tp, _Compare, _Alloc>& __x,
 	       const map<_Key, _Tp, _Compare, _Alloc>& __y)
     { return !(__x < __y); }
+#endif // three-way comparison
 
   /// See std::map::swap().
   template<typename _Key, typename _Tp, typename _Compare, typename _Alloc>
diff --git a/libstdc++-v3/include/bits/stl_multimap.h b/libstdc++-v3/include/bits/stl_multimap.h
index d38f530e123..65f4d0117a4 100644
--- a/libstdc++-v3/include/bits/stl_multimap.h
+++ b/libstdc++-v3/include/bits/stl_multimap.h
@@ -1065,10 +1065,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	operator==(const multimap<_K1, _T1, _C1, _A1>&,
 		   const multimap<_K1, _T1, _C1, _A1>&);
 
+#if __cpp_lib_three_way_comparison
+      template<typename _K1, typename _T1, typename _C1, typename _A1>
+	friend __detail::__synth3way_t<pair<const _K1, _T1>>
+	operator<=>(const multimap<_K1, _T1, _C1, _A1>&,
+		    const multimap<_K1, _T1, _C1, _A1>&);
+#else
       template<typename _K1, typename _T1, typename _C1, typename _A1>
 	friend bool
 	operator<(const multimap<_K1, _T1, _C1, _A1>&,
 		  const multimap<_K1, _T1, _C1, _A1>&);
+#endif
   };
 
 #if __cpp_deduction_guides >= 201606
@@ -1104,7 +1111,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     multimap(initializer_list<pair<_Key, _Tp>>, _Allocator)
     -> multimap<_Key, _Tp, less<_Key>, _Allocator>;
 
-#endif
+#endif // deduction guides
 
   /**
    *  @brief  Multimap equality comparison.
@@ -1122,6 +1129,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	       const multimap<_Key, _Tp, _Compare, _Alloc>& __y)
     { return __x._M_t == __y._M_t; }
 
+#if __cpp_lib_three_way_comparison
+  /**
+   *  @brief  Multimap ordering relation.
+   *  @param  __x  A `multimap`.
+   *  @param  __y  A `multimap` of the same type as `x`.
+   *  @return  A value indicating whether `__x` is less than, equal to,
+   *           greater than, or incomparable with `__y`.
+   *
+   *  This is a total ordering relation.  It is linear in the size of the
+   *  maps.  The elements must be comparable with @c <.
+   *
+   *  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 _Key, typename _Tp, typename _Compare, typename _Alloc>
+    inline __detail::__synth3way_t<pair<const _Key, _Tp>>
+    operator<=>(const multimap<_Key, _Tp, _Compare, _Alloc>& __x,
+		const multimap<_Key, _Tp, _Compare, _Alloc>& __y)
+    { return __x._M_t <=> __y._M_t; }
+#else
   /**
    *  @brief  Multimap ordering relation.
    *  @param  __x  A %multimap.
@@ -1166,6 +1194,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     operator>=(const multimap<_Key, _Tp, _Compare, _Alloc>& __x,
 	       const multimap<_Key, _Tp, _Compare, _Alloc>& __y)
     { return !(__x < __y); }
+#endif // three-way comparison
 
   /// See std::multimap::swap().
   template<typename _Key, typename _Tp, typename _Compare, typename _Alloc>
diff --git a/libstdc++-v3/include/bits/stl_multiset.h b/libstdc++-v3/include/bits/stl_multiset.h
index ab62df1e508..bf6ae7de095 100644
--- a/libstdc++-v3/include/bits/stl_multiset.h
+++ b/libstdc++-v3/include/bits/stl_multiset.h
@@ -903,10 +903,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	operator==(const multiset<_K1, _C1, _A1>&,
 		   const multiset<_K1, _C1, _A1>&);
 
+#if __cpp_lib_three_way_comparison
+      template<typename _K1, typename _C1, typename _A1>
+	friend __detail::__synth3way_t<_K1>
+	operator<=>(const multiset<_K1, _C1, _A1>&,
+		    const multiset<_K1, _C1, _A1>&);
+#else
       template<typename _K1, typename _C1, typename _A1>
 	friend bool
 	operator< (const multiset<_K1, _C1, _A1>&,
 		   const multiset<_K1, _C1, _A1>&);
+#endif
     };
 
 #if __cpp_deduction_guides >= 201606
@@ -946,7 +953,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     multiset(initializer_list<_Key>, _Allocator)
     -> multiset<_Key, less<_Key>, _Allocator>;
 
-#endif
+#endif // deduction guides
 
   /**
    *  @brief  Multiset equality comparison.
@@ -965,6 +972,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	       const multiset<_Key, _Compare, _Alloc>& __y)
     { return __x._M_t == __y._M_t; }
 
+#if __cpp_lib_three_way_comparison
+  /**
+   *  @brief  Multiset ordering relation.
+   *  @param  __x  A `multiset`.
+   *  @param  __y  A `multiset` of the same type as `x`.
+   *  @return  A value indicating whether `__x` is less than, equal to,
+   *           greater than, or incomparable with `__y`.
+   *
+   *  This is a total ordering relation.  It is linear in the size of the
+   *  maps.  The elements must be comparable with @c <.
+   *
+   *  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 _Key, typename _Compare, typename _Alloc>
+    inline __detail::__synth3way_t<_Key>
+    operator<=>(const multiset<_Key, _Compare, _Alloc>& __x,
+		const multiset<_Key, _Compare, _Alloc>& __y)
+    { return __x._M_t <=> __y._M_t; }
+#else
   /**
    *  @brief  Multiset ordering relation.
    *  @param  __x  A %multiset.
@@ -1009,6 +1037,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     operator>=(const multiset<_Key, _Compare, _Alloc>& __x,
 	       const multiset<_Key, _Compare, _Alloc>& __y)
     { return !(__x < __y); }
+#endif // three-way comparison
 
   /// See std::multiset::swap().
   template<typename _Key, typename _Compare, typename _Alloc>
diff --git a/libstdc++-v3/include/bits/stl_set.h b/libstdc++-v3/include/bits/stl_set.h
index 4f8d631bb3b..da426650815 100644
--- a/libstdc++-v3/include/bits/stl_set.h
+++ b/libstdc++-v3/include/bits/stl_set.h
@@ -921,9 +921,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	friend bool
 	operator==(const set<_K1, _C1, _A1>&, const set<_K1, _C1, _A1>&);
 
+#if __cpp_lib_three_way_comparison
+      template<typename _K1, typename _C1, typename _A1>
+	friend __detail::__synth3way_t<_K1>
+	operator<=>(const set<_K1, _C1, _A1>&, const set<_K1, _C1, _A1>&);
+#else
       template<typename _K1, typename _C1, typename _A1>
 	friend bool
 	operator<(const set<_K1, _C1, _A1>&, const set<_K1, _C1, _A1>&);
+#endif
     };
 
 #if __cpp_deduction_guides >= 201606
@@ -962,7 +968,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     set(initializer_list<_Key>, _Allocator)
     -> set<_Key, less<_Key>, _Allocator>;
 
-#endif
+#endif // deduction guides
 
   /**
    *  @brief  Set equality comparison.
@@ -980,6 +986,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	       const set<_Key, _Compare, _Alloc>& __y)
     { return __x._M_t == __y._M_t; }
 
+#if __cpp_lib_three_way_comparison
+  /**
+   *  @brief  Set ordering relation.
+   *  @param  __x  A `set`.
+   *  @param  __y  A `set` of the same type as `x`.
+   *  @return  A value indicating whether `__x` is less than, equal to,
+   *           greater than, or incomparable with `__y`.
+   *
+   *  This is a total ordering relation.  It is linear in the size of the
+   *  maps.  The elements must be comparable with @c <.
+   *
+   *  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 _Key, typename _Compare, typename _Alloc>
+    inline __detail::__synth3way_t<_Key>
+    operator<=>(const set<_Key, _Compare, _Alloc>& __x,
+		const set<_Key, _Compare, _Alloc>& __y)
+    { return __x._M_t <=> __y._M_t; }
+#else
   /**
    *  @brief  Set ordering relation.
    *  @param  __x  A %set.
@@ -1024,6 +1051,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     operator>=(const set<_Key, _Compare, _Alloc>& __x,
 	       const set<_Key, _Compare, _Alloc>& __y)
     { return !(__x < __y); }
+#endif // three-way comparison
 
   /// See std::set::swap().
   template<typename _Key, typename _Compare, typename _Alloc>
diff --git a/libstdc++-v3/include/bits/stl_tree.h b/libstdc++-v3/include/bits/stl_tree.h
index 9339011e872..5be15afa257 100644
--- a/libstdc++-v3/include/bits/stl_tree.h
+++ b/libstdc++-v3/include/bits/stl_tree.h
@@ -315,9 +315,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return __x._M_node == __y._M_node; }
 
+#if ! __cpp_lib_three_way_comparison
       friend bool
       operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return __x._M_node != __y._M_node; }
+#endif
 
       _Base_ptr _M_node;
   };
@@ -394,9 +396,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return __x._M_node == __y._M_node; }
 
+#if ! __cpp_lib_three_way_comparison
       friend bool
       operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT
       { return __x._M_node != __y._M_node; }
+#endif
 
       _Base_ptr _M_node;
     };
@@ -1610,6 +1614,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  && std::equal(__x.begin(), __x.end(), __y.begin());
       }
 
+#if __cpp_lib_three_way_comparison
+      friend auto
+      operator<=>(const _Rb_tree& __x, const _Rb_tree& __y)
+      {
+	if constexpr (requires { typename __detail::__synth3way_t<_Val>; })
+	  return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
+							__y.begin(), __y.end(),
+							__detail::__synth3way);
+      }
+#else
       friend bool
       operator<(const _Rb_tree& __x, const _Rb_tree& __y)
       {
@@ -1632,6 +1646,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       friend bool _GLIBCXX_DEPRECATED
       operator>=(const _Rb_tree& __x, const _Rb_tree& __y)
       { return !(__x < __y); }
+#endif
     };
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
diff --git a/libstdc++-v3/include/debug/map.h b/libstdc++-v3/include/debug/map.h
index e96fc31f522..adbabf62915 100644
--- a/libstdc++-v3/include/debug/map.h
+++ b/libstdc++-v3/include/debug/map.h
@@ -731,7 +731,7 @@ namespace __debug
     map(initializer_list<pair<_Key, _Tp>>, _Allocator)
     -> map<_Key, _Tp, less<_Key>, _Allocator>;
 
-#endif
+#endif // deduction guides
 
   template<typename _Key, typename _Tp,
 	   typename _Compare, typename _Allocator>
@@ -740,6 +740,13 @@ namespace __debug
 	       const map<_Key, _Tp, _Compare, _Allocator>& __rhs)
     { return __lhs._M_base() == __rhs._M_base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Key, typename _Tp, typename _Compare, typename _Alloc>
+    inline __detail::__synth3way_t<pair<const _Key, _Tp>>
+    operator<=>(const map<_Key, _Tp, _Compare, _Alloc>& __lhs,
+		const map<_Key, _Tp, _Compare, _Alloc>& __rhs)
+    { return __lhs._M_base() <=> __rhs._M_base(); }
+#else
   template<typename _Key, typename _Tp,
 	   typename _Compare, typename _Allocator>
     inline bool
@@ -774,6 +781,7 @@ namespace __debug
     operator>(const map<_Key, _Tp, _Compare, _Allocator>& __lhs,
 	      const map<_Key, _Tp, _Compare, _Allocator>& __rhs)
     { return __lhs._M_base() > __rhs._M_base(); }
+#endif // three-way comparison
 
   template<typename _Key, typename _Tp,
 	   typename _Compare, typename _Allocator>
diff --git a/libstdc++-v3/include/debug/multimap.h b/libstdc++-v3/include/debug/multimap.h
index 83de49e87e2..6cba52d35dc 100644
--- a/libstdc++-v3/include/debug/multimap.h
+++ b/libstdc++-v3/include/debug/multimap.h
@@ -621,6 +621,13 @@ namespace __debug
 	       const multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
     { return __lhs._M_base() == __rhs._M_base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Key, typename _Tp, typename _Compare, typename _Alloc>
+    inline __detail::__synth3way_t<pair<const _Key, _Tp>>
+    operator<=>(const multimap<_Key, _Tp, _Compare, _Alloc>& __lhs,
+		const multimap<_Key, _Tp, _Compare, _Alloc>& __rhs)
+    { return __lhs._M_base() <=> __rhs._M_base(); }
+#else
   template<typename _Key, typename _Tp,
 	   typename _Compare, typename _Allocator>
     inline bool
@@ -655,6 +662,7 @@ namespace __debug
     operator>(const multimap<_Key, _Tp, _Compare, _Allocator>& __lhs,
 	      const multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
     { return __lhs._M_base() > __rhs._M_base(); }
+#endif // three-way comparison
 
   template<typename _Key, typename _Tp,
 	   typename _Compare, typename _Allocator>
diff --git a/libstdc++-v3/include/debug/multiset.h b/libstdc++-v3/include/debug/multiset.h
index fcbba339478..a2d5e717b34 100644
--- a/libstdc++-v3/include/debug/multiset.h
+++ b/libstdc++-v3/include/debug/multiset.h
@@ -584,7 +584,7 @@ namespace __debug
     multiset(initializer_list<_Key>, _Allocator)
     -> multiset<_Key, less<_Key>, _Allocator>;
 
-#endif
+#endif // deduction guides
 
   template<typename _Key, typename _Compare, typename _Allocator>
     inline bool
@@ -592,6 +592,13 @@ namespace __debug
 	       const multiset<_Key, _Compare, _Allocator>& __rhs)
     { return __lhs._M_base() == __rhs._M_base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Key, typename _Compare, typename _Alloc>
+    inline __detail::__synth3way_t<_Key>
+    operator<=>(const multiset<_Key, _Compare, _Alloc>& __lhs,
+		const multiset<_Key, _Compare, _Alloc>& __rhs)
+    { return __lhs._M_base() <=> __rhs._M_base(); }
+#else
   template<typename _Key, typename _Compare, typename _Allocator>
     inline bool
     operator!=(const multiset<_Key, _Compare, _Allocator>& __lhs,
@@ -621,6 +628,7 @@ namespace __debug
     operator>(const multiset<_Key, _Compare, _Allocator>& __lhs,
 	      const multiset<_Key, _Compare, _Allocator>& __rhs)
     { return __lhs._M_base() > __rhs._M_base(); }
+#endif // three-way comparison
 
   template<typename _Key, typename _Compare, typename _Allocator>
     void
diff --git a/libstdc++-v3/include/debug/set.h b/libstdc++-v3/include/debug/set.h
index 093ff129f3e..210186623df 100644
--- a/libstdc++-v3/include/debug/set.h
+++ b/libstdc++-v3/include/debug/set.h
@@ -595,7 +595,7 @@ namespace __debug
     set(initializer_list<_Key>, _Allocator)
     -> set<_Key, less<_Key>, _Allocator>;
 
-#endif
+#endif // deduction guides
 
   template<typename _Key, typename _Compare, typename _Allocator>
     inline bool
@@ -603,6 +603,13 @@ namespace __debug
 	       const set<_Key, _Compare, _Allocator>& __rhs)
     { return __lhs._M_base() == __rhs._M_base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _Key, typename _Compare, typename _Alloc>
+    inline __detail::__synth3way_t<_Key>
+    operator<=>(const set<_Key, _Compare, _Alloc>& __lhs,
+		const set<_Key, _Compare, _Alloc>& __rhs)
+    { return __lhs._M_base() <=> __rhs._M_base(); }
+#else
   template<typename _Key, typename _Compare, typename _Allocator>
     inline bool
     operator!=(const set<_Key, _Compare, _Allocator>& __lhs,
@@ -632,6 +639,7 @@ namespace __debug
     operator>(const set<_Key, _Compare, _Allocator>& __lhs,
 	      const set<_Key, _Compare, _Allocator>& __rhs)
     { return __lhs._M_base() > __rhs._M_base(); }
+#endif // three-way comparison
 
   template<typename _Key, typename _Compare, typename _Allocator>
     void
diff --git a/libstdc++-v3/testsuite/23_containers/map/operators/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/map/operators/cmp_c++20.cc
new file mode 100644
index 00000000000..a586a6df648
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/map/operators/cmp_c++20.cc
@@ -0,0 +1,111 @@
+// 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 <map>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::map<int, int> c1{ {1,1}, {2,1}, {3,1} };
+  std::map<int, int> c2{ {1,1}, {2,1}, {3,1}, {4,1} };
+  std::map<int, int> c3{ {1,1}, {2,1}, {3,2} };
+  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::map<int, int>> );
+
+  static_assert( std::three_way_comparable<std::map<int, int>,
+					   std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::map<int, float>,
+					     std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::map<int, float>,
+					     std::weak_ordering> );
+  static_assert( std::three_way_comparable<std::map<int, float>,
+					   std::partial_ordering> );
+
+  struct E
+  {
+    bool operator==(E) { return true; }
+  };
+  static_assert( ! std::totally_ordered<std::map<int, E>> );
+  static_assert( ! std::three_way_comparable<E> );
+  static_assert( ! std::three_way_comparable<std::map<int, 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::map<int, W>> );
+
+  using P = std::pair<const W, W>;
+  std::map<W, W> c1{ P{1,1}, P{2,2}, P{3,3} }, c2{ P{1,0}, P{3,2}, P{3,3} };
+  static_assert( std::same_as<decltype(c1 <=> c1), std::weak_ordering> );
+  VERIFY( c1 == c2 );
+  VERIFY( std::is_eq(c1 <=> c2) );
+}
+
+void
+test04()
+{
+  struct L
+  {
+    int value = 0;
+
+    bool operator<(L rhs) const noexcept { return value < rhs.value; }
+  };
+
+  static_assert( std::totally_ordered<std::map<int, L>> );
+
+  using P = std::pair<const L, L>;
+  std::map<L, L> c{ P{1,1}, P{2,2}, P{3,3} }, d{ P{1,1}, P{2,2}, P{3,4} };
+  static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
+  VERIFY( std::is_lt(c <=> d) );
+}
+
+// Associative container iterators are not random access
+static_assert( ! std::totally_ordered<std::map<int, int>::iterator> );
+static_assert( ! std::three_way_comparable<std::map<int, int>::iterator> );
+
+int
+main()
+{
+  test01();
+  test02();
+  test04();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/operators/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/multimap/operators/cmp_c++20.cc
new file mode 100644
index 00000000000..350ed3e6a15
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/multimap/operators/cmp_c++20.cc
@@ -0,0 +1,111 @@
+// 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 <map>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::multimap<int, int> c1{ {1,1}, {2,1}, {3,1} };
+  std::multimap<int, int> c2{ {1,1}, {2,1}, {3,1}, {4,1} };
+  std::multimap<int, int> c3{ {1,1}, {2,1}, {3,2} };
+  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::multimap<int, int>> );
+
+  static_assert( std::three_way_comparable<std::multimap<int, int>,
+					   std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::multimap<int, float>,
+					     std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::multimap<int, float>,
+					     std::weak_ordering> );
+  static_assert( std::three_way_comparable<std::multimap<int, float>,
+					   std::partial_ordering> );
+
+  struct E
+  {
+    bool operator==(E) { return true; }
+  };
+  static_assert( ! std::totally_ordered<std::multimap<int, E>> );
+  static_assert( ! std::three_way_comparable<E> );
+  static_assert( ! std::three_way_comparable<std::multimap<int, 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::multimap<int, W>> );
+
+  using P = std::pair<const W, W>;
+  std::multimap<W, W> c1{ P{1,1}, P{2,2}, P{3,3} }, c2{ P{1,0}, P{3,2}, P{3,3} };
+  static_assert( std::same_as<decltype(c1 <=> c1), std::weak_ordering> );
+  VERIFY( c1 == c2 );
+  VERIFY( std::is_eq(c1 <=> c2) );
+}
+
+void
+test04()
+{
+  struct L
+  {
+    int value = 0;
+
+    bool operator<(L rhs) const noexcept { return value < rhs.value; }
+  };
+
+  static_assert( std::totally_ordered<std::multimap<int, L>> );
+
+  using P = std::pair<const L, L>;
+  std::multimap<L, L> c{ P{1,1}, P{2,2}, P{3,3} }, d{ P{1,1}, P{2,2}, P{3,4} };
+  static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> );
+  VERIFY( std::is_lt(c <=> d) );
+}
+
+// Associative container iterators are not random access
+static_assert( ! std::totally_ordered<std::multimap<int, int>::iterator> );
+static_assert( ! std::three_way_comparable<std::multimap<int, int>::iterator> );
+
+int
+main()
+{
+  test01();
+  test02();
+  test04();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/multiset/operators/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/multiset/operators/cmp_c++20.cc
new file mode 100644
index 00000000000..94cb7991891
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/multiset/operators/cmp_c++20.cc
@@ -0,0 +1,107 @@
+// 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 <set>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::multiset<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::multiset<int>> );
+
+  static_assert( std::three_way_comparable<std::multiset<int>,
+					   std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::multiset<float>,
+					     std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::multiset<float>,
+					     std::weak_ordering> );
+  static_assert( std::three_way_comparable<std::multiset<float>,
+					   std::partial_ordering> );
+
+  struct E
+  {
+    bool operator==(E) { return true; }
+  };
+  static_assert( ! std::totally_ordered<std::multiset<E>> );
+  static_assert( ! std::three_way_comparable<E> );
+  static_assert( ! std::three_way_comparable<std::multiset<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::multiset<W>> );
+
+  std::multiset<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
+test04()
+{
+  struct L
+  {
+    int value = 0;
+
+    bool operator<(L rhs) const noexcept { return value < rhs.value; }
+  };
+
+  static_assert( std::totally_ordered<std::multiset<L>> );
+
+  std::multiset<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) );
+}
+
+// Associative container iterators are not random access
+static_assert( ! std::totally_ordered<std::multiset<int>::iterator> );
+static_assert( ! std::three_way_comparable<std::multiset<int>::iterator> );
+
+int
+main()
+{
+  test01();
+  test02();
+  test04();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/set/operators/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/set/operators/cmp_c++20.cc
new file mode 100644
index 00000000000..fbc95c4c6f0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/set/operators/cmp_c++20.cc
@@ -0,0 +1,107 @@
+// 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 <set>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::set<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::set<int>> );
+
+  static_assert( std::three_way_comparable<std::set<int>,
+					   std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::set<float>,
+					     std::strong_ordering> );
+  static_assert( ! std::three_way_comparable<std::set<float>,
+					     std::weak_ordering> );
+  static_assert( std::three_way_comparable<std::set<float>,
+					   std::partial_ordering> );
+
+  struct E
+  {
+    bool operator==(E) { return true; }
+  };
+  static_assert( ! std::totally_ordered<std::set<E>> );
+  static_assert( ! std::three_way_comparable<E> );
+  static_assert( ! std::three_way_comparable<std::set<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::set<W>> );
+
+  std::set<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
+test04()
+{
+  struct L
+  {
+    int value = 0;
+
+    bool operator<(L rhs) const noexcept { return value < rhs.value; }
+  };
+
+  static_assert( std::totally_ordered<std::set<L>> );
+
+  std::set<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) );
+}
+
+// Associative container iterators are not random access
+static_assert( ! std::totally_ordered<std::set<int>::iterator> );
+static_assert( ! std::three_way_comparable<std::set<int>::iterator> );
+
+int
+main()
+{
+  test01();
+  test02();
+  test04();
+}


More information about the Libstdc++-cvs mailing list