[libcxx-commits] [libcxx] 254986d - [libc++][spaceship] Implement `operator<=>` for `array`

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Mon May 8 07:03:12 PDT 2023


Author: Hristo Hristov
Date: 2023-05-08T17:03:06+03:00
New Revision: 254986d2df8d8407b46329e452c16748d29ed4cd

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

LOG: [libc++][spaceship] Implement `operator<=>` for `array`

Implements part of P1614R2 "The Mothership has Landed"

Reviewed By: Mordante, #libc, philnik

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

Added: 
    libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp
    libcxx/test/std/containers/sequences/array/compare.three_way.verify.cpp
    libcxx/test/std/containers/sequences/array/compare.verify.cpp

Modified: 
    libcxx/docs/Status/Cxx20Issues.csv
    libcxx/docs/Status/SpaceshipProjects.csv
    libcxx/include/array
    libcxx/test/std/containers/sequences/array/compare.pass.cpp
    libcxx/test/support/test_container_comparisons.h

Removed: 
    libcxx/test/std/containers/sequences/array/compare.fail.cpp


################################################################################
diff  --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv
index c0143931be018..d9f87112a5e65 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -259,7 +259,7 @@
 "`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|"

diff  --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index 3eecc354b8113..6dd14bdd09dbf 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -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|

diff  --git a/libcxx/include/array b/libcxx/include/array
index 58e0fb273f01e..5a8a1acca4755 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -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
index 1fe4c706b62c2..0000000000000
--- a/libcxx/test/std/containers/sequences/array/compare.fail.cpp
+++ /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;
-}

diff  --git a/libcxx/test/std/containers/sequences/array/compare.pass.cpp b/libcxx/test/std/containers/sequences/array/compare.pass.cpp
index 972600992980f..f79a638c5688d 100644
--- a/libcxx/test/std/containers/sequences/array/compare.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/compare.pass.cpp
@@ -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>
@@ -22,49 +27,53 @@
 #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
index 0000000000000..01be1db73041b
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/array/compare.three_way.pass.cpp
@@ -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 
diff erent 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
index 0000000000000..b7267ec9b932b
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/array/compare.three_way.verify.cpp
@@ -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 
diff erent 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
index 0000000000000..4b001601a4fe2
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/array/compare.verify.cpp
@@ -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;
+}

diff  --git a/libcxx/test/support/test_container_comparisons.h b/libcxx/test/support/test_container_comparisons.h
index 561275c8bb790..f9dae9d6455ad 100644
--- a/libcxx/test/support/test_container_comparisons.h
+++ b/libcxx/test/support/test_container_comparisons.h
@@ -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 
diff erent 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 
diff erent 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`


        


More information about the libcxx-commits mailing list