[libc++][spaceship] Implement `operator<=>` for `array`
authorHristo Hristov <zingam@outlook.com>
Sat, 6 May 2023 12:41:41 +0000 (15:41 +0300)
committerHristo Hristov <zingam@outlook.com>
Mon, 8 May 2023 14:03:06 +0000 (17:03 +0300)
Implements part of P1614R2 "The Mothership has Landed"

Reviewed By: Mordante, #libc, philnik

Differential Revision: https://reviews.llvm.org/D132265

libcxx/docs/Status/Cxx20Issues.csv
libcxx/docs/Status/SpaceshipProjects.csv
libcxx/include/array
libcxx/test/std/containers/sequences/array/compare.fail.cpp [deleted file]
libcxx/test/std/containers/sequences/array/compare.pass.cpp
libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp [new file with mode: 0644]
libcxx/test/std/containers/sequences/array/compare.three_way.verify.cpp [new file with mode: 0644]
libcxx/test/std/containers/sequences/array/compare.verify.cpp [new file with mode: 0644]
libcxx/test/support/test_container_comparisons.h

index c0143931be018e16bdc4c2d4349b4926f05f1e35..d9f87112a5e65edcb4273e82a4e20ecfd609d8a5 100644 (file)
 "`3338 <https://wg21.link/LWG3338>`__","Rename ``default_constructible``\  to ``default_initializable``\ ","Prague","|Complete|","13.0"
 "`3340 <https://wg21.link/LWG3340>`__","Formatting functions should throw on argument/format string mismatch in |sect|\ [format.functions]","Prague","|Complete|","14.0","|format|"
 "`3346 <https://wg21.link/LWG3346>`__","``pair``\  and ``tuple``\  copy and move constructor have backwards specification","Prague","",""
-"`3347 <https://wg21.link/LWG3347>`__","``std::pair<T, U>``\  now requires ``T``\  and ``U``\  to be less-than-comparable","Prague","",""
+"`3347 <https://wg21.link/LWG3347>`__","``std::pair<T, U>``\  now requires ``T``\  and ``U``\  to be less-than-comparable","Prague","|Complete|","17.0"
 "`3348 <https://wg21.link/LWG3348>`__","``__cpp_lib_unwrap_ref``\  in wrong header","Prague","|Complete|","12.0"
 "`3349 <https://wg21.link/LWG3349>`__","Missing ``__cpp_lib_constexpr_complex``\  for P0415R1","Prague","|Complete|","16.0"
 "`3350 <https://wg21.link/LWG3350>`__","Simplify return type of ``lexicographical_compare_three_way``\ ","Prague","|Complete|","17.0","|spaceship|"
index 3eecc354b8113126e15e5d9e5f161e02de9a6feb..6dd14bdd09dbfa70b71197641d54e9e69e0b3ee3 100644 (file)
@@ -35,7 +35,8 @@ Section,Description,Dependencies,Assignee,Complete
 | `[stacktrace.basic.cmp] <https://wg21.link/stacktrace.basic.cmp>`_,| `basic_stacktrace <https://reviews.llvm.org/D123228>`_,[alg.three.way],Nikolas Klauser,|In Progress|
 | `[string.cmp] <https://wg21.link/string.cmp>`_,| `basic_string <https://reviews.llvm.org/D131421>`_,None,Mark de Wever,|Complete|
 | `[string.view.comparison] <https://wg21.link/string.view.comparison>`_,| `basic_string_view <https://reviews.llvm.org/D130295>`_,None,Mark de Wever,|Complete|
-| `[array.syn] <https://wg21.link/array.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `array <https://reviews.llvm.org/D132265>`_,[expos.only.func],Adrian Vogelsgesang,|In Progress|
+| `[array.syn] <https://wg21.link/array.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `array <https://reviews.llvm.org/D132265>`_,[expos.only.func],"| Adrian Vogelsgesang
+| Hristo Hristov",|Complete|
 | `[deque.syn] <https://wg21.link/deque.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `deque <https://reviews.llvm.org/D144821>`_,[expos.only.func],Hristo Hristov,|Complete|
 | `[forward.list.syn] <https://wg21.link/forward.list.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `forward_list <https://reviews.llvm.org/D145172>`_,[expos.only.func],Hristo Hristov,|Complete|
 | `[list.syn] <https://wg21.link/list.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `list <https://reviews.llvm.org/D132312>`_,[expos.only.func],Adrian Vogelsgesang,|Complete|
