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 {
operator ==(const CustomEquality &,int)33 friend constexpr bool operator==(const CustomEquality&, int) noexcept { return true; }
operator <(const CustomEquality &,int)34 friend constexpr bool operator<(const CustomEquality&, int) noexcept { return false; }
operator <(int,const CustomEquality &)35 friend constexpr bool operator<(int, const CustomEquality&) noexcept { return false; }
36 };
37
test()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
main(int,char **)230 int main(int, char**) {
231 test();
232 static_assert(test());
233
234 return 0;
235 }
236