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