index 58e0fb273f01e26d063f4b21dbcf6dc12ccbe845..5a8a1acca47550c0f944999c7c9afe359850a0d2 100644 (file)
@@ -77,15 +77,18 @@ template <class T, class... U>
 template <class T, size_t N>
   bool operator==(const array<T,N>& x, const array<T,N>& y);    // constexpr in C++20
 template <class T, size_t N>
-  bool operator!=(const array<T,N>& x, const array<T,N>& y);    // constexpr in C++20
+  bool operator!=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
 template <class T, size_t N>
-  bool operator<(const array<T,N>& x, const array<T,N>& y);     // constexpr in C++20
+  bool operator<(const array<T,N>& x, const array<T,N>& y);     // removed in C++20
 template <class T, size_t N>
-  bool operator>(const array<T,N>& x, const array<T,N>& y);     // constexpr in C++20
+  bool operator>(const array<T,N>& x, const array<T,N>& y);     // removed in C++20
 template <class T, size_t N>
-  bool operator<=(const array<T,N>& x, const array<T,N>& y);    // constexpr in C++20
+  bool operator<=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
 template <class T, size_t N>
-  bool operator>=(const array<T,N>& x, const array<T,N>& y);    // constexpr in C++20
+  bool operator>=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
+template<class T, size_t N>
+  constexpr synth-three-way-result<T>
+    operator<=>(const array<T, N>& x, const array<T, N>& y);    // since C++20
 
 template <class T, size_t N >
   void swap(array<T,N>& x, array<T,N>& y) noexcept(noexcept(x.swap(y))); // constexpr in C++20
@@ -111,6 +114,7 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce
 #include <__algorithm/equal.h>
 #include <__algorithm/fill_n.h>
 #include <__algorithm/lexicographical_compare.h>
+#include <__algorithm/lexicographical_compare_three_way.h>
 #include <__algorithm/swap_ranges.h>
 #include <__assert> // all public C++ headers provide the assertion handler
 #include <__config>
@@ -401,47 +405,44 @@ operator==(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y)
     return _VSTD::equal(__x.begin(), __x.end(), __y.begin());
 }
 
+#if _LIBCPP_STD_VER <= 17
+
 template <class _Tp, size_t _Size>
-inline _LIBCPP_INLINE_VISIBILITY
-_LIBCPP_CONSTEXPR_SINCE_CXX20 bool
-operator!=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y)
-{
+inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
     return !(__x == __y);
 }
 
 template <class _Tp, size_t _Size>
-inline _LIBCPP_INLINE_VISIBILITY
-_LIBCPP_CONSTEXPR_SINCE_CXX20 bool
-operator<(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y)
-{
-    return _VSTD::lexicographical_compare(__x.begin(), __x.end(),
-                                          __y.begin(), __y.end());
+inline _LIBCPP_HIDE_FROM_ABI bool operator<(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
+    return _VSTD::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end());
 }
 
 template <class _Tp, size_t _Size>
-inline _LIBCPP_INLINE_VISIBILITY
-_LIBCPP_CONSTEXPR_SINCE_CXX20 bool
-operator>(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y)
-{
+inline _LIBCPP_HIDE_FROM_ABI bool operator>(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
     return __y < __x;
 }
 
 template <class _Tp, size_t _Size>
-inline _LIBCPP_INLINE_VISIBILITY
-_LIBCPP_CONSTEXPR_SINCE_CXX20 bool
-operator<=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y)
-{
+inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
     return !(__y < __x);
 }
 
 template <class _Tp, size_t _Size>
-inline _LIBCPP_INLINE_VISIBILITY
-_LIBCPP_CONSTEXPR_SINCE_CXX20 bool
-operator>=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y)
-{
+inline _LIBCPP_HIDE_FROM_ABI bool operator>=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
     return !(__x < __y);
 }
 
