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