1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // <tuple> 10 11 // template <class... Types> class tuple; 12 13 // template<class... TTypes, class... UTypes> 14 // auto 15 // operator<=>(const tuple<TTypes...>& t, const tuple<UTypes...>& u); 16 17 // UNSUPPORTED: c++03, c++11, c++14, c++17 18 19 #include "test_macros.h" 20 21 TEST_CLANG_DIAGNOSTIC_IGNORED("-Wsign-compare") 22 TEST_GCC_DIAGNOSTIC_IGNORED("-Wsign-compare") 23 TEST_MSVC_DIAGNOSTIC_IGNORED(4242 4244) 24 25 #include <cassert> 26 #include <compare> 27 #include <limits> 28 #include <tuple> 29 #include <type_traits> // std::is_constant_evaluated 30 31 // A custom three-way result type 32 struct CustomEquality { 33 friend constexpr bool operator==(const CustomEquality&, int) noexcept { return true; } 34 friend constexpr bool operator<(const CustomEquality&, int) noexcept { return false; } 35 friend constexpr bool operator<(int, const CustomEquality&) noexcept { return false; } 36 }; 37 38 constexpr bool test() { 39 // Empty tuple 40 { 41 typedef std::tuple<> T0; 42 // No member types yields strong ordering (all are equal). 43 ASSERT_SAME_TYPE(decltype(T0() <=> T0()), std::strong_ordering); 44 assert((T0() <=> T0()) == std::strong_ordering::equal); 45 } 46 // Mixed types with integers, which compare strongly ordered 47 { 48 typedef std::tuple<long> T1; 49 typedef std::tuple<short> T2; 50 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); 51 assert((T1(1) <=> T2(1)) == std::strong_ordering::equal); 52 assert((T1(1) <=> T2(0)) == std::strong_ordering::greater); 53 assert((T1(1) <=> T2(2)) == std::strong_ordering::less); 54 } 55 { 56 typedef std::tuple<long, unsigned int> T1; 57 typedef std::tuple<short, unsigned long> T2; 58 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); 59 assert((T1(1, 2) <=> T2(1, 2)) == std::strong_ordering::equal); 60 assert((T1(1, 2) <=> T2(0, 2)) == std::strong_ordering::greater); 61 assert((T1(1, 2) <=> T2(2, 2)) == std::strong_ordering::less); 62 assert((T1(1, 2) <=> T2(1, 1)) == std::strong_ordering::greater); 63 assert((T1(1, 2) <=> T2(1, 3)) == std::strong_ordering::less); 64 } 65 { 66 typedef std::tuple<long, int, unsigned short> T1; 67 typedef std::tuple<short, long, unsigned int> T2; 68 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); 69 assert((T1(1, 2, 3) <=> T2(1, 2, 3)) == std::strong_ordering::equal); 70 assert((T1(1, 2, 3) <=> T2(0, 2, 3)) == std::strong_ordering::greater); 71 assert((T1(1, 2, 3) <=> T2(2, 2, 3)) == std::strong_ordering::less); 72 assert((T1(1, 2, 3) <=> T2(1, 1, 3)) == std::strong_ordering::greater); 73 assert((T1(1, 2, 3) <=> T2(1, 3, 3)) == std::strong_ordering::less); 74 assert((T1(1, 2, 3) <=> T2(1, 2, 2)) == std::strong_ordering::greater); 75 assert((T1(1, 2, 3) <=> T2(1, 2, 4)) == std::strong_ordering::less); 76 } 77 // Mixed types with floating point, which compare partially ordered 78 { 79 typedef std::tuple<long> T1; 80 typedef std::tuple<double> T2; 81 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 82 assert((T1(1) <=> T2(1)) == std::partial_ordering::equivalent); 83 assert((T1(1) <=> T2(0.9)) == std::partial_ordering::greater); 84 assert((T1(1) <=> T2(1.1)) == std::partial_ordering::less); 85 } 86 { 87 typedef std::tuple<long, float> T1; 88 typedef std::tuple<double, unsigned int> T2; 89 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 90 assert((T1(1, 2) <=> T2(1, 2)) == std::partial_ordering::equivalent); 91 assert((T1(1, 2) <=> T2(0.9, 2)) == std::partial_ordering::greater); 92 assert((T1(1, 2) <=> T2(1.1, 2)) == std::partial_ordering::less); 93 assert((T1(1, 2) <=> T2(1, 1)) == std::partial_ordering::greater); 94 assert((T1(1, 2) <=> T2(1, 3)) == std::partial_ordering::less); 95 } 96 { 97 typedef std::tuple<short, float, double> T1; 98 typedef std::tuple<double, long, unsigned int> T2; 99 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 100 assert((T1(1, 2, 3) <=> T2(1, 2, 3)) == std::partial_ordering::equivalent); 101 assert((T1(1, 2, 3) <=> T2(0.9, 2, 3)) == std::partial_ordering::greater); 102 assert((T1(1, 2, 3) <=> T2(1.1, 2, 3)) == std::partial_ordering::less); 103 assert((T1(1, 2, 3) <=> T2(1, 1, 3)) == std::partial_ordering::greater); 104 assert((T1(1, 2, 3) <=> T2(1, 3, 3)) == std::partial_ordering::less); 105 assert((T1(1, 2, 3) <=> T2(1, 2, 2)) == std::partial_ordering::greater); 106 assert((T1(1, 2, 3) <=> T2(1, 2, 4)) == std::partial_ordering::less); 107 } 108 { 109 typedef std::tuple<float> T1; 110 typedef std::tuple<double> T2; 111 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 112 // Comparisons with NaN and non-NaN are non-constexpr in GCC, so both sides must be NaN 113 assert((T1(nan) <=> T2(nan)) == std::partial_ordering::unordered); 114 } 115 { 116 typedef std::tuple<double, double> T1; 117 typedef std::tuple<float, float> T2; 118 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 119 assert((T1(nan, 2) <=> T2(nan, 2)) == std::partial_ordering::unordered); 120 assert((T1(1, nan) <=> T2(1, nan)) == std::partial_ordering::unordered); 121 } 122 { 123 typedef std::tuple<double, float, float> T1; 124 typedef std::tuple<double, double, float> T2; 125 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 126 assert((T1(nan, 2, 3) <=> T2(nan, 2, 3)) == std::partial_ordering::unordered); 127 assert((T1(1, nan, 3) <=> T2(1, nan, 3)) == std::partial_ordering::unordered); 128 assert((T1(1, 2, nan) <=> T2(1, 2, nan)) == std::partial_ordering::unordered); 129 } 130 // Ordering classes and synthesized three way comparison 131 { 132 typedef std::tuple<long, int, unsigned int> T1; 133 typedef std::tuple<int, long, unsigned short> T2; 134 // All strongly ordered members yields strong ordering. 135 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::strong_ordering); 136 } 137 { 138 struct WeakSpaceship { 139 constexpr bool operator==(const WeakSpaceship&) const { return true; } 140 constexpr std::weak_ordering operator<=>(const WeakSpaceship&) const { return std::weak_ordering::equivalent; } 141 }; 142 { 143 typedef std::tuple<int, unsigned int, WeakSpaceship> T1; 144 typedef std::tuple<int, unsigned long, WeakSpaceship> T2; 145 // Strongly ordered members and a weakly ordered member yields weak ordering. 146 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 147 } 148 { 149 typedef std::tuple<unsigned int, int, WeakSpaceship> T1; 150 typedef std::tuple<double, long, WeakSpaceship> T2; 151 // Doubles are partially ordered, so one partial, one strong, and one weak ordering 152 // yields partial ordering. 153 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 154 } 155 } 156 { 157 struct NoSpaceship { 158 constexpr bool operator==(const NoSpaceship&) const { return true; } 159 constexpr bool operator<(const NoSpaceship&) const { return false; } 160 }; 161 typedef std::tuple<int, unsigned int, NoSpaceship> T1; 162 typedef std::tuple<int, unsigned long, NoSpaceship> T2; 163 // Strongly ordered members and a weakly ordered member (synthesized) yields weak ordering. 164 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 165 } 166 { 167 struct SpaceshipNoEquals { 168 constexpr std::strong_ordering operator<=>(const SpaceshipNoEquals&) const { return std::strong_ordering::equal; } 169 constexpr bool operator<(const SpaceshipNoEquals&) const { return false; } 170 }; 171 typedef std::tuple<int, unsigned int, SpaceshipNoEquals> T1; 172 typedef std::tuple<int, unsigned long, SpaceshipNoEquals> T2; 173 // Spaceship operator with no == operator falls back on the < operator and weak ordering. 174 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 175 } 176 { 177 struct CustomSpaceship { 178 constexpr CustomEquality operator<=>(const CustomSpaceship&) const { return CustomEquality(); } 179 }; 180 typedef std::tuple<int, unsigned int, CustomSpaceship> T1; 181 typedef std::tuple<short, unsigned long, CustomSpaceship> T2; 182 typedef std::tuple<CustomSpaceship> T3; 183 // Custom three way return types cannot be used in synthesized three way comparison, 184 // but they can be used for (rewritten) operator< when synthesizing a weak ordering. 185 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 186 ASSERT_SAME_TYPE(decltype(T3() <=> T3()), std::weak_ordering); 187 } 188 { 189 typedef std::tuple<long, int> T1; 190 typedef std::tuple<long, unsigned int> T2; 191 // Even with the warning suppressed (-Wno-sign-compare) there should still be no <=> operator 192 // between signed and unsigned types, so we should end up with a synthesized weak ordering. 193 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::weak_ordering); 194 } 195 196 #ifdef TEST_COMPILER_GCC 197 // GCC cannot evaluate NaN @ non-NaN constexpr, so test that runtime-only. 198 if (!std::is_constant_evaluated()) 199 #endif 200 { 201 { 202 typedef std::tuple<double> T1; 203 typedef std::tuple<int> T2; 204 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 205 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 206 assert((T1(nan) <=> T2(1)) == std::partial_ordering::unordered); 207 } 208 { 209 typedef std::tuple<double, double> T1; 210 typedef std::tuple<int, int> T2; 211 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 212 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 213 assert((T1(nan, 2) <=> T2(1, 2)) == std::partial_ordering::unordered); 214 assert((T1(1, nan) <=> T2(1, 2)) == std::partial_ordering::unordered); 215 } 216 { 217 typedef std::tuple<double, double, double> T1; 218 typedef std::tuple<int, int, int> T2; 219 constexpr double nan = std::numeric_limits<double>::quiet_NaN(); 220 ASSERT_SAME_TYPE(decltype(T1() <=> T2()), std::partial_ordering); 221 assert((T1(nan, 2, 3) <=> T2(1, 2, 3)) == std::partial_ordering::unordered); 222 assert((T1(1, nan, 3) <=> T2(1, 2, 3)) == std::partial_ordering::unordered); 223 assert((T1(1, 2, nan) <=> T2(1, 2, 3)) == std::partial_ordering::unordered); 224 } 225 } 226 227 return true; 228 } 229 230 int main(int, char**) { 231 test(); 232 static_assert(test()); 233 234 return 0; 235 } 236