mclow.lists updated this revision to Diff 136582.
mclow.lists added a comment.

Add the `tuple` bits. Regularize the equality comparisons of the containers; 
i.e, don't try to be clever - let the compiler be clever.


https://reviews.llvm.org/D43773

Files:
  include/array
  include/deque
  include/forward_list
  include/list
  include/tuple
  include/vector
  test/std/containers/sequences/array/compare.fail.cpp
  test/std/containers/sequences/array/compare.pass.cpp
  test/std/containers/sequences/deque/compare.fail.cpp
  test/std/containers/sequences/deque/compare.pass.cpp
  test/std/containers/sequences/forwardlist/compare.fail.cpp
  test/std/containers/sequences/forwardlist/compare.pass.cpp
  test/std/containers/sequences/list/compare.fail.cpp
  test/std/containers/sequences/list/compare.pass.cpp
  test/std/containers/sequences/vector/compare.fail.cpp
  test/std/containers/sequences/vector/compare.pass.cpp
  test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
  test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp

Index: test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
===================================================================
--- test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
+++ test/std/utilities/tuple/tuple.tuple/tuple.rel/lt.pass.cpp
@@ -35,6 +35,16 @@
 
 #include "test_macros.h"
 
+
+template <bool isLess, bool isEqual, typename T1, typename T2>
+void compare (const T1 &t1, const T2 &t2)
+{
+    assert((t1  < t2) == ( isLess));
+    assert((t1  > t2) == (!isLess && !isEqual));
+    assert((t1 <= t2) == ( isLess ||  isEqual));
+    assert((t1 >= t2) == (!isLess ||  isEqual));
+}
+
 int main()
 {
     {
@@ -208,5 +218,57 @@
         static_assert(!(t1 >  t2), "");
         static_assert(!(t1 >= t2), "");
     }
+    { // P0805
+        typedef std::tuple<> T0;
+        typedef std::tuple<long, int, double> T1;
+        typedef std::tuple<double, long> T2;
+        constexpr T0 t0;
+        constexpr T1 t1(1, 2, 3);
+        constexpr T2 t2(1, 2);
+        constexpr T1 t3(0, 1, 2); // common tail
+
+        // less, equal
+        compare<false, true >(t0, t0);
+        static_assert(!(t0  < t0), "");
+        static_assert(!(t0  > t0), "");
+        static_assert( (t0 <= t0), "");
+        static_assert( (t0 >= t0), "");
+
+        compare<true,  false>(t0, t1);
+        static_assert( (t0  < t1), "");
+        static_assert(!(t0  > t1), "");
+        static_assert( (t0 <= t1), "");
+        static_assert(!(t0 >= t1), "");
+
+        compare<false, false>(t1, t0);
+        static_assert(!(t1  < t0), "");
+        static_assert( (t1  > t0), "");
+        static_assert(!(t1 <= t0), "");
+        static_assert( (t1 >= t0), "");
+
+        compare<false, false>(t1, t2);
+        static_assert(!(t1  < t2), "");
+        static_assert( (t1  > t2), "");
+        static_assert(!(t1 <= t2), "");
+        static_assert( (t1 >= t2), "");
+
+        compare<true, false>(t2, t1);
+        static_assert( (t2  < t1), "");
+        static_assert(!(t2  > t1), "");
+        static_assert( (t2 <= t1), "");
+        static_assert(!(t2 >= t1), "");
+
+        compare<false, false>(t2, t3);
+        static_assert(!(t2  < t3), "");
+        static_assert( (t2  > t3), "");
+        static_assert(!(t2 <= t3), "");
+        static_assert( (t2 >= t3), "");
+
+        compare<true, false>(t3, t2);
+        static_assert( (t3  < t2), "");
+        static_assert(!(t3  > t2), "");
+        static_assert( (t3 <= t2), "");
+        static_assert(!(t3 >= t2), "");
+        }
 #endif
 }
Index: test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
===================================================================
--- test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
+++ test/std/utilities/tuple/tuple.tuple/tuple.rel/eq.pass.cpp
@@ -154,5 +154,20 @@
         static_assert(!(t1 == t2), "");
         static_assert(t1 != t2, "");
     }