+#else // _LIBCPP_STD_VER <= 17
+
+template <class _Tp, size_t _Size>
+_LIBCPP_HIDE_FROM_ABI constexpr __synth_three_way_result<_Tp>
+operator<=>(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) {
+    return std::lexicographical_compare_three_way(
+        __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way<_Tp, _Tp>);
+}
+
+#endif // _LIBCPP_STD_VER <= 17
+
 template <class _Tp, size_t _Size>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 __enable_if_t<_Size == 0 || __is_swappable<_Tp>::value, void>
diff --git a/libcxx/test/std/containers/sequences/array/compare.fail.cpp b/libcxx/test/std/containers/sequences/array/compare.fail.cpp
deleted file mode 100644 (file)
index 1fe4c70..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <array>
-
-// bool operator==(array<T, N> const&, array<T, N> const&);
-// bool operator!=(array<T, N> const&, array<T, N> const&);
-// bool operator<(array<T, N> const&, array<T, N> const&);
-// bool operator<=(array<T, N> const&, array<T, N> const&);
-// bool operator>(array<T, N> const&, array<T, N> const&);
-// bool operator>=(array<T, N> const&, array<T, N> const&);
-
-
-#include <array>
-#include <vector>
-#include <cassert>
-
-#include "test_macros.h"
-
-template <class Array>
-void test_compare(const Array& LHS, const Array& RHS) {
-  typedef std::vector<typename Array::value_type> Vector;
-  const Vector LHSV(LHS.begin(), LHS.end());
-  const Vector RHSV(RHS.begin(), RHS.end());
-  assert((LHS == RHS) == (LHSV == RHSV));
-  assert((LHS != RHS) == (LHSV != RHSV));
-  assert((LHS < RHS) == (LHSV < RHSV));
-  assert((LHS <= RHS) == (LHSV <= RHSV));
-  assert((LHS > RHS) == (LHSV > RHSV));
-  assert((LHS >= RHS) == (LHSV >= RHSV));
-}
-
-template <int Dummy> struct NoCompare {};
-
-int main(int, char**)
-{
-  {
-    typedef NoCompare<0> T;
-    typedef std::array<T, 3> C;
-    C c1 = {{}};
-    // expected-error@*:* 2 {{invalid operands to binary expression}}
-    TEST_IGNORE_NODISCARD (c1 == c1);
-    TEST_IGNORE_NODISCARD (c1 < c1);
-  }
-  {
-    typedef NoCompare<1> T;
-    typedef std::array<T, 3> C;
-    C c1 = {{}};
-    // expected-error@*:* 2 {{invalid operands to binary expression}}
-    TEST_IGNORE_NODISCARD (c1 != c1);
-    TEST_IGNORE_NODISCARD (c1 > c1);
-  }
-  {
-    typedef NoCompare<2> T;
-    typedef std::array<T, 0> C;
-    C c1 = {{}};
-    // expected-error@*:* 2 {{invalid operands to binary expression}}
-    TEST_IGNORE_NODISCARD (c1 == c1);
-    TEST_IGNORE_NODISCARD (c1 < c1);
-  }
-
-  return 0;
-}
index 972600992980f02b8ecb20aec7a4fd1fad6034b9..f79a638c5688d669bfee3a028a54e17a5b30963b 100644 (file)
@@ -8,13 +8,18 @@
 
 // <array>
 
-// bool operator==(array<T, N> const&, array<T, N> const&);   // constexpr in C++20
-// bool operator!=(array<T, N> const&, array<T, N> const&);   // constexpr in C++20
-// bool operator<(array<T, N> const&, array<T, N> const&);    // constexpr in C++20
-// bool operator<=(array<T, N> const&, array<T, N> const&);   // constexpr in C++20
-// bool operator>(array<T, N> const&, array<T, N> const&);    // constexpr in C++20
-// bool operator>=(array<T, N> const&, array<T, N> const&);   // constexpr in C++20
-
+// template <class T, size_t N>
+//   bool operator==(const array<T,N>& x, const array<T,N>& y);    // constexpr in C++20
+// template <class T, size_t N>
+//   bool operator!=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
+// template <class T, size_t N>
+//   bool operator<(const array<T,N>& x, const array<T,N>& y);     // removed in C++20
+// template <class T, size_t N>
+//   bool operator>(const array<T,N>& x, const array<T,N>& y);     // removed in C++20
+// template <class T, size_t N>
+//   bool operator<=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
+// template <class T, size_t N>
+//   bool operator>=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
 
 #include <array>
 #include <cassert>
 #include "test_macros.h"
 #include "test_comparisons.h"
 
