swap.pass.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. // -*- C++ -*-
  2. //===----------------------------------------------------------------------===//
  3. //
  4. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  5. // See https://llvm.org/LICENSE.txt for license information.
  6. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  7. //
  8. //===----------------------------------------------------------------------===//
  9. // UNSUPPORTED: c++98, c++03, c++11, c++14
  10. // XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions
  11. // <variant>
  12. // template <class ...Types> class variant;
  13. // void swap(variant& rhs) noexcept(see below)
  14. #include <cassert>
  15. #include <string>
  16. #include <type_traits>
  17. #include <variant>
  18. #include "test_convertible.h"
  19. #include "test_macros.h"
  20. #include "variant_test_helpers.h"
  21. struct NotSwappable {};
  22. void swap(NotSwappable &, NotSwappable &) = delete;
  23. struct NotCopyable {
  24. NotCopyable() = default;
  25. NotCopyable(const NotCopyable &) = delete;
  26. NotCopyable &operator=(const NotCopyable &) = delete;
  27. };
  28. struct NotCopyableWithSwap {
  29. NotCopyableWithSwap() = default;
  30. NotCopyableWithSwap(const NotCopyableWithSwap &) = delete;
  31. NotCopyableWithSwap &operator=(const NotCopyableWithSwap &) = delete;
  32. };
  33. void swap(NotCopyableWithSwap &, NotCopyableWithSwap) {}
  34. struct NotMoveAssignable {
  35. NotMoveAssignable() = default;
  36. NotMoveAssignable(NotMoveAssignable &&) = default;
  37. NotMoveAssignable &operator=(NotMoveAssignable &&) = delete;
  38. };
  39. struct NotMoveAssignableWithSwap {
  40. NotMoveAssignableWithSwap() = default;
  41. NotMoveAssignableWithSwap(NotMoveAssignableWithSwap &&) = default;
  42. NotMoveAssignableWithSwap &operator=(NotMoveAssignableWithSwap &&) = delete;
  43. };
  44. void swap(NotMoveAssignableWithSwap &, NotMoveAssignableWithSwap &) noexcept {}
  45. template <bool Throws> void do_throw() {}
  46. template <> void do_throw<true>() {
  47. #ifndef TEST_HAS_NO_EXCEPTIONS
  48. throw 42;
  49. #else
  50. std::abort();
  51. #endif
  52. }
  53. template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
  54. bool NT_Swap, bool EnableSwap = true>
  55. struct NothrowTypeImp {
  56. static int move_called;
  57. static int move_assign_called;
  58. static int swap_called;
  59. static void reset() { move_called = move_assign_called = swap_called = 0; }
  60. NothrowTypeImp() = default;
  61. explicit NothrowTypeImp(int v) : value(v) {}
  62. NothrowTypeImp(const NothrowTypeImp &o) noexcept(NT_Copy) : value(o.value) {
  63. assert(false);
  64. } // never called by test
  65. NothrowTypeImp(NothrowTypeImp &&o) noexcept(NT_Move) : value(o.value) {
  66. ++move_called;
  67. do_throw<!NT_Move>();
  68. o.value = -1;
  69. }
  70. NothrowTypeImp &operator=(const NothrowTypeImp &) noexcept(NT_CopyAssign) {
  71. assert(false);
  72. return *this;
  73. } // never called by the tests
  74. NothrowTypeImp &operator=(NothrowTypeImp &&o) noexcept(NT_MoveAssign) {
  75. ++move_assign_called;
  76. do_throw<!NT_MoveAssign>();
  77. value = o.value;
  78. o.value = -1;
  79. return *this;
  80. }
  81. int value;
  82. };
  83. template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
  84. bool NT_Swap, bool EnableSwap>
  85. int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
  86. EnableSwap>::move_called = 0;
  87. template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
  88. bool NT_Swap, bool EnableSwap>
  89. int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
  90. EnableSwap>::move_assign_called = 0;
  91. template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
  92. bool NT_Swap, bool EnableSwap>
  93. int NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign, NT_Swap,
  94. EnableSwap>::swap_called = 0;
  95. template <bool NT_Copy, bool NT_Move, bool NT_CopyAssign, bool NT_MoveAssign,
  96. bool NT_Swap>
  97. void swap(NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign,
  98. NT_Swap, true> &lhs,
  99. NothrowTypeImp<NT_Copy, NT_Move, NT_CopyAssign, NT_MoveAssign,
  100. NT_Swap, true> &rhs) noexcept(NT_Swap) {
  101. lhs.swap_called++;
  102. do_throw<!NT_Swap>();
  103. int tmp = lhs.value;
  104. lhs.value = rhs.value;
  105. rhs.value = tmp;
  106. }
  107. // throwing copy, nothrow move ctor/assign, no swap provided
  108. using NothrowMoveable = NothrowTypeImp<false, true, false, true, false, false>;
  109. // throwing copy and move assign, nothrow move ctor, no swap provided
  110. using NothrowMoveCtor = NothrowTypeImp<false, true, false, false, false, false>;
  111. // nothrow move ctor, throwing move assignment, swap provided
  112. using NothrowMoveCtorWithThrowingSwap =
  113. NothrowTypeImp<false, true, false, false, false, true>;
  114. // throwing move ctor, nothrow move assignment, no swap provided
  115. using ThrowingMoveCtor =
  116. NothrowTypeImp<false, false, false, true, false, false>;
  117. // throwing special members, nothrowing swap
  118. using ThrowingTypeWithNothrowSwap =
  119. NothrowTypeImp<false, false, false, false, true, true>;
  120. using NothrowTypeWithThrowingSwap =
  121. NothrowTypeImp<true, true, true, true, false, true>;
  122. // throwing move assign with nothrow move and nothrow swap
  123. using ThrowingMoveAssignNothrowMoveCtorWithSwap =
  124. NothrowTypeImp<false, true, false, false, true, true>;
  125. // throwing move assign with nothrow move but no swap.
  126. using ThrowingMoveAssignNothrowMoveCtor =
  127. NothrowTypeImp<false, true, false, false, false, false>;
  128. struct NonThrowingNonNoexceptType {
  129. static int move_called;
  130. static void reset() { move_called = 0; }
  131. NonThrowingNonNoexceptType() = default;
  132. NonThrowingNonNoexceptType(int v) : value(v) {}
  133. NonThrowingNonNoexceptType(NonThrowingNonNoexceptType &&o) noexcept(false)
  134. : value(o.value) {
  135. ++move_called;
  136. o.value = -1;
  137. }
  138. NonThrowingNonNoexceptType &
  139. operator=(NonThrowingNonNoexceptType &&) noexcept(false) {
  140. assert(false); // never called by the tests.
  141. return *this;
  142. }
  143. int value;
  144. };
  145. int NonThrowingNonNoexceptType::move_called = 0;
  146. struct ThrowsOnSecondMove {
  147. int value;
  148. int move_count;
  149. ThrowsOnSecondMove(int v) : value(v), move_count(0) {}
  150. ThrowsOnSecondMove(ThrowsOnSecondMove &&o) noexcept(false)
  151. : value(o.value), move_count(o.move_count + 1) {
  152. if (move_count == 2)
  153. do_throw<true>();
  154. o.value = -1;
  155. }
  156. ThrowsOnSecondMove &operator=(ThrowsOnSecondMove &&) {
  157. assert(false); // not called by test
  158. return *this;
  159. }
  160. };
  161. void test_swap_valueless_by_exception() {
  162. #ifndef TEST_HAS_NO_EXCEPTIONS
  163. using V = std::variant<int, MakeEmptyT>;
  164. { // both empty
  165. V v1;
  166. makeEmpty(v1);
  167. V v2;
  168. makeEmpty(v2);
  169. assert(MakeEmptyT::alive == 0);
  170. { // member swap
  171. v1.swap(v2);
  172. assert(v1.valueless_by_exception());
  173. assert(v2.valueless_by_exception());
  174. assert(MakeEmptyT::alive == 0);
  175. }
  176. { // non-member swap
  177. swap(v1, v2);
  178. assert(v1.valueless_by_exception());
  179. assert(v2.valueless_by_exception());
  180. assert(MakeEmptyT::alive == 0);
  181. }
  182. }
  183. { // only one empty
  184. V v1(42);
  185. V v2;
  186. makeEmpty(v2);
  187. { // member swap
  188. v1.swap(v2);
  189. assert(v1.valueless_by_exception());
  190. assert(std::get<0>(v2) == 42);
  191. // swap again
  192. v2.swap(v1);
  193. assert(v2.valueless_by_exception());
  194. assert(std::get<0>(v1) == 42);
  195. }
  196. { // non-member swap
  197. swap(v1, v2);
  198. assert(v1.valueless_by_exception());
  199. assert(std::get<0>(v2) == 42);
  200. // swap again
  201. swap(v1, v2);
  202. assert(v2.valueless_by_exception());
  203. assert(std::get<0>(v1) == 42);
  204. }
  205. }
  206. #endif
  207. }
  208. void test_swap_same_alternative() {
  209. {
  210. using T = ThrowingTypeWithNothrowSwap;
  211. using V = std::variant<T, int>;
  212. T::reset();
  213. V v1(std::in_place_index<0>, 42);
  214. V v2(std::in_place_index<0>, 100);
  215. v1.swap(v2);
  216. assert(T::swap_called == 1);
  217. assert(std::get<0>(v1).value == 100);
  218. assert(std::get<0>(v2).value == 42);
  219. swap(v1, v2);
  220. assert(T::swap_called == 2);
  221. assert(std::get<0>(v1).value == 42);
  222. assert(std::get<0>(v2).value == 100);
  223. }
  224. {
  225. using T = NothrowMoveable;
  226. using V = std::variant<T, int>;
  227. T::reset();
  228. V v1(std::in_place_index<0>, 42);
  229. V v2(std::in_place_index<0>, 100);
  230. v1.swap(v2);
  231. assert(T::swap_called == 0);
  232. assert(T::move_called == 1);
  233. assert(T::move_assign_called == 2);
  234. assert(std::get<0>(v1).value == 100);
  235. assert(std::get<0>(v2).value == 42);
  236. T::reset();
  237. swap(v1, v2);
  238. assert(T::swap_called == 0);
  239. assert(T::move_called == 1);
  240. assert(T::move_assign_called == 2);
  241. assert(std::get<0>(v1).value == 42);
  242. assert(std::get<0>(v2).value == 100);
  243. }
  244. #ifndef TEST_HAS_NO_EXCEPTIONS
  245. {
  246. using T = NothrowTypeWithThrowingSwap;
  247. using V = std::variant<T, int>;
  248. T::reset();
  249. V v1(std::in_place_index<0>, 42);
  250. V v2(std::in_place_index<0>, 100);
  251. try {
  252. v1.swap(v2);
  253. assert(false);
  254. } catch (int) {
  255. }
  256. assert(T::swap_called == 1);
  257. assert(T::move_called == 0);
  258. assert(T::move_assign_called == 0);
  259. assert(std::get<0>(v1).value == 42);
  260. assert(std::get<0>(v2).value == 100);
  261. }
  262. {
  263. using T = ThrowingMoveCtor;
  264. using V = std::variant<T, int>;
  265. T::reset();
  266. V v1(std::in_place_index<0>, 42);
  267. V v2(std::in_place_index<0>, 100);
  268. try {
  269. v1.swap(v2);
  270. assert(false);
  271. } catch (int) {
  272. }
  273. assert(T::move_called == 1); // call threw
  274. assert(T::move_assign_called == 0);
  275. assert(std::get<0>(v1).value ==
  276. 42); // throw happened before v1 was moved from
  277. assert(std::get<0>(v2).value == 100);
  278. }
  279. {
  280. using T = ThrowingMoveAssignNothrowMoveCtor;
  281. using V = std::variant<T, int>;
  282. T::reset();
  283. V v1(std::in_place_index<0>, 42);
  284. V v2(std::in_place_index<0>, 100);
  285. try {
  286. v1.swap(v2);
  287. assert(false);
  288. } catch (int) {
  289. }
  290. assert(T::move_called == 1);
  291. assert(T::move_assign_called == 1); // call threw and didn't complete
  292. assert(std::get<0>(v1).value == -1); // v1 was moved from
  293. assert(std::get<0>(v2).value == 100);
  294. }
  295. #endif
  296. }
  297. void test_swap_different_alternatives() {
  298. {
  299. using T = NothrowMoveCtorWithThrowingSwap;
  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<1>, 100);
  304. v1.swap(v2);
  305. assert(T::swap_called == 0);
  306. // The libc++ implementation double copies the argument, and not
  307. // the variant swap is called on.
  308. LIBCPP_ASSERT(T::move_called == 1);
  309. assert(T::move_called <= 2);
  310. assert(T::move_assign_called == 0);
  311. assert(std::get<1>(v1) == 100);
  312. assert(std::get<0>(v2).value == 42);
  313. T::reset();
  314. swap(v1, v2);
  315. assert(T::swap_called == 0);
  316. LIBCPP_ASSERT(T::move_called == 2);
  317. assert(T::move_called <= 2);
  318. assert(T::move_assign_called == 0);
  319. assert(std::get<0>(v1).value == 42);
  320. assert(std::get<1>(v2) == 100);
  321. }
  322. #ifndef TEST_HAS_NO_EXCEPTIONS
  323. {
  324. using T1 = ThrowingTypeWithNothrowSwap;
  325. using T2 = NonThrowingNonNoexceptType;
  326. using V = std::variant<T1, T2>;
  327. T1::reset();
  328. T2::reset();
  329. V v1(std::in_place_index<0>, 42);
  330. V v2(std::in_place_index<1>, 100);
  331. try {
  332. v1.swap(v2);
  333. assert(false);
  334. } catch (int) {
  335. }
  336. assert(T1::swap_called == 0);
  337. assert(T1::move_called == 1); // throws
  338. assert(T1::move_assign_called == 0);
  339. // FIXME: libc++ shouldn't move from T2 here.
  340. LIBCPP_ASSERT(T2::move_called == 1);
  341. assert(T2::move_called <= 1);
  342. assert(std::get<0>(v1).value == 42);
  343. if (T2::move_called != 0)
  344. assert(v2.valueless_by_exception());
  345. else
  346. assert(std::get<1>(v2).value == 100);
  347. }
  348. {
  349. using T1 = NonThrowingNonNoexceptType;
  350. using T2 = ThrowingTypeWithNothrowSwap;
  351. using V = std::variant<T1, T2>;
  352. T1::reset();
  353. T2::reset();
  354. V v1(std::in_place_index<0>, 42);
  355. V v2(std::in_place_index<1>, 100);
  356. try {
  357. v1.swap(v2);
  358. assert(false);
  359. } catch (int) {
  360. }
  361. LIBCPP_ASSERT(T1::move_called == 0);
  362. assert(T1::move_called <= 1);
  363. assert(T2::swap_called == 0);
  364. assert(T2::move_called == 1); // throws
  365. assert(T2::move_assign_called == 0);
  366. if (T1::move_called != 0)
  367. assert(v1.valueless_by_exception());
  368. else
  369. assert(std::get<0>(v1).value == 42);
  370. assert(std::get<1>(v2).value == 100);
  371. }
  372. // FIXME: The tests below are just very libc++ specific
  373. #ifdef _LIBCPP_VERSION
  374. {
  375. using T1 = ThrowsOnSecondMove;
  376. using T2 = NonThrowingNonNoexceptType;
  377. using V = std::variant<T1, T2>;
  378. T2::reset();
  379. V v1(std::in_place_index<0>, 42);
  380. V v2(std::in_place_index<1>, 100);
  381. v1.swap(v2);
  382. assert(T2::move_called == 2);
  383. assert(std::get<1>(v1).value == 100);
  384. assert(std::get<0>(v2).value == 42);
  385. assert(std::get<0>(v2).move_count == 1);
  386. }
  387. {
  388. using T1 = NonThrowingNonNoexceptType;
  389. using T2 = ThrowsOnSecondMove;
  390. using V = std::variant<T1, T2>;
  391. T1::reset();
  392. V v1(std::in_place_index<0>, 42);
  393. V v2(std::in_place_index<1>, 100);
  394. try {
  395. v1.swap(v2);
  396. assert(false);
  397. } catch (int) {
  398. }
  399. assert(T1::move_called == 1);
  400. assert(v1.valueless_by_exception());
  401. assert(std::get<0>(v2).value == 42);
  402. }
  403. #endif
  404. // testing libc++ extension. If either variant stores a nothrow move
  405. // constructible type v1.swap(v2) provides the strong exception safety
  406. // guarantee.
  407. #ifdef _LIBCPP_VERSION
  408. {
  409. using T1 = ThrowingTypeWithNothrowSwap;
  410. using T2 = NothrowMoveable;
  411. using V = std::variant<T1, T2>;
  412. T1::reset();
  413. T2::reset();
  414. V v1(std::in_place_index<0>, 42);
  415. V v2(std::in_place_index<1>, 100);
  416. try {
  417. v1.swap(v2);
  418. assert(false);
  419. } catch (int) {
  420. }
  421. assert(T1::swap_called == 0);
  422. assert(T1::move_called == 1);
  423. assert(T1::move_assign_called == 0);
  424. assert(T2::swap_called == 0);
  425. assert(T2::move_called == 2);
  426. assert(T2::move_assign_called == 0);
  427. assert(std::get<0>(v1).value == 42);
  428. assert(std::get<1>(v2).value == 100);
  429. // swap again, but call v2's swap.
  430. T1::reset();
  431. T2::reset();
  432. try {
  433. v2.swap(v1);
  434. assert(false);
  435. } catch (int) {
  436. }
  437. assert(T1::swap_called == 0);
  438. assert(T1::move_called == 1);
  439. assert(T1::move_assign_called == 0);
  440. assert(T2::swap_called == 0);
  441. assert(T2::move_called == 2);
  442. assert(T2::move_assign_called == 0);
  443. assert(std::get<0>(v1).value == 42);
  444. assert(std::get<1>(v2).value == 100);
  445. }
  446. #endif // _LIBCPP_VERSION
  447. #endif
  448. }
  449. template <class Var>
  450. constexpr auto has_swap_member_imp(int)
  451. -> decltype(std::declval<Var &>().swap(std::declval<Var &>()), true) {
  452. return true;
  453. }
  454. template <class Var> constexpr auto has_swap_member_imp(long) -> bool {
  455. return false;
  456. }
  457. template <class Var> constexpr bool has_swap_member() {
  458. return has_swap_member_imp<Var>(0);
  459. }
  460. void test_swap_sfinae() {
  461. {
  462. // This variant type does not provide either a member or non-member swap
  463. // but is still swappable via the generic swap algorithm, since the
  464. // variant is move constructible and move assignable.
  465. using V = std::variant<int, NotSwappable>;
  466. LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
  467. static_assert(std::is_swappable_v<V>, "");
  468. }
  469. {
  470. using V = std::variant<int, NotCopyable>;
  471. LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
  472. static_assert(!std::is_swappable_v<V>, "");
  473. }
  474. {
  475. using V = std::variant<int, NotCopyableWithSwap>;
  476. LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
  477. static_assert(!std::is_swappable_v<V>, "");
  478. }
  479. {
  480. using V = std::variant<int, NotMoveAssignable>;
  481. LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
  482. static_assert(!std::is_swappable_v<V>, "");
  483. }
  484. }
  485. void test_swap_noexcept() {
  486. {
  487. using V = std::variant<int, NothrowMoveable>;
  488. static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
  489. static_assert(std::is_nothrow_swappable_v<V>, "");
  490. // instantiate swap
  491. V v1, v2;
  492. v1.swap(v2);
  493. swap(v1, v2);
  494. }
  495. {
  496. using V = std::variant<int, NothrowMoveCtor>;
  497. static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
  498. static_assert(!std::is_nothrow_swappable_v<V>, "");
  499. // instantiate swap
  500. V v1, v2;
  501. v1.swap(v2);
  502. swap(v1, v2);
  503. }
  504. {
  505. using V = std::variant<int, ThrowingTypeWithNothrowSwap>;
  506. static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
  507. static_assert(!std::is_nothrow_swappable_v<V>, "");
  508. // instantiate swap
  509. V v1, v2;
  510. v1.swap(v2);
  511. swap(v1, v2);
  512. }
  513. {
  514. using V = std::variant<int, ThrowingMoveAssignNothrowMoveCtor>;
  515. static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
  516. static_assert(!std::is_nothrow_swappable_v<V>, "");
  517. // instantiate swap
  518. V v1, v2;
  519. v1.swap(v2);
  520. swap(v1, v2);
  521. }
  522. {
  523. using V = std::variant<int, ThrowingMoveAssignNothrowMoveCtorWithSwap>;
  524. static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
  525. static_assert(std::is_nothrow_swappable_v<V>, "");
  526. // instantiate swap
  527. V v1, v2;
  528. v1.swap(v2);
  529. swap(v1, v2);
  530. }
  531. {
  532. using V = std::variant<int, NotMoveAssignableWithSwap>;
  533. static_assert(std::is_swappable_v<V> && has_swap_member<V>(), "");
  534. static_assert(std::is_nothrow_swappable_v<V>, "");
  535. // instantiate swap
  536. V v1, v2;
  537. v1.swap(v2);
  538. swap(v1, v2);
  539. }
  540. {
  541. // This variant type does not provide either a member or non-member swap
  542. // but is still swappable via the generic swap algorithm, since the
  543. // variant is move constructible and move assignable.
  544. using V = std::variant<int, NotSwappable>;
  545. LIBCPP_STATIC_ASSERT(!has_swap_member<V>(), "");
  546. static_assert(std::is_swappable_v<V>, "");
  547. static_assert(std::is_nothrow_swappable_v<V>, "");
  548. V v1, v2;
  549. swap(v1, v2);
  550. }
  551. }
  552. #ifdef _LIBCPP_VERSION
  553. // This is why variant should SFINAE member swap. :-)
  554. template class std::variant<int, NotSwappable>;
  555. #endif
  556. int main(int, char**) {
  557. test_swap_valueless_by_exception();
  558. test_swap_same_alternative();
  559. test_swap_different_alternatives();
  560. test_swap_sfinae();
  561. test_swap_noexcept();
  562. return 0;
  563. }