+    { // P0805
+        typedef std::tuple<long, int, double> T1;
+        typedef std::tuple<double, long> T2;
+        constexpr T1 t1(1, 2, 3);
+        constexpr T2 t2(1.1, 3);
+        constexpr T2 t3(1, 2);
+        static_assert(!(t1 == t2), "");
+        static_assert(!(t2 == t1), "");
+        static_assert(!(t1 == t3), "");
+        static_assert(!(t3 == t1), "");
+        static_assert(  t1 != t2,  "");
+        static_assert(  t2 != t1,  "");
+        static_assert(  t1 != t3,  "");
+        static_assert(  t3 != t1,  "");
+    }
 #endif
 }
Index: test/std/containers/sequences/vector/compare.pass.cpp
===================================================================
--- test/std/containers/sequences/vector/compare.pass.cpp
+++ test/std/containers/sequences/vector/compare.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <vector>
+
+// template <class T, class Allocator> bool operator==(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator< (const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator!=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator> (const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator>=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator<=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// 
+// C++20
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator==(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator< (const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator!=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator> (const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator>=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator<=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+
+
+#include <vector>
+#include <cassert>
+
+#include "min_allocator.h"
+#include "test_macros.h"
+
+template <class Vector>
+void test_compare(const Vector& LHS, const Vector& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
+template <class Vector1, class Vector2>
+void test_compare(const Vector1& LHS, const Vector2& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
+int main()
+{
+  {
+    typedef int T;
+    typedef std::vector<T> C;
+    C c0 = {};
+    C c1 = {1, 2, 3};
+    C c2 = {1, 2, 3};
+    C c3 = {3, 2, 1};
+    C c4 = {1, 2, 1};
+    test_compare(c0, c1, true, false);
+    test_compare(c1, c2, false, true);
+    test_compare(c1, c3, true, false);
+    test_compare(c1, c4, false, false);
+  }
+
+#if TEST_STD_VER > 17
+  {
+    std::vector<int>   c0 = {};
+    std::vector<int>   c1 = {4};
+    std::vector<long>  c2 = {4L};
+    std::vector<short> c3 = {2};
+    std::vector<short, min_allocator<short>> c4 = {4};
+    test_compare(c0, c1, true, false);  // same type, different lengths
+    test_compare(c0, c2, true, false);  // different type, different lengths
+    test_compare(c1, c2, false, true);  // different types, same length, same values
+    test_compare(c1, c3, false, false); // different types, same length, different values
+    test_compare(c1, c4, false, true);  // different types, same length, same value, different allocator
+  }
+#endif
+}
Index: test/std/containers/sequences/vector/compare.fail.cpp
===================================================================
--- test/std/containers/sequences/vector/compare.fail.cpp
+++ test/std/containers/sequences/vector/compare.fail.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <vector>
+
+// template <class T, class Allocator> bool operator==(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator< (const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator!=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator> (const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator>=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// template <class T, class Allocator> bool operator<=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
+// 
+// C++20
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator==(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator< (const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator!=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator> (const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator>=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator<=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+
+
+#include <vector>
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <int Dummy> struct NoCompare {};
+
+int main()
+{
+  {
+    typedef NoCompare<0> T;
+    typedef std::vector<T> C;
+    C c1 = {};
+    // expected-error@algorithm:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c1);
+    TEST_IGNORE_NODISCARD (c1 < c1);
+  }
+  {
+    typedef NoCompare<1> T;
+    typedef std::vector<T> C;
+    C c1 = {};
+    // expected-error@algorithm:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 != c1);
+    TEST_IGNORE_NODISCARD (c1 > c1);
+  }
+
+#if TEST_STD_VER > 17
+  {
+    std::vector<int> c1 = {};
+    std::vector<std::string> c2 = {};
+    // expected-error@algorithm:* 3 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c2);
+    TEST_IGNORE_NODISCARD (c1 < c2);
+  }
+#endif
+}
Index: test/std/containers/sequences/list/compare.pass.cpp
===================================================================
--- test/std/containers/sequences/list/compare.pass.cpp
+++ test/std/containers/sequences/list/compare.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <list>
+
+// template <class T, class Allocator> bool operator==(const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator< (const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator!=(const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator> (const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator>=(const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator<=(const list<T,Allocator>& x, const list<T,Allocator>& y);
+// 
+// C++20
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator==(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator< (const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator!=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator> (const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator>=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator<=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+
+
+#include <list>
+#include <cassert>
+
+#include "min_allocator.h"
+#include "test_macros.h"
+
+template <class List>
+void test_compare(const List& LHS, const List& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
+template <class List1, class List2>
+void test_compare(const List1& LHS, const List2& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
+int main()
+{
+  {
+    typedef int T;
+    typedef std::list<T> C;
+    C c0 = {};
+    C c1 = {1, 2, 3};
+    C c2 = {1, 2, 3};
+    C c3 = {3, 2, 1};
+    C c4 = {1, 2, 1};
+    test_compare(c0, c1, true, false);
+    test_compare(c1, c2, false, true);
+    test_compare(c1, c3, true, false);
+    test_compare(c1, c4, false, false);
+  }
+
+#if TEST_STD_VER > 17
+  {
+    std::list<int>   c0 = {};
+    std::list<int>   c1 = {4};
+    std::list<long>  c2 = {4L};
+    std::list<short> c3 = {2};
+    std::list<short, min_allocator<short>> c4 = {4};
+    test_compare(c0, c1, true, false);  // same type, different lengths
+    test_compare(c0, c2, true, false);  // different type, different lengths
+    test_compare(c1, c2, false, true);  // different types, same length, same values
+    test_compare(c1, c3, false, false); // different types, same length, different values
+    test_compare(c1, c4, false, true);  // different types, same length, same value, different allocator
+  }
+#endif
+}
Index: test/std/containers/sequences/list/compare.fail.cpp
===================================================================
--- test/std/containers/sequences/list/compare.fail.cpp
+++ test/std/containers/sequences/list/compare.fail.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <list>
+
+// template <class T, class Allocator> bool operator==(const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator< (const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator!=(const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator> (const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator>=(const list<T,Allocator>& x, const list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator<=(const list<T,Allocator>& x, const list<T,Allocator>& y);
+// 
+// C++20
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator==(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator< (const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator!=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator> (const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator>=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator<=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+
+
+#include <list>
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <int Dummy> struct NoCompare {};
+
+int main()
+{
+  {
+    typedef NoCompare<0> T;
+    typedef std::list<T> C;
+    C c1 = {};
+    // expected-error@algorithm:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c1);
+    TEST_IGNORE_NODISCARD (c1 < c1);
+  }
+  {
+    typedef NoCompare<1> T;
+    typedef std::list<T> C;
+    C c1 = {};
+    // expected-error@algorithm:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 != c1);
+    TEST_IGNORE_NODISCARD (c1 > c1);
+  }
+
+#if TEST_STD_VER > 17
+  {
+    std::list<int> c1 = {};
+    std::list<std::string> c2 = {};
+    // expected-error@algorithm:* 3 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c2);
+    TEST_IGNORE_NODISCARD (c1 < c2);
+  }
+#endif
+}
Index: test/std/containers/sequences/forwardlist/compare.pass.cpp
===================================================================
--- test/std/containers/sequences/forwardlist/compare.pass.cpp
+++ test/std/containers/sequences/forwardlist/compare.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <forward_list>
+
+// template <class T, class Allocator> bool operator==(const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator< (const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator!=(const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator> (const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator>=(const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator<=(const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// 
+// C++20
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator==(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator< (const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator!=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator> (const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator>=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator<=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+
+
+#include <forward_list>
+#include <cassert>
+
+#include "min_allocator.h"
+#include "test_macros.h"
+
+template <class FList>
+void test_compare(const FList& LHS, const FList& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
+template <class FList1, class FList2>
+void test_compare(const FList1& LHS, const FList2& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
+int main()
+{
+  {
+    typedef int T;
+    typedef std::forward_list<T> C;
+    C c0 = {};
+    C c1 = {1, 2, 3};
+    C c2 = {1, 2, 3};
+    C c3 = {3, 2, 1};
+    C c4 = {1, 2, 1};
+    test_compare(c0, c1, true, false);
+    test_compare(c1, c2, false, true);
+    test_compare(c1, c3, true, false);
+    test_compare(c1, c4, false, false);
+  }
+
+#if TEST_STD_VER > 17
+  {
+    std::forward_list<int>   c0 = {};
+    std::forward_list<int>   c1 = {4};
+    std::forward_list<long>  c2 = {4L};
+    std::forward_list<short> c3 = {2};
+    std::forward_list<short, min_allocator<short>> c4 = {4};
+    test_compare(c0, c1, true, false);  // same type, different lengths
+    test_compare(c0, c2, true, false);  // different type, different lengths
+    test_compare(c1, c2, false, true);  // different types, same length, same values
+    test_compare(c1, c3, false, false); // different types, same length, different values
+    test_compare(c1, c4, false, true);  // different types, same length, same value, different allocator
+  }
+#endif
+}
Index: test/std/containers/sequences/forwardlist/compare.fail.cpp
===================================================================
--- test/std/containers/sequences/forwardlist/compare.fail.cpp
+++ test/std/containers/sequences/forwardlist/compare.fail.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <forward_list>
+
+// template <class T, class Allocator> bool operator==(const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator< (const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator!=(const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator> (const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator>=(const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// template <class T, class Allocator> bool operator<=(const forward_list<T,Allocator>& x, const forward_list<T,Allocator>& y);
+// 
+// C++20
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator==(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator< (const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator!=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator> (const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator>=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator<=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+
+
+#include <forward_list>
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <int Dummy> struct NoCompare {};
+
+int main()
+{
+  {
+    typedef NoCompare<0> T;
+    typedef std::forward_list<T> C;
+    C c1 = {};
+    // expected-error@algorithm:*  {{invalid operands to binary expression}}
+    // expected-error@forward_list:*  {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c1);
+    TEST_IGNORE_NODISCARD (c1 < c1);
+  }
+  {
+    typedef NoCompare<1> T;
+    typedef std::forward_list<T> C;
+    C c1 = {};
+    // expected-error@algorithm:* {{invalid operands to binary expression}}
+    // expected-error@forward_list:* {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 != c1);
+    TEST_IGNORE_NODISCARD (c1 > c1);
+  }
+
+#if TEST_STD_VER > 17
+  {
+    std::forward_list<int> c1 = {};
+    std::forward_list<std::string> c2 = {};
+    // expected-error@algorithm:* 3 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c2);
+    TEST_IGNORE_NODISCARD (c1 < c2);
+  }
+#endif
+}
Index: test/std/containers/sequences/deque/compare.pass.cpp
===================================================================
--- test/std/containers/sequences/deque/compare.pass.cpp
+++ test/std/containers/sequences/deque/compare.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// template <class T, class Allocator> bool operator==(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator< (const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator!=(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator> (const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator>=(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator<=(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// 
+// C++20
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator==(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator< (const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator!=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator> (const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator>=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator<=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+
+
+#include <deque>
+#include <cassert>
+
+#include "min_allocator.h"
+#include "test_macros.h"
+
+template <class Deque>
+void test_compare(const Deque& LHS, const Deque& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
+template <class Deque1, class Deque2>
+void test_compare(const Deque1& LHS, const Deque2& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
+int main()
+{
+  {
+    typedef int T;
+    typedef std::deque<T> C;
+    C c0 = {};
+    C c1 = {1, 2, 3};
+    C c2 = {1, 2, 3};
+    C c3 = {3, 2, 1};
+    C c4 = {1, 2, 1};
+    test_compare(c0, c1, true, false);
+    test_compare(c1, c2, false, true);
+    test_compare(c1, c3, true, false);
+    test_compare(c1, c4, false, false);
+  }
+
+#if TEST_STD_VER > 17
+  {
+    std::deque<int>   c0 = {};
+    std::deque<int>   c1 = {4};
+    std::deque<long>  c2 = {4L};
+    std::deque<short> c3 = {2};
+    std::deque<short, min_allocator<short>> c4 = {4};
+    test_compare(c0, c1, true, false);  // same type, different lengths
+    test_compare(c0, c2, true, false);  // different type, different lengths
+    test_compare(c1, c2, false, true);  // different types, same length, same values
+    test_compare(c1, c3, false, false); // different types, same length, different values
+    test_compare(c1, c4, false, true);  // different types, same length, same value, different allocator
+  }
+#endif
+}
Index: test/std/containers/sequences/deque/compare.fail.cpp
===================================================================
--- test/std/containers/sequences/deque/compare.fail.cpp
+++ test/std/containers/sequences/deque/compare.fail.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// template <class T, class Allocator> bool operator==(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator< (const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator!=(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator> (const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator>=(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// template <class T, class Allocator> bool operator<=(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
+// 
+// C++20
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator==(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator< (const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator!=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator> (const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator>=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+// template<class T1, class T2, class Allocator1, class Allocator2>
+//   bool operator<=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+
+
+#include <deque>
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <int Dummy> struct NoCompare {};
+
+int main()
+{
+  {
+    typedef NoCompare<0> T;
+    typedef std::deque<T> C;
+    C c1 = {};
+    // expected-error@algorithm:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c1);
+    TEST_IGNORE_NODISCARD (c1 < c1);
+  }
+  {
+    typedef NoCompare<1> T;
+    typedef std::deque<T> C;
+    C c1 = {};
+    // expected-error@algorithm:* 2 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 != c1);
+    TEST_IGNORE_NODISCARD (c1 > c1);
+  }
+
+#if TEST_STD_VER > 17
+  {
+    std::deque<int> c1 = {};
+    std::deque<std::string> c2 = {};
+    // expected-error@algorithm:* 3 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c2);
+    TEST_IGNORE_NODISCARD (c1 < c2);
+  }
+#endif
+}
Index: test/std/containers/sequences/array/compare.pass.cpp
===================================================================
--- test/std/containers/sequences/array/compare.pass.cpp
+++ test/std/containers/sequences/array/compare.pass.cpp
@@ -16,9 +16,22 @@
 // bool operator>(array<T, N> const&, array<T, N> const&);
 // bool operator>=(array<T, N> const&, array<T, N> const&);
 
+// C++20 
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator==(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator!=(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator<(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator>(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator<=(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator>=(const array<T1,N1>& x, const array<T2,N2>& y);
 
+
 #include <array>
-#include <vector>
 #include <cassert>
 
 #include "test_macros.h"
@@ -28,18 +41,25 @@
 #include "disable_missing_braces_warning.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));
+void test_compare(const Array& LHS, const Array& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
 }
 
+template <class Array1, class Array2>
+void test_compare(const Array1& LHS, const Array2& RHS, bool isLess, bool isEqual) {
+  assert((LHS == RHS) ==  isEqual);
+  assert((LHS != RHS) == !isEqual);
+  assert((LHS  < RHS) ==  isLess);
+  assert((LHS <= RHS) ==  (isLess | isEqual));
+  assert((LHS  > RHS) == !(isLess | isEqual));
+  assert((LHS >= RHS) == !isLess);
+}
+
 int main()
 {
   {
@@ -49,9 +69,9 @@
     C c2 = {1, 2, 3};
     C c3 = {3, 2, 1};
     C c4 = {1, 2, 1};
-    test_compare(c1, c2);
-    test_compare(c1, c3);
-    test_compare(c1, c4);
+    test_compare(c1, c2, false, true);
+    test_compare(c1, c3, true, false);
+    test_compare(c1, c4, false, false);
   }
   {
     typedef int T;
@@ -58,6 +78,19 @@
     typedef std::array<T, 0> C;
     C c1 = {};
     C c2 = {};
-    test_compare(c1, c2);
+    test_compare(c1, c2, false, true);
   }
+
+#if TEST_STD_VER > 17
+  {
+    std::array<int, 0>   c0 = {{}};
+    std::array<int, 1>   c1 = {{4}};
+    std::array<long, 1>  c2 = {{4L}};
+    std::array<short, 1> c3 = {{2u}};
+    test_compare(c0, c1, true, false);  // same type, different lengths
+    test_compare(c0, c2, true, false);  // different type, different lengths
+    test_compare(c1, c2, false, true);  // different types, same length, same values
+    test_compare(c1, c3, false, false); // different types, same length, different values
+  }
+#endif
 }
Index: test/std/containers/sequences/array/compare.fail.cpp
===================================================================
--- test/std/containers/sequences/array/compare.fail.cpp
+++ test/std/containers/sequences/array/compare.fail.cpp
@@ -16,9 +16,24 @@
 // bool operator>(array<T, N> const&, array<T, N> const&);
 // bool operator>=(array<T, N> const&, array<T, N> const&);
 
+// C++20 
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator==(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator!=(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator<(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator>(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator<=(const array<T1,N1>& x, const array<T2,N2>& y);
+// template <class T1, class T2, size_t N1, size_t N2>
+//   bool operator>=(const array<T1,N1>& x, const array<T2,N2>& y);
 
+
 #include <array>
 #include <vector>
+#include <string>
 #include <cassert>
 
 #include "test_macros.h"
@@ -27,19 +42,6 @@
 // Disable the missing braces warning for this reason.
 #include "disable_missing_braces_warning.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()
@@ -68,4 +70,13 @@
     TEST_IGNORE_NODISCARD (c1 == c1);
     TEST_IGNORE_NODISCARD (c1 < c1);
   }
+#if TEST_STD_VER > 17
+  {
+    std::array<int, 0> c1 = {{}};
+    std::array<std::string, 0> c2 = {{}};
+    // expected-error@algorithm:* 3 {{invalid operands to binary expression}}
+    TEST_IGNORE_NODISCARD (c1 == c2);
+    TEST_IGNORE_NODISCARD (c1 < c2);
+  }
+#endif
 }
Index: include/vector
===================================================================
--- include/vector
+++ include/vector
@@ -253,6 +253,20 @@
 template <class T, class Allocator> bool operator>=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
 template <class T, class Allocator> bool operator<=(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
 
+// C++20
+template<class T1, class T2, class Allocator1, class Allocator2>
+  bool operator==(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+  bool operator< (const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+  bool operator!=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+  bool operator> (const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+  bool operator>=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+  bool operator<=(const vector<T1, Allocator1>& x, const vector<T2, Allocator2>& y);
+
 template <class T, class Allocator>
 void swap(vector<T,Allocator>& x, vector<T,Allocator>& y)
     noexcept(noexcept(x.swap(y)));
@@ -3352,6 +3366,58 @@
     return !(__y < __x);
 }
 
+#if _LIBCPP_STD_VER > 17
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator==(const vector<_Tp1, _Allocator1>& __x, const vector<_Tp2, _Allocator2>& __y)
+{
+    if (__x.size() != __y.size())
+        return false;
+    return _VSTD::equal(__x.begin(), __x.end(), __y.begin());
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator!=(const vector<_Tp1, _Allocator1>& __x, const vector<_Tp2, _Allocator2>& __y)
+{
+    return !(__x == __y);
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator< (const vector<_Tp1, _Allocator1>& __x, const vector<_Tp2, _Allocator2>& __y)
+{
+    return _VSTD::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end());
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator> (const vector<_Tp1, _Allocator1>& __x, const vector<_Tp2, _Allocator2>& __y)
+{
+    return __y < __x;
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator>=(const vector<_Tp1, _Allocator1>& __x, const vector<_Tp2, _Allocator2>& __y)
+{
+    return !(__x < __y);
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator<=(const vector<_Tp1, _Allocator1>& __x, const vector<_Tp2, _Allocator2>& __y)
+{
+    return !(__y < __x);
+}
+#endif
+
 template <class _Tp, class _Allocator>
 inline _LIBCPP_INLINE_VISIBILITY
 void
Index: include/tuple
===================================================================
--- include/tuple
+++ include/tuple
@@ -1111,6 +1111,10 @@
     return tuple<_Tp&&...>(_VSTD::forward<_Tp>(__t)...);
 }
 
+template <typename T>
+_LIBCPP_CONSTEXPR _LIBCPP_ALWAYS_INLINE
+const T& __min(const T& __x, const T& __y) { return __y < __x ? __y : __x; }
+
 template <size_t _Ip>
 struct __tuple_equal
 {
@@ -1129,7 +1133,7 @@
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
     bool operator()(const _Tp&, const _Up&)
     {
-        return true;
+        return tuple_size<_Tp>::value == tuple_size<_Up>::value;
     }
 };
 
@@ -1138,7 +1142,9 @@
 bool
 operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
 {
-    return __tuple_equal<sizeof...(_Tp)>()(__x, __y);
+    if (sizeof...(_Tp) != sizeof...(_Up))
+        return false;
+    return __tuple_equal<__min(sizeof...(_Tp), sizeof...(_Up))>()(__x, __y);
 }
 
 template <class ..._Tp, class ..._Up>
@@ -1156,7 +1162,7 @@
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
     bool operator()(const _Tp& __x, const _Up& __y)
     {
-        const size_t __idx = tuple_size<_Tp>::value - _Ip;
+        const size_t __idx = __min(tuple_size<_Tp>::value, tuple_size<_Up>::value) - _Ip;
         if (_VSTD::get<__idx>(__x) < _VSTD::get<__idx>(__y))
             return true;
         if (_VSTD::get<__idx>(__y) < _VSTD::get<__idx>(__x))
@@ -1172,7 +1178,7 @@
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
     bool operator()(const _Tp&, const _Up&)
     {
-        return false;
+        return tuple_size<_Tp>::value < tuple_size<_Up>::value;
     }
 };
 
@@ -1181,7 +1187,7 @@
 bool
 operator<(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
 {
-    return __tuple_less<sizeof...(_Tp)>()(__x, __y);
+    return __tuple_less<__min(sizeof...(_Tp), sizeof...(_Up))>()(__x, __y);
 }
 
 template <class ..._Tp, class ..._Up>
Index: include/list
===================================================================
--- include/list
+++ include/list
@@ -160,6 +160,20 @@
 template <class T, class Alloc>
     bool operator<=(const list<T,Alloc>& x, const list<T,Alloc>& y);
 
+// C++20
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator==(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator< (const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator!=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator> (const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator>=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator<=(const list<T1, Allocator1>& x, const list<T2, Allocator2>& y);
+
 template <class T, class Alloc>
     void swap(list<T,Alloc>& x, list<T,Alloc>& y)
          noexcept(noexcept(x.swap(y)));
@@ -2405,6 +2419,58 @@
     return !(__y < __x);
 }
 
+#if _LIBCPP_STD_VER > 17
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator==(const list<_Tp1, _Allocator1>& __x, const list<_Tp2, _Allocator2>& __y)
+{
+    if (__x.size() != __y.size())
+        return false;
+    return _VSTD::equal(__x.begin(), __x.end(), __y.begin());
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator< (const list<_Tp1, _Allocator1>& __x, const list<_Tp2, _Allocator2>& __y)
+{
+    return _VSTD::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end());
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator!=(const list<_Tp1, _Allocator1>& __x, const list<_Tp2, _Allocator2>& __y)
+{
+    return !(__x == __y);
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator> (const list<_Tp1, _Allocator1>& __x, const list<_Tp2, _Allocator2>& __y)
+{
+    return __y < __x;
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator>=(const list<_Tp1, _Allocator1>& __x, const list<_Tp2, _Allocator2>& __y)
+{
+    return !(__x < __y);
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator<=(const list<_Tp1, _Allocator1>& __x, const list<_Tp2, _Allocator2>& __y)
+{
+    return !(__y < __x);
+}
+#endif
+
 template <class _Tp, class _Alloc>
 inline _LIBCPP_INLINE_VISIBILITY
 void
Index: include/forward_list
===================================================================
--- include/forward_list
+++ include/forward_list
@@ -158,6 +158,20 @@
     bool operator<=(const forward_list<T, Allocator>& x,
                     const forward_list<T, Allocator>& y);
 
+// C++20
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator==(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator< (const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator!=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator> (const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator>=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator<=(const forward_list<T1, Allocator1>& x, const forward_list<T2, Allocator2>& y);
+
 template <class T, class Allocator>
     void swap(forward_list<T, Allocator>& x, forward_list<T, Allocator>& y)
          noexcept(noexcept(x.swap(y)));
@@ -1709,6 +1723,54 @@
     return !(__y < __x);
 }
 
+#if _LIBCPP_STD_VER > 17
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+bool operator==(const forward_list<_Tp1, _Allocator1>& __x,
+                const forward_list<_Tp2, _Allocator2>& __y)
+{
+	return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end());
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+bool operator!=(const forward_list<_Tp1, _Allocator1>& __x,
+                const forward_list<_Tp2, _Allocator2>& __y)
+{
+    return !(__x == __y);
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+bool operator< (const forward_list<_Tp1, _Allocator1>& __x,
+                const forward_list<_Tp2, _Allocator2>& __y)
+{
+    return _VSTD::lexicographical_compare(__x.begin(), __x.end(),
+                                         __y.begin(), __y.end());
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator> (const forward_list<_Tp1, _Allocator1>& __x,
+                const forward_list<_Tp2, _Allocator2>& __y)
+{
+    return __y < __x;
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator>=(const forward_list<_Tp1, _Allocator1>& __x,
+                const forward_list<_Tp2, _Allocator2>& __y)
+{
+    return !(__x < __y);
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator<=(const forward_list<_Tp1, _Allocator1>& __x,
+                const forward_list<_Tp2, _Allocator2>& __y)
+{
+    return !(__y < __x);
+}
+#endif
+
 template <class _Tp, class _Alloc>
 inline _LIBCPP_INLINE_VISIBILITY
 void
Index: include/deque
===================================================================
--- include/deque
+++ include/deque
@@ -141,6 +141,20 @@
 template <class T, class Allocator>
     bool operator<=(const deque<T,Allocator>& x, const deque<T,Allocator>& y);
 
+// C++20
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator==(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator< (const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator!=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator> (const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator>=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+template<class T1, class T2, class Allocator1, class Allocator2>
+    bool operator<=(const deque<T1, Allocator1>& x, const deque<T2, Allocator2>& y);
+
 // specialized algorithms:
 template <class T, class Allocator>
     void swap(deque<T,Allocator>& x, deque<T,Allocator>& y)
@@ -2894,6 +2908,58 @@
     return !(__y < __x);
 }
 
+#if _LIBCPP_STD_VER > 17
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator==(const deque<_Tp1, _Allocator1>& __x, const deque<_Tp2, _Allocator2>& __y)
+{
+    if (__x.size() != __y.size())
+        return false;
+    return _VSTD::equal(__x.begin(), __x.end(), __y.begin());
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator!=(const deque<_Tp1, _Allocator1>& __x, const deque<_Tp2, _Allocator2>& __y)
+{
+    return !(__x == __y);
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator< (const deque<_Tp1, _Allocator1>& __x, const deque<_Tp2, _Allocator2>& __y)
+{
+    return _VSTD::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end());
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator> (const deque<_Tp1, _Allocator1>& __x, const deque<_Tp2, _Allocator2>& __y)
+{
+    return __y < __x;
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator>=(const deque<_Tp1, _Allocator1>& __x, const deque<_Tp2, _Allocator2>& __y)
+{
+    return !(__x < __y);
+}
+
+template <class _Tp1, class _Tp2, class _Allocator1, class _Allocator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator<=(const deque<_Tp1, _Allocator1>& __x, const deque<_Tp2, _Allocator2>& __y)
+{
+    return !(__y < __x);
+}
+#endif
+
 template <class _Tp, class _Allocator>
 inline _LIBCPP_INLINE_VISIBILITY
 void
Index: include/array
===================================================================
--- include/array
+++ include/array
@@ -85,6 +85,20 @@
 template <class T, size_t N>
   bool operator>=(const array<T,N>& x, const array<T,N>& y);
 
+// C++20 
+template <class T1, class T2, size_t N1, size_t N2>
+  bool operator==(const array<T1,N1>& x, const array<T2,N2>& y);
+template <class T1, class T2, size_t N1, size_t N2>
+  bool operator!=(const array<T1,N1>& x, const array<T2,N2>& y);
+template <class T1, class T2, size_t N1, size_t N2>
+  bool operator<(const array<T1,N1>& x, const array<T2,N2>& y);
+template <class T1, class T2, size_t N1, size_t N2>
+  bool operator>(const array<T1,N1>& x, const array<T2,N2>& y);
+template <class T1, class T2, size_t N1, size_t N2>
+  bool operator<=(const array<T1,N1>& x, const array<T2,N2>& y);
+template <class T1, class T2, size_t N1, size_t N2>
+  bool operator>=(const array<T1,N1>& x, const array<T2,N2>& y);
+
 template <class T, size_t N >
   void swap(array<T,N>& x, array<T,N>& y) noexcept(noexcept(x.swap(y)));
 
@@ -403,6 +417,59 @@
     return !(__x < __y);
 }
 
+#if _LIBCPP_STD_VER > 17
+template <class _Tp1, class _Tp2, size_t _Size1, size_t _Size2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator==(const array<_Tp1, _Size1>& __x, const array<_Tp2, _Size2>& __y)
+{
+    if (_Size1 != _Size2)
+        return false;
+    return _VSTD::equal(__x.begin(), __x.end(), __y.begin());
+}
+
+template <class _Tp1, class _Tp2, size_t _Size1, size_t _Size2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator!=(const array<_Tp1, _Size1>& __x, const array<_Tp2, _Size2>& __y)
+{
+    return !(__x == __y);
+}
+
+template <class _Tp1, class _Tp2, size_t _Size1, size_t _Size2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator<(const array<_Tp1, _Size1>& __x, const array<_Tp2, _Size2>& __y)
+{
+    return _VSTD::lexicographical_compare(__x.begin(), __x.end(),
+                                          __y.begin(), __y.end());
+}
+
+template <class _Tp1, class _Tp2, size_t _Size1, size_t _Size2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator>(const array<_Tp1, _Size1>& __x, const array<_Tp2, _Size2>& __y)
+{
+    return __y < __x;
+}
+
+template <class _Tp1, class _Tp2, size_t _Size1, size_t _Size2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator<=(const array<_Tp1, _Size1>& __x, const array<_Tp2, _Size2>& __y)
+{
+    return !(__y < __x);
+}
+
+template <class _Tp1, class _Tp2, size_t _Size1, size_t _Size2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+operator>=(const array<_Tp1, _Size1>& __x, const array<_Tp2, _Size2>& __y)
+{
+    return !(__x < __y);
+}
+#endif
+
 template <class _Tp, size_t _Size>
 inline _LIBCPP_INLINE_VISIBILITY
 typename enable_if
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to