[RISCV] Fix mgather -> riscv.masked.strided.load combine not extending indices (...
[llvm-project.git] / libcxx / test / std / utilities / variant / variant.variant / variant.swap / swap.pass.cpp
blob1802bc4670bba90cc19cee92a8bbb9afb59331c6
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 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14
11 // <variant>
13 // template <class ...Types> class variant;
15 // void swap(variant& rhs) noexcept(see below)
17 #include <cassert>
18 #include <cstdlib>
19 #include <string>
20 #include <type_traits>
21 #include <variant>
23 #include "test_convertible.h"
24 #include "test_macros.h"
25 #include "variant_test_helpers.h"
27 struct NotSwappable {};
28 void swap(NotSwappable &, NotSwappable &) = delete;
30 struct NotCopyable {
31 NotCopyable() = default;
32 NotCopyable(const NotCopyable &) = delete;
33 NotCopyable &operator=(const NotCopyable &) = delete;
36 struct NotCopyableWithSwap {
37 NotCopyableWithSwap() = default;
38 NotCopyableWithSwap(const NotCopyableWithSwap &) = delete;
39 NotCopyableWithSwap &operator=(const NotCopyableWithSwap &) = delete;
41 void swap(NotCopyableWithSwap &, NotCopyableWithSwap) {}
43 struct NotMoveAssignable {
44 NotMoveAssignable() = default;
45 NotMoveAssignable(NotMoveAssignable &&) = default;
46 NotMoveAssignable &operator=(NotMoveAssignable &&) = delete;
49 struct NotMoveAssignableWithSwap {
50 NotMoveAssignableWithSwap() = default;
51 NotMoveAssignableWithSwap(NotMoveAssignableWithSwap &&) = default;
52 NotMoveAssignableWithSwap &operator=(NotMoveAssignableWithSwap &&) = delete;
54 void swap(NotMoveAssignableWithSwap &, NotMoveAssignableWithSwap &) noexcept {}
56 template <bool Throws> void do_throw() {}
58 template <> void do_throw<true>() {
59 #ifndef TEST_HAS_NO_EXCEPTIONS
60 throw 42;
61 #else
62 std::abort();
63 #endif
66 template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
67 bool NT_Swap, bool EnableSwap = true>
68 struct NothrowTypeImp {
69 static int move_called;
70 static int move_assign_called;
71 static int swap_called;
72 static void reset() { move_called = move_assign_called = swap_called = 0; }
73 NothrowTypeImp() = default;
74 explicit NothrowTypeImp(int v) : value(v) {}
75 NothrowTypeImp(const NothrowTypeImp &o) noexcept(NT_Copy) : value(o.value) {
76 assert(false);
77 } // never called by test
78 NothrowTypeImp(NothrowTypeImp &&o) noexcept(NT_Move) : value(o.value) {
79 ++move_called;
80 do_throw<!NT_Move>();
81 o.value = -1;
83 NothrowTypeImp &operator=(const NothrowTypeImp &) noexcept(NT_CopyAssign) {
84 assert(false);
85 return *this;
86 } // never called by the tests
87 NothrowTypeImp &operator=(NothrowTypeImp &&o) noexcept(NT_MoveAssign) {
88 ++move_assign_called;
89 do_throw<!NT_MoveAssign>();
90 value = o.value;
91 o.value = -1;
92 return *this;
94 int value;
96 template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
97 bool NT_Swap, bool EnableSwap>
98 int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
99 EnableSwap>::move_called = 0;
100 template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
101 bool NT_Swap, bool EnableSwap>
102 int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
103 EnableSwap>::move_assign_called = 0;
104 template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
105 bool NT_Swap, bool EnableSwap>
106 int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
107 EnableSwap>::swap_called = 0;
109 template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
110 bool NT_Swap>
111 void swap(NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign,
112 NT_Swap, true> &lhs,
113 NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign,
114 NT_Swap, true> &rhs) noexcept(NT_Swap) {
115 lhs.swap_called++;
116 do_throw<!NT_Swap>();
117 int tmp = lhs.value;
118 lhs.value = rhs.value;
119 rhs.value = tmp;
122 // throwing copy, nothrow move ctor/assign, no swap provided
123 using NothrowMoveable = NothrowTypeImp<false, true, false, true, false, false>;
124 // throwing copy and move assign, nothrow move ctor, no swap provided
125 using NothrowMoveCtor = NothrowTypeImp<false, true, false, false, false, false>;
126 // nothrow move ctor, throwing move assignment, swap provided
127 using NothrowMoveCtorWithThrowingSwap =
128 NothrowTypeImp<false, true, false, false, false, true>;
129 // throwing move ctor, nothrow move assignment, no swap provided
130 using ThrowingMoveCtor =
131 NothrowTypeImp<false, false, false, true, false, false>;
132 // throwing special members, nothrowing swap
133 using ThrowingTypeWithNothrowSwap =
134 NothrowTypeImp<false, false, false, false, true, true>;
135 using NothrowTypeWithThrowingSwap =
136 NothrowTypeImp<true, true, true, true, false, true>;
137 // throwing move assign with nothrow move and nothrow swap
138 using ThrowingMoveAssignNothrowMoveCtorWithSwap =
139 NothrowTypeImp<false, true, false, false, true, true>;
140 // throwing move assign with nothrow move but no swap.
141 using ThrowingMoveAssignNothrowMoveCtor =
142 NothrowTypeImp<false, true, false, false, false, false>;
144 struct NonThrowingNonNoexceptType {
145 static int move_called;
146 static void reset() { move_called = 0; }
147 NonThrowingNonNoexceptType() = default;
148 NonThrowingNonNoexceptType(int v) : value(v) {}
149 NonThrowingNonNoexceptType(NonThrowingNonNoexceptType &&o) noexcept(false)
150 : value(o.value) {
151 ++move_called;
152 o.value = -1;
154 NonThrowingNonNoexceptType &
155 operator=(NonThrowingNonNoexceptType &&) noexcept(false) {
156 assert(false); // never called by the tests.
157 return *this;
159 int value;
161 int NonThrowingNonNoexceptType::move_called = 0;
163 struct ThrowsOnSecondMove {
164 int value;
165 int move_count;
166 ThrowsOnSecondMove(int v) : value(v), move_count(0) {}
167 ThrowsOnSecondMove(ThrowsOnSecondMove &&o) noexcept(false)
168 : value(o.value), move_count(o.move_count + 1) {
169 if (move_count == 2)
170 do_throw<true>();
171 o.value = -1;
173 ThrowsOnSecondMove &operator=(ThrowsOnSecondMove &&) {
174 assert(false); // not called by test
175 return *this;
179 void test_swap_valueless_by_exception() {
180 #ifndef TEST_HAS_NO_EXCEPTIONS
181 using V = std::variant<int, MakeEmptyT>;
182 { // both empty
183 V v1;
184 makeEmpty(v1);
185 V v2;
186 makeEmpty(v2);
187 assert(MakeEmptyT::alive == 0);
188 { // member swap
189 v1.swap(v2);
190 assert(v1.valueless_by_exception());
191 assert(v2.valueless_by_exception());
192 assert(MakeEmptyT::alive == 0);
194 { // non-member swap
195 swap(v1, v2);
196 assert(v1.valueless_by_exception());
197 assert(v2.valueless_by_exception());
198 assert(MakeEmptyT::alive == 0);
201 { // only one empty
202 V v1(42);
203 V v2;
204 makeEmpty(v2);
205 { // member swap
206 v1.swap(v2);
207 assert(v1.valueless_by_exception());
208 assert(std::get<0>(v2) == 42);
209 // swap again
210 v2.swap(v1);
211 assert(v2.valueless_by_exception());
212 assert(std::get<0>(v1) == 42);
214 { // non-member swap
215 swap(v1, v2);
216 assert(v1.valueless_by_exception());
217 assert(std::get<0>(v2) == 42);
218 // swap again
219 swap(v1, v2);
220 assert(v2.valueless_by_exception());
221 assert(std::get<0>(v1) == 42);
224 #endif
227 void test_swap_same_alternative() {
229 using T = ThrowingTypeWithNothrowSwap;
230 using V = std::variant<T, int>;
231 T::reset();
232 V v1(std::in_place_index<0>, 42);
233 V v2(std::in_place_index<0>, 100);
234 v1.swap(v2);
235 assert(T::swap_called == 1);
236 assert(std::get<0>(v1).value == 100);
237 assert(std::get<0>(v2).value == 42);
238 swap(v1, v2);
239 assert(T::swap_called == 2);
240 assert(std::get<0>(v1).value == 42);
241 assert(std::get<0>(v2).value == 100);
244 using T = NothrowMoveable;
245 using V = std::variant<T, int>;
246 T::reset();
247 V v1(std::in_place_index<0>, 42);
248 V v2(std::in_place_index<0>, 100);
249 v1.swap(v2);
250 assert(T::swap_called == 0);
251 assert(T::move_called == 1);
252 assert(T::move_assign_called == 2);
253 assert(std::get<0>(v1).value == 100);
254 assert(std::get<0>(v2).value == 42);
255 T::reset();
256 swap(v1, v2);
257 assert(T::swap_called == 0);
258 assert(T::move_called == 1);
259 assert(T::move_assign_called == 2);
260 assert(std::get<0>(v1).value == 42);
261 assert(std::get<0>(v2).value == 100);
263 #ifndef TEST_HAS_NO_EXCEPTIONS
265 using T = NothrowTypeWithThrowingSwap;
266 using V = std::variant<T, int>;
267 T::reset();
268 V v1(std::in_place_index<0>, 42);
269 V v2(std::in_place_index<0>, 100);
270 try {
271 v1.swap(v2);
272 assert(false);
273 } catch (int) {
275 assert(T::swap_called == 1);
276 assert(T::move_called == 0);
277 assert(T::move_assign_called == 0);
278 assert(std::get<0>(v1).value == 42);
279 assert(std::get<0>(v2).value == 100);
282 using T = ThrowingMoveCtor;
283 using V = std::variant<T, int>;
284 T::reset();
285 V v1(std::in_place_index<0>, 42);
286 V v2(std::in_place_index<0>, 100);
287 try {
288 v1.swap(v2);
289 assert(false);
290 } catch (int) {
292 assert(T::move_called == 1); // call threw
293 assert(T::move_assign_called == 0);
294 assert(std::get<0>(v1).value ==
295 42); // throw happened before v1 was moved from
296 assert(std::get<0>(v2).value == 100);
299 using T = ThrowingMoveAssignNothrowMoveCtor;
300 using V = std::variant<T, int>;
301 T::reset();
302 V v1(std::in_place_index<0>, 42);
303 V v2(std::in_place_index<0>, 100);
304 try {
305 v1.swap(v2);
306 assert(false);
307 } catch (int) {
309 assert(T::move_called == 1);
310 assert(T::move_assign_called == 1); // call threw and didn't complete
311 assert(std::get<0>(v1).value == -1); // v1 was moved from
312 assert(std::get<0>(v2).value == 100);
314 #endif
317 void test_swap_different_alternatives() {
319 using T = NothrowMoveCtorWithThrowingSwap;
320 using V = std::variant<T, int>;
321 T::reset();
322 V v1(std::in_place_index<0>, 42);
323 V v2(std::in_place_index<1>, 100);
324 v1.swap(v2);
325 assert(T::swap_called == 0);
326 // The libc++ implementation double copies the argument, and not
327 // the variant swap is called on.
328 LIBCPP_ASSERT(T::move_called == 1);
329 assert(T::move_called <= 2);
330 assert(T::move_assign_called == 0);
331 assert(std::get<1>(v1) == 100);
332 assert(std::get<0>(v2).value == 42);
333 T::reset();
334 swap(v1, v2);
335 assert(T::swap_called == 0);
336 LIBCPP_ASSERT(T::move_called == 2);
337 assert(T::move_called <= 2);
338 assert(T::move_assign_called == 0);
339 assert(std::get<0>(v1).value == 42);
340 assert(std::get<1>(v2) == 100);
342 #ifndef TEST_HAS_NO_EXCEPTIONS
344 using T1 = ThrowingTypeWithNothrowSwap;
345 using T2 = NonThrowingNonNoexceptType;
346 using V = std::variant<T1, T2>;
347 T1::reset();
348 T2::reset();
349 V v1(std::in_place_index<0>, 42);
350 V v2(std::in_place_index<1>, 100);
351 try {
352 v1.swap(v2);
353 assert(false);
354 } catch (int) {
356 assert(T1::swap_called == 0);
357 assert(T1::move_called == 1); // throws
358 assert(T1::move_assign_called == 0);
359 // FIXME: libc++ shouldn't move from T2 here.
360 LIBCPP_ASSERT(T2::move_called == 1);
361 assert(T2::move_called <= 1);
362 assert(std::get<0>(v1).value == 42);
363 if (T2::move_called != 0)
364 assert(v2.valueless_by_exception());
365 else
366 assert(std::get<1>(v2).value == 100);
369 using T1 = NonThrowingNonNoexceptType;
370 using T2 = ThrowingTypeWithNothrowSwap;
371 using V = std::variant<T1, T2>;
372 T1::reset();
373 T2::reset();
374 V v1(std::in_place_index<0>, 42);
375 V v2(std::in_place_index<1>, 100);
376 try {
377 v1.swap(v2);
378 assert(false);
379 } catch (int) {
381 LIBCPP_ASSERT(T1::move_called == 0);
382 assert(T1::move_called <= 1);
383 assert(T2::swap_called == 0);
384 assert(T2::move_called == 1); // throws
385 assert(T2::move_assign_called == 0);
386 if (T1::move_called != 0)
387 assert(v1.valueless_by_exception());
388 else
389 assert(std::get<0>(v1).value == 42);
390 assert(std::get<1>(v2).value == 100);
392 // FIXME: The tests below are just very libc++ specific
393 #ifdef _LIBCPP_VERSION
395 using T1 = ThrowsOnSecondMove;
396 using T2 = NonThrowingNonNoexceptType;
397 using V = std::variant<T1, T2>;
398 T2::reset();
399 V v1(std::in_place_index<0>, 42);
400 V v2(std::in_place_index<1>, 100);
401 v1.swap(v2);
402 assert(T2::move_called == 2);
403 assert(std::get<1>(v1).value == 100);
404 assert(std::get<0>(v2).value == 42);
405 assert(std::get<0>(v2).move_count == 1);
408 using T1 = NonThrowingNonNoexceptType;
409 using T2 = ThrowsOnSecondMove;
410 using V = std::variant<T1, T2>;
411 T1::reset();
412 V v1(std::in_place_index<0>, 42);
413 V v2(std::in_place_index<1>, 100);
414 try {
415 v1.swap(v2);
416 assert(false);
417 } catch (int) {
419 assert(T1::move_called == 1);
420 assert(v1.valueless_by_exception());
421 assert(std::get<0>(v2).value == 42);
423 #endif
424 // testing libc++ extension. If either variant stores a nothrow move
425 // constructible type v1.swap(v2) provides the strong exception safety
426 // guarantee.
427 #ifdef _LIBCPP_VERSION
430 using T1 = ThrowingTypeWithNothrowSwap;
431 using T2 = NothrowMoveable;
432 using V = std::variant<T1, T2>;
433 T1::reset();
434 T2::reset();
435 V v1(std::in_place_index<0>, 42);
436 V v2(std::in_place_index<1>, 100);
437 try {
438 v1.swap(v2);
439 assert(false);
440 } catch (int) {
442 assert(T1::swap_called == 0);
443 assert(T1::move_called == 1);
444 assert(T1::move_assign_called == 0);
445 assert(T2::swap_called == 0);
446 assert(T2::move_called == 2);
447 assert(T2::move_assign_called == 0);
448 assert(std::get<0>(v1).value == 42);
449 assert(std::get<1>(v2).value == 100);
450 // swap again, but call v2's swap.
451 T1::reset();
452 T2::reset();
453 try {
454 v2.swap(v1);
455 assert(false);
456 } catch (int) {
458 assert(T1::swap_called == 0);
459 assert(T1::move_called == 1);
460 assert(T1::move_assign_called == 0);
461 assert(T2::swap_called == 0);
462 assert(T2::move_called == 2);
463 assert(T2::move_assign_called == 0);
464 assert(std::get<0>(v1).value == 42);
465 assert(std::get<1>(v2).value == 100);
467 #endif // _LIBCPP_VERSION
468 #endif
471 template <class Var>
472 constexpr auto has_swap_member_imp(int)
473 -> decltype(std::declval<Var &>().swap(std::declval<Var &>()), true) {
474 return true;
477 template <class Var> constexpr auto has_swap_member_imp(long) -> bool {
478 return false;
481 template <class Var> constexpr bool has_swap_member() {
482 return has_swap_member_imp<Var>(0);
485 void test_swap_sfinae() {
487 // This variant type does not provide either a member or non-member swap
488 // but is still swappable via the generic swap algorithm, since the
489 // variant is move constructible and move assignable.
490 using V = std::variant<int, NotSwappable>;
491 LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
492 static_assert(std::is_swappable_v<V>, "");
495 using V = std::variant<int, NotCopyable>;
496 LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
497 static_assert(!std::is_swappable_v<V>, "");
500 using V = std::variant<int, NotCopyableWithSwap>;
501 LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
502 static_assert(!std::is_swappable_v<V>, "");
505 using V = std::variant<int, NotMoveAssignable>;
506 LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
507 static_assert(!std::is_swappable_v<V>, "");
511 void test_swap_noexcept() {
513 using V = std::variant<int, NothrowMoveable>;
514 static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
515 static_assert(std::is_nothrow_swappable_v<V>, "");
516 // instantiate swap
517 V v1, v2;
518 v1.swap(v2);
519 swap(v1, v2);
522 using V = std::variant<int, NothrowMoveCtor>;
523 static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
524 static_assert(!std::is_nothrow_swappable_v<V>, "");
525 // instantiate swap
526 V v1, v2;
527 v1.swap(v2);
528 swap(v1, v2);
531 using V = std::variant<int, ThrowingTypeWithNothrowSwap>;
532 static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
533 static_assert(!std::is_nothrow_swappable_v<V>, "");
534 // instantiate swap
535 V v1, v2;
536 v1.swap(v2);
537 swap(v1, v2);
540 using V = std::variant<int, ThrowingMoveAssignNothrowMoveCtor>;
541 static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
542 static_assert(!std::is_nothrow_swappable_v<V>, "");
543 // instantiate swap
544 V v1, v2;
545 v1.swap(v2);
546 swap(v1, v2);
549 using V = std::variant<int, ThrowingMoveAssignNothrowMoveCtorWithSwap>;
550 static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
551 static_assert(std::is_nothrow_swappable_v<V>, "");
552 // instantiate swap
553 V v1, v2;
554 v1.swap(v2);
555 swap(v1, v2);
558 using V = std::variant<int, NotMoveAssignableWithSwap>;
559 static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
560 static_assert(std::is_nothrow_swappable_v<V>, "");
561 // instantiate swap
562 V v1, v2;
563 v1.swap(v2);
564 swap(v1, v2);
567 // This variant type does not provide either a member or non-member swap
568 // but is still swappable via the generic swap algorithm, since the
569 // variant is move constructible and move assignable.
570 using V = std::variant<int, NotSwappable>;
571 LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
572 static_assert(std::is_swappable_v<V>, "");
573 static_assert(std::is_nothrow_swappable_v<V>, "");
574 V v1, v2;
575 swap(v1, v2);
579 #ifdef _LIBCPP_VERSION
580 // This is why variant should SFINAE member swap. :-)
581 template class std::variant<int, NotSwappable>;
582 #endif
584 int main(int, char**) {
585 test_swap_valueless_by_exception();
586 test_swap_same_alternative();
587 test_swap_different_alternatives();
588 test_swap_sfinae();
589 test_swap_noexcept();
591 return 0;