-TEST_CONSTEXPR_CXX20 bool tests()
-{
-    {
-        typedef std::array<int, 3> C;
-        const C c1 = {1, 2, 3};
-        const C c2 = {1, 2, 3};
-        const C c3 = {3, 2, 1};
-        const C c4 = {1, 2, 1};
-        assert(testComparisons(c1, c2, true, false));
-        assert(testComparisons(c1, c3, false, true));
-        assert(testComparisons(c1, c4, false, false));
-    }
-    {
-        typedef std::array<int, 0> C;
-        const C c1 = {};
-        const C c2 = {};
-        assert(testComparisons(c1, c2, true, false));
-    }
-    {
-        typedef std::array<LessAndEqComp, 3> C;
-        const C c1 = {LessAndEqComp(1), LessAndEqComp(2), LessAndEqComp(3)};
-        const C c2 = {LessAndEqComp(1), LessAndEqComp(2), LessAndEqComp(3)};
-        const C c3 = {LessAndEqComp(3), LessAndEqComp(2), LessAndEqComp(1)};
-        const C c4 = {LessAndEqComp(1), LessAndEqComp(2), LessAndEqComp(1)};
-        assert(testComparisons(c1, c2, true, false));
-        assert(testComparisons(c1, c3, false, true));
-        assert(testComparisons(c1, c4, false, false));
-    }
-    {
-        typedef std::array<LessAndEqComp, 0> C;
-        const C c1 = {};
-        const C c2 = {};
-        assert(testComparisons(c1, c2, true, false));
-    }
+TEST_CONSTEXPR_CXX20 bool tests() {
+  // Arrays where the elements support all comparison operators
+  AssertComparisonsReturnBool<std::array<int, 3> >();
+  {
+    typedef std::array<int, 3> C;
+    const C c1 = {1, 2, 3};
+    const C c2 = {1, 2, 3};
+    const C c3 = {3, 2, 1};
+    const C c4 = {1, 2, 1};
+    assert(testComparisons(c1, c2, true, false));
+    assert(testComparisons(c1, c3, false, true));
+    assert(testComparisons(c1, c4, false, false));
+  }
+  // Empty array
+  {
+    typedef std::array<int, 0> C;
+    const C c1 = {};
+    const C c2 = {};
+    assert(testComparisons(c1, c2, true, false));
+  }
+  // Arrays where the elements support only less and equality comparisons
+  AssertComparisonsReturnBool<std::array<LessAndEqComp, 3> >();
+  {
+    typedef std::array<LessAndEqComp, 3> C;
+    const C c1 = {LessAndEqComp(1), LessAndEqComp(2), LessAndEqComp(3)};
+    const C c2 = {LessAndEqComp(1), LessAndEqComp(2), LessAndEqComp(3)};
+    const C c3 = {LessAndEqComp(3), LessAndEqComp(2), LessAndEqComp(1)};
+    const C c4 = {LessAndEqComp(1), LessAndEqComp(2), LessAndEqComp(1)};
+    assert(testComparisons(c1, c2, true, false));
+    assert(testComparisons(c1, c3, false, true));
+    assert(testComparisons(c1, c4, false, false));
+  }
+  // Empty array where the elements support only less and equality comparisons
+  {
+    typedef std::array<LessAndEqComp, 0> C;
+    const C c1 = {};
+    const C c2 = {};
+    assert(testComparisons(c1, c2, true, false));
+  }
 
-    return true;
+  return true;
 }
 
-int main(int, char**)
-{
-    tests();
+int main(int, char**) {
+  tests();
 #if TEST_STD_VER >= 20
-    static_assert(tests(), "");
+  static_assert(tests());
 #endif
-    return 0;
+  return 0;
 }
diff --git a/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp b/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp
new file mode 100644 (file)
index 0000000..01be1db
--- /dev/null
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <array>
+
+// template<class T, size_t N>
+//   constexpr synth-three-way-result<T>
+//     operator<=>(const array<T, N>& x, const array<T, N>& y);
+
+#include <array>
+#include <cassert>
+
+#include "test_comparisons.h"
+
+// SFINAE
+
+constexpr std::size_t N{1};
+
+// The container should fulfill `std::three_way_comparable`
+static_assert(std::three_way_comparable<std::array<int, N>>);
+
+// Thanks to SFINAE, the following is not a compiler error but returns `false`
+struct NonComparable {};
+static_assert(!std::three_way_comparable<std::array<NonComparable, N>>);
+
+// Implementation detail of `test_sequence_container_array_spaceship`
+template <typename Elem, typename Order>
+constexpr void test_sequence_container_array_spaceship_with_type() {
+  // Empty containers
+  {
+    std::array<Elem, 0> l1 = {};
+    std::array<Elem, 0> l2 = {};
+    assert(testOrder(l1, l2, Order::equivalent));
+  }
+  // Identical contents
+  {
+    std::array l1{Elem{1}, Elem{1}};
+    std::array l2{Elem{1}, Elem{1}};
+    assert(testOrder(l1, l2, Order::equivalent));
+  }
+  // Less, due to contained values
+  {
+    std::array l1{Elem{1}, Elem{1}};
+    std::array l2{Elem{1}, Elem{2}};
+    assert(testOrder(l1, l2, Order::less));
+  }
+  // Greater, due to contained values
+  {
+    std::array l1{Elem{1}, Elem{3}};
+    std::array l2{Elem{1}, Elem{2}};
+    assert(testOrder(l1, l2, Order::greater));
+  }
+  // Shorter list - unsupported - containers must be of equal lengths
+  // Longer list - unsupported - containers must be of equal lengths
+  // Unordered
+  if constexpr (std::is_same_v<Elem, PartialOrder>) {
+    std::array l1{Elem{1}, Elem{std::numeric_limits<int>::min()}};
+    std::array l2{Elem{1}, Elem{2}};
+    assert(testOrder(l1, l2, Order::unordered));
+  }
+}
+
+// Tests the `operator<=>` on sequence containers `array`
+constexpr bool test_sequence_container_array_spaceship() {
+  // Test different comparison categories
+  test_sequence_container_array_spaceship_with_type<int, std::strong_ordering>();
+  test_sequence_container_array_spaceship_with_type<StrongOrder, std::strong_ordering>();
+  test_sequence_container_array_spaceship_with_type<WeakOrder, std::weak_ordering>();
+  test_sequence_container_array_spaceship_with_type<PartialOrder, std::partial_ordering>();
+
+  // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
+  test_sequence_container_array_spaceship_with_type<LessAndEqComp, std::weak_ordering>();
+
+  return true;
+}
+
+int main(int, char**) {
+  assert(test_sequence_container_array_spaceship());
+  static_assert(test_sequence_container_array_spaceship());
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/array/compare.three_way.verify.cpp b/libcxx/test/std/containers/sequences/array/compare.three_way.verify.cpp
new file mode 100644 (file)
index 0000000..b7267ec
--- /dev/null
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <array>
+
+// template<class T, size_t N>
+//   constexpr synth-three-way-result<T>
+//     operator<=>(const array<T, N>& x, const array<T, N>& y);
+
+// arrays with different sizes should not compare
+
+#include <array>
+
+int main(int, char**) {
+  {
+    std::array a1{1};
+    std::array a2{1, 2};
+
+    // expected-error@*:* {{invalid operands to binary expression}}
+    a1 <=> a2;
+  }
+  {
+    std::array a1{1, 2};
+    std::array a2{1};
+
+    // expected-error@*:* {{invalid operands to binary expression}}
+    a1 <=> a2;
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/array/compare.verify.cpp b/libcxx/test/std/containers/sequences/array/compare.verify.cpp
new file mode 100644 (file)
index 0000000..4b00160
--- /dev/null
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <array>
+
+// template <class T, size_t N>
+//   bool operator==(const array<T,N>& x, const array<T,N>& y);    // constexpr in C++20
+// template <class T, size_t N>
+//   bool operator!=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
+// template <class T, size_t N>
+//   bool operator<(const array<T,N>& x, const array<T,N>& y);     // removed in C++20
+// template <class T, size_t N>
+//   bool operator>(const array<T,N>& x, const array<T,N>& y);     // removed in C++20
+// template <class T, size_t N>
+//   bool operator<=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
+// template <class T, size_t N>
+//   bool operator>=(const array<T,N>& x, const array<T,N>& y);    // removed in C++20
+
+#include <array>
+
+#include "test_macros.h"
+
+template <int>
+struct NoCompare {};
+
+int main(int, char**) {
+  {
+    typedef NoCompare<0> T;
+    typedef std::array<T, 3> C;
+    C c1 = {{}};
+    // expected-error@*:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD(c1 == c1);
+    TEST_IGNORE_NODISCARD(c1 < c1);
+  }
+  {
+    typedef NoCompare<1> T;
+    typedef std::array<T, 3> C;
+    C c1 = {{}};
+    // expected-error@*:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD(c1 != c1);
+    TEST_IGNORE_NODISCARD(c1 > c1);
+  }
+  {
+    typedef NoCompare<2> T;
+    typedef std::array<T, 0> C;
+    C c1 = {{}};
+    // expected-error@*:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD(c1 == c1);
+    TEST_IGNORE_NODISCARD(c1 < c1);
+  }
+
+  return 0;
+}
index 561275c8bb7909686098509bf44e9c0f9fa991db..f9dae9d6455adb781b916c47c3ad85b4c4733dd2 100644 (file)
@@ -62,7 +62,7 @@ constexpr void test_sequence_container_spaceship_with_type() {
 // Tests the `operator<=>` on sequence containers
 template <template <typename...> typename Container>
 constexpr bool test_sequence_container_spaceship() {
-  // The container should fulfil `std::three_way_comparable`
+  // The container should fulfill `std::three_way_comparable`
   static_assert(std::three_way_comparable<Container<int>>);
 
   // Test different comparison categories
@@ -71,7 +71,7 @@ constexpr bool test_sequence_container_spaceship() {
   test_sequence_container_spaceship_with_type<Container, WeakOrder, std::weak_ordering>();
   test_sequence_container_spaceship_with_type<Container, PartialOrder, std::partial_ordering>();
 
-  // `LessAndEqComp` does not have `operator<=>`. ordering is sythesized based on `operator<`
+  // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
   test_sequence_container_spaceship_with_type<Container, LessAndEqComp, std::weak_ordering>();
 
   // Thanks to SFINAE, the following is not a compiler error but returns `false`
@@ -186,7 +186,7 @@ constexpr void test_ordered_map_container_spaceship_with_type() {
 // Tests the `operator<=>` on ordered containers
 template <template <typename...> typename Container>
 constexpr bool test_ordered_map_container_spaceship() {
-  // The container should fulfil `std::three_way_comparable`
+  // The container should fulfill `std::three_way_comparable`
   static_assert(std::three_way_comparable<Container<int, int>>);
 
   // Test different comparison categories
@@ -195,7 +195,7 @@ constexpr bool test_ordered_map_container_spaceship() {
   test_ordered_map_container_spaceship_with_type<Container, int, WeakOrder, std::weak_ordering>();
   test_ordered_map_container_spaceship_with_type<Container, int, PartialOrder, std::partial_ordering>();
 
-  // `LessAndEqComp` does not have `operator<=>`. ordering is sythesized based on `operator<`
+  // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
   test_ordered_map_container_spaceship_with_type<Container, int, LessAndEqComp, std::weak_ordering>();
 
   // Thanks to SFINAE, the following is not a compiler error but returns `false`