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 // UNSUPPORTED: c++03, c++11, c++14
10
11 // <variant>
12
13 // template <class ...Types>
14 // constexpr bool
15 // operator==(variant<Types...> const&, variant<Types...> const&) noexcept;
16 //
17 // template <class ...Types>
18 // constexpr bool
19 // operator!=(variant<Types...> const&, variant<Types...> const&) noexcept;
20 //
21 // template <class ...Types>
22 // constexpr bool
23 // operator<(variant<Types...> const&, variant<Types...> const&) noexcept;
24 //
25 // template <class ...Types>
26 // constexpr bool
27 // operator>(variant<Types...> const&, variant<Types...> const&) noexcept;
28 //
29 // template <class ...Types>
30 // constexpr bool
31 // operator<=(variant<Types...> const&, variant<Types...> const&) noexcept;
32 //
33 // template <class ...Types>
34 // constexpr bool
35 // operator>=(variant<Types...> const&, variant<Types...> const&) noexcept;
36
37 #include <cassert>
38 #include <type_traits>
39 #include <utility>
40 #include <variant>
41
42 #include "test_macros.h"
43
44 #ifndef TEST_HAS_NO_EXCEPTIONS
45 struct MakeEmptyT {
46 MakeEmptyT() = default;
MakeEmptyTMakeEmptyT47 MakeEmptyT(MakeEmptyT &&) { throw 42; }
operator =MakeEmptyT48 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
49 };
operator ==(const MakeEmptyT &,const MakeEmptyT &)50 inline bool operator==(const MakeEmptyT &, const MakeEmptyT &) {
51 assert(false);
52 return false;
53 }
operator !=(const MakeEmptyT &,const MakeEmptyT &)54 inline bool operator!=(const MakeEmptyT &, const MakeEmptyT &) {
55 assert(false);
56 return false;
57 }
operator <(const MakeEmptyT &,const MakeEmptyT &)58 inline bool operator<(const MakeEmptyT &, const MakeEmptyT &) {
59 assert(false);
60 return false;
61 }
operator <=(const MakeEmptyT &,const MakeEmptyT &)62 inline bool operator<=(const MakeEmptyT &, const MakeEmptyT &) {
63 assert(false);
64 return false;
65 }
operator >(const MakeEmptyT &,const MakeEmptyT &)66 inline bool operator>(const MakeEmptyT &, const MakeEmptyT &) {
67 assert(false);
68 return false;
69 }
operator >=(const MakeEmptyT &,const MakeEmptyT &)70 inline bool operator>=(const MakeEmptyT &, const MakeEmptyT &) {
71 assert(false);
72 return false;
73 }
74
makeEmpty(Variant & v)75 template <class Variant> void makeEmpty(Variant &v) {
76 Variant v2(std::in_place_type<MakeEmptyT>);
77 try {
78 v = std::move(v2);
79 assert(false);
80 } catch (...) {
81 assert(v.valueless_by_exception());
82 }
83 }
84 #endif // TEST_HAS_NO_EXCEPTIONS
85
86 struct MyBool {
87 bool value;
MyBoolMyBool88 constexpr explicit MyBool(bool v) : value(v) {}
operator boolMyBool89 constexpr operator bool() const noexcept { return value; }
90 };
91
92 struct ComparesToMyBool {
93 int value = 0;
94 };
operator ==(const ComparesToMyBool & LHS,const ComparesToMyBool & RHS)95 inline constexpr MyBool operator==(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
96 return MyBool(LHS.value == RHS.value);
97 }
operator !=(const ComparesToMyBool & LHS,const ComparesToMyBool & RHS)98 inline constexpr MyBool operator!=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
99 return MyBool(LHS.value != RHS.value);
100 }
operator <(const ComparesToMyBool & LHS,const ComparesToMyBool & RHS)101 inline constexpr MyBool operator<(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
102 return MyBool(LHS.value < RHS.value);
103 }
operator <=(const ComparesToMyBool & LHS,const ComparesToMyBool & RHS)104 inline constexpr MyBool operator<=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
105 return MyBool(LHS.value <= RHS.value);
106 }
operator >(const ComparesToMyBool & LHS,const ComparesToMyBool & RHS)107 inline constexpr MyBool operator>(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
108 return MyBool(LHS.value > RHS.value);
109 }
operator >=(const ComparesToMyBool & LHS,const ComparesToMyBool & RHS)110 inline constexpr MyBool operator>=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
111 return MyBool(LHS.value >= RHS.value);
112 }
113
114 template <class T1, class T2>
test_equality_basic()115 void test_equality_basic() {
116 {
117 using V = std::variant<T1, T2>;
118 constexpr V v1(std::in_place_index<0>, T1{42});
119 constexpr V v2(std::in_place_index<0>, T1{42});
120 static_assert(v1 == v2, "");
121 static_assert(v2 == v1, "");
122 static_assert(!(v1 != v2), "");
123 static_assert(!(v2 != v1), "");
124 }
125 {
126 using V = std::variant<T1, T2>;
127 constexpr V v1(std::in_place_index<0>, T1{42});
128 constexpr V v2(std::in_place_index<0>, T1{43});
129 static_assert(!(v1 == v2), "");
130 static_assert(!(v2 == v1), "");
131 static_assert(v1 != v2, "");
132 static_assert(v2 != v1, "");
133 }
134 {
135 using V = std::variant<T1, T2>;
136 constexpr V v1(std::in_place_index<0>, T1{42});
137 constexpr V v2(std::in_place_index<1>, T2{42});
138 static_assert(!(v1 == v2), "");
139 static_assert(!(v2 == v1), "");
140 static_assert(v1 != v2, "");
141 static_assert(v2 != v1, "");
142 }
143 {
144 using V = std::variant<T1, T2>;
145 constexpr V v1(std::in_place_index<1>, T2{42});
146 constexpr V v2(std::in_place_index<1>, T2{42});
147 static_assert(v1 == v2, "");
148 static_assert(v2 == v1, "");
149 static_assert(!(v1 != v2), "");
150 static_assert(!(v2 != v1), "");
151 }
152 }
153
test_equality()154 void test_equality() {
155 test_equality_basic<int, long>();
156 test_equality_basic<ComparesToMyBool, int>();
157 test_equality_basic<int, ComparesToMyBool>();
158 test_equality_basic<ComparesToMyBool, ComparesToMyBool>();
159 #ifndef TEST_HAS_NO_EXCEPTIONS
160 {
161 using V = std::variant<int, MakeEmptyT>;
162 V v1;
163 V v2;
164 makeEmpty(v2);
165 assert(!(v1 == v2));
166 assert(!(v2 == v1));
167 assert(v1 != v2);
168 assert(v2 != v1);
169 }
170 {
171 using V = std::variant<int, MakeEmptyT>;
172 V v1;
173 makeEmpty(v1);
174 V v2;
175 assert(!(v1 == v2));
176 assert(!(v2 == v1));
177 assert(v1 != v2);
178 assert(v2 != v1);
179 }
180 {
181 using V = std::variant<int, MakeEmptyT>;
182 V v1;
183 makeEmpty(v1);
184 V v2;
185 makeEmpty(v2);
186 assert(v1 == v2);
187 assert(v2 == v1);
188 assert(!(v1 != v2));
189 assert(!(v2 != v1));
190 }
191 #endif
192 }
193
194 template <class Var>
test_less(const Var & l,const Var & r,bool expect_less,bool expect_greater)195 constexpr bool test_less(const Var &l, const Var &r, bool expect_less,
196 bool expect_greater) {
197 static_assert(std::is_same_v<decltype(l < r), bool>, "");
198 static_assert(std::is_same_v<decltype(l <= r), bool>, "");
199 static_assert(std::is_same_v<decltype(l > r), bool>, "");
200 static_assert(std::is_same_v<decltype(l >= r), bool>, "");
201
202 return ((l < r) == expect_less) && (!(l >= r) == expect_less) &&
203 ((l > r) == expect_greater) && (!(l <= r) == expect_greater);
204 }
205
206 template <class T1, class T2>
test_relational_basic()207 void test_relational_basic() {
208 { // same index, same value
209 using V = std::variant<T1, T2>;
210 constexpr V v1(std::in_place_index<0>, T1{1});
211 constexpr V v2(std::in_place_index<0>, T1{1});
212 static_assert(test_less(v1, v2, false, false), "");
213 }
214 { // same index, value < other_value
215 using V = std::variant<T1, T2>;
216 constexpr V v1(std::in_place_index<0>, T1{0});
217 constexpr V v2(std::in_place_index<0>, T1{1});
218 static_assert(test_less(v1, v2, true, false), "");
219 }
220 { // same index, value > other_value
221 using V = std::variant<T1, T2>;
222 constexpr V v1(std::in_place_index<0>, T1{1});
223 constexpr V v2(std::in_place_index<0>, T1{0});
224 static_assert(test_less(v1, v2, false, true), "");
225 }
226 { // LHS.index() < RHS.index()
227 using V = std::variant<T1, T2>;
228 constexpr V v1(std::in_place_index<0>, T1{0});
229 constexpr V v2(std::in_place_index<1>, T2{0});
230 static_assert(test_less(v1, v2, true, false), "");
231 }
232 { // LHS.index() > RHS.index()
233 using V = std::variant<T1, T2>;
234 constexpr V v1(std::in_place_index<1>, T2{0});
235 constexpr V v2(std::in_place_index<0>, T1{0});
236 static_assert(test_less(v1, v2, false, true), "");
237 }
238 }
239
test_relational()240 void test_relational() {
241 test_relational_basic<int, long>();
242 test_relational_basic<ComparesToMyBool, int>();
243 test_relational_basic<int, ComparesToMyBool>();
244 test_relational_basic<ComparesToMyBool, ComparesToMyBool>();
245 #ifndef TEST_HAS_NO_EXCEPTIONS
246 { // LHS.index() < RHS.index(), RHS is empty
247 using V = std::variant<int, MakeEmptyT>;
248 V v1;
249 V v2;
250 makeEmpty(v2);
251 assert(test_less(v1, v2, false, true));
252 }
253 { // LHS.index() > RHS.index(), LHS is empty
254 using V = std::variant<int, MakeEmptyT>;
255 V v1;
256 makeEmpty(v1);
257 V v2;
258 assert(test_less(v1, v2, true, false));
259 }
260 { // LHS.index() == RHS.index(), LHS and RHS are empty
261 using V = std::variant<int, MakeEmptyT>;
262 V v1;
263 makeEmpty(v1);
264 V v2;
265 makeEmpty(v2);
266 assert(test_less(v1, v2, false, false));
267 }
268 #endif
269 }
270
main(int,char **)271 int main(int, char**) {
272 test_equality();
273 test_relational();
274
275 return 0;
276 }
277