move.pass.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  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. // The following compilers don't generate constexpr special members correctly.
  11. // XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8
  12. // XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0
  13. // XFAIL: dylib-has-no-bad_variant_access
  14. // <variant>
  15. // template <class ...Types> class variant;
  16. // variant& operator=(variant&&) noexcept(see below); // constexpr in C++20
  17. #include <cassert>
  18. #include <string>
  19. #include <type_traits>
  20. #include <utility>
  21. #include <variant>
  22. #include "test_macros.h"
  23. #include "variant_test_helpers.hpp"
  24. struct NoCopy {
  25. NoCopy(const NoCopy &) = delete;
  26. NoCopy &operator=(const NoCopy &) = default;
  27. };
  28. struct CopyOnly {
  29. CopyOnly(const CopyOnly &) = default;
  30. CopyOnly(CopyOnly &&) = delete;
  31. CopyOnly &operator=(const CopyOnly &) = default;
  32. CopyOnly &operator=(CopyOnly &&) = delete;
  33. };
  34. struct MoveOnly {
  35. MoveOnly(const MoveOnly &) = delete;
  36. MoveOnly(MoveOnly &&) = default;
  37. MoveOnly &operator=(const MoveOnly &) = delete;
  38. MoveOnly &operator=(MoveOnly &&) = default;
  39. };
  40. struct MoveOnlyNT {
  41. MoveOnlyNT(const MoveOnlyNT &) = delete;
  42. MoveOnlyNT(MoveOnlyNT &&) {}
  43. MoveOnlyNT &operator=(const MoveOnlyNT &) = delete;
  44. MoveOnlyNT &operator=(MoveOnlyNT &&) = default;
  45. };
  46. struct MoveOnlyOddNothrow {
  47. MoveOnlyOddNothrow(MoveOnlyOddNothrow &&) noexcept(false) {}
  48. MoveOnlyOddNothrow(const MoveOnlyOddNothrow &) = delete;
  49. MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow &&) noexcept = default;
  50. MoveOnlyOddNothrow &operator=(const MoveOnlyOddNothrow &) = delete;
  51. };
  52. struct MoveAssignOnly {
  53. MoveAssignOnly(MoveAssignOnly &&) = delete;
  54. MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
  55. };
  56. struct MoveAssign {
  57. static int move_construct;
  58. static int move_assign;
  59. static void reset() { move_construct = move_assign = 0; }
  60. MoveAssign(int v) : value(v) {}
  61. MoveAssign(MoveAssign &&o) : value(o.value) {
  62. ++move_construct;
  63. o.value = -1;
  64. }
  65. MoveAssign &operator=(MoveAssign &&o) {
  66. value = o.value;
  67. ++move_assign;
  68. o.value = -1;
  69. return *this;
  70. }
  71. int value;
  72. };
  73. int MoveAssign::move_construct = 0;
  74. int MoveAssign::move_assign = 0;
  75. struct NTMoveAssign {
  76. constexpr NTMoveAssign(int v) : value(v) {}
  77. NTMoveAssign(const NTMoveAssign &) = default;
  78. NTMoveAssign(NTMoveAssign &&) = default;
  79. NTMoveAssign &operator=(const NTMoveAssign &that) = default;
  80. NTMoveAssign &operator=(NTMoveAssign &&that) {
  81. value = that.value;
  82. that.value = -1;
  83. return *this;
  84. };
  85. int value;
  86. };
  87. static_assert(!std::is_trivially_move_assignable<NTMoveAssign>::value, "");
  88. static_assert(std::is_move_assignable<NTMoveAssign>::value, "");
  89. struct TMoveAssign {
  90. constexpr TMoveAssign(int v) : value(v) {}
  91. TMoveAssign(const TMoveAssign &) = delete;
  92. TMoveAssign(TMoveAssign &&) = default;
  93. TMoveAssign &operator=(const TMoveAssign &) = delete;
  94. TMoveAssign &operator=(TMoveAssign &&) = default;
  95. int value;
  96. };
  97. static_assert(std::is_trivially_move_assignable<TMoveAssign>::value, "");
  98. struct TMoveAssignNTCopyAssign {
  99. constexpr TMoveAssignNTCopyAssign(int v) : value(v) {}
  100. TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default;
  101. TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default;
  102. TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) {
  103. value = that.value;
  104. return *this;
  105. }
  106. TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default;
  107. int value;
  108. };
  109. static_assert(std::is_trivially_move_assignable_v<TMoveAssignNTCopyAssign>, "");
  110. struct TrivialCopyNontrivialMove {
  111. TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default;
  112. TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {}
  113. TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default;
  114. TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept {
  115. return *this;
  116. }
  117. };
  118. static_assert(std::is_trivially_copy_assignable_v<TrivialCopyNontrivialMove>, "");
  119. static_assert(!std::is_trivially_move_assignable_v<TrivialCopyNontrivialMove>, "");
  120. void test_move_assignment_noexcept() {
  121. {
  122. using V = std::variant<int>;
  123. static_assert(std::is_nothrow_move_assignable<V>::value, "");
  124. }
  125. {
  126. using V = std::variant<MoveOnly>;
  127. static_assert(std::is_nothrow_move_assignable<V>::value, "");
  128. }
  129. {
  130. using V = std::variant<int, long>;
  131. static_assert(std::is_nothrow_move_assignable<V>::value, "");
  132. }
  133. {
  134. using V = std::variant<int, MoveOnly>;
  135. static_assert(std::is_nothrow_move_assignable<V>::value, "");
  136. }
  137. {
  138. using V = std::variant<MoveOnlyNT>;
  139. static_assert(!std::is_nothrow_move_assignable<V>::value, "");
  140. }
  141. {
  142. using V = std::variant<MoveOnlyOddNothrow>;
  143. static_assert(!std::is_nothrow_move_assignable<V>::value, "");
  144. }
  145. }
  146. void test_move_assignment_sfinae() {
  147. {
  148. using V = std::variant<int, long>;
  149. static_assert(std::is_move_assignable<V>::value, "");
  150. }
  151. {
  152. using V = std::variant<int, CopyOnly>;
  153. static_assert(std::is_move_assignable<V>::value, "");
  154. }
  155. {
  156. using V = std::variant<int, NoCopy>;
  157. static_assert(!std::is_move_assignable<V>::value, "");
  158. }
  159. {
  160. using V = std::variant<int, MoveOnly>;
  161. static_assert(std::is_move_assignable<V>::value, "");
  162. }
  163. {
  164. using V = std::variant<int, MoveOnlyNT>;
  165. static_assert(std::is_move_assignable<V>::value, "");
  166. }
  167. {
  168. // variant only provides move assignment when the types also provide
  169. // a move constructor.
  170. using V = std::variant<int, MoveAssignOnly>;
  171. static_assert(!std::is_move_assignable<V>::value, "");
  172. }
  173. // Make sure we properly propagate triviality (see P0602R4).
  174. #if TEST_STD_VER > 17
  175. {
  176. using V = std::variant<int, long>;
  177. static_assert(std::is_trivially_move_assignable<V>::value, "");
  178. }
  179. {
  180. using V = std::variant<int, NTMoveAssign>;
  181. static_assert(!std::is_trivially_move_assignable<V>::value, "");
  182. static_assert(std::is_move_assignable<V>::value, "");
  183. }
  184. {
  185. using V = std::variant<int, TMoveAssign>;
  186. static_assert(std::is_trivially_move_assignable<V>::value, "");
  187. }
  188. {
  189. using V = std::variant<int, TMoveAssignNTCopyAssign>;
  190. static_assert(std::is_trivially_move_assignable<V>::value, "");
  191. }
  192. {
  193. using V = std::variant<int, TrivialCopyNontrivialMove>;
  194. static_assert(!std::is_trivially_move_assignable<V>::value, "");
  195. }
  196. {
  197. using V = std::variant<int, CopyOnly>;
  198. static_assert(std::is_trivially_move_assignable<V>::value, "");
  199. }
  200. #endif // > C++17
  201. }
  202. void test_move_assignment_empty_empty() {
  203. #ifndef TEST_HAS_NO_EXCEPTIONS
  204. using MET = MakeEmptyT;
  205. {
  206. using V = std::variant<int, long, MET>;
  207. V v1(std::in_place_index<0>);
  208. makeEmpty(v1);
  209. V v2(std::in_place_index<0>);
  210. makeEmpty(v2);
  211. V &vref = (v1 = std::move(v2));
  212. assert(&vref == &v1);
  213. assert(v1.valueless_by_exception());
  214. assert(v1.index() == std::variant_npos);
  215. }
  216. #endif // TEST_HAS_NO_EXCEPTIONS
  217. }
  218. void test_move_assignment_non_empty_empty() {
  219. #ifndef TEST_HAS_NO_EXCEPTIONS
  220. using MET = MakeEmptyT;
  221. {
  222. using V = std::variant<int, MET>;
  223. V v1(std::in_place_index<0>, 42);
  224. V v2(std::in_place_index<0>);
  225. makeEmpty(v2);
  226. V &vref = (v1 = std::move(v2));
  227. assert(&vref == &v1);
  228. assert(v1.valueless_by_exception());
  229. assert(v1.index() == std::variant_npos);
  230. }
  231. {
  232. using V = std::variant<int, MET, std::string>;
  233. V v1(std::in_place_index<2>, "hello");
  234. V v2(std::in_place_index<0>);
  235. makeEmpty(v2);
  236. V &vref = (v1 = std::move(v2));
  237. assert(&vref == &v1);
  238. assert(v1.valueless_by_exception());
  239. assert(v1.index() == std::variant_npos);
  240. }
  241. #endif // TEST_HAS_NO_EXCEPTIONS
  242. }
  243. void test_move_assignment_empty_non_empty() {
  244. #ifndef TEST_HAS_NO_EXCEPTIONS
  245. using MET = MakeEmptyT;
  246. {
  247. using V = std::variant<int, MET>;
  248. V v1(std::in_place_index<0>);
  249. makeEmpty(v1);
  250. V v2(std::in_place_index<0>, 42);
  251. V &vref = (v1 = std::move(v2));
  252. assert(&vref == &v1);
  253. assert(v1.index() == 0);
  254. assert(std::get<0>(v1) == 42);
  255. }
  256. {
  257. using V = std::variant<int, MET, std::string>;
  258. V v1(std::in_place_index<0>);
  259. makeEmpty(v1);
  260. V v2(std::in_place_type<std::string>, "hello");
  261. V &vref = (v1 = std::move(v2));
  262. assert(&vref == &v1);
  263. assert(v1.index() == 2);
  264. assert(std::get<2>(v1) == "hello");
  265. }
  266. #endif // TEST_HAS_NO_EXCEPTIONS
  267. }
  268. template <typename T> struct Result { size_t index; T value; };
  269. void test_move_assignment_same_index() {
  270. {
  271. using V = std::variant<int>;
  272. V v1(43);
  273. V v2(42);
  274. V &vref = (v1 = std::move(v2));
  275. assert(&vref == &v1);
  276. assert(v1.index() == 0);
  277. assert(std::get<0>(v1) == 42);
  278. }
  279. {
  280. using V = std::variant<int, long, unsigned>;
  281. V v1(43l);
  282. V v2(42l);
  283. V &vref = (v1 = std::move(v2));
  284. assert(&vref == &v1);
  285. assert(v1.index() == 1);
  286. assert(std::get<1>(v1) == 42);
  287. }
  288. {
  289. using V = std::variant<int, MoveAssign, unsigned>;
  290. V v1(std::in_place_type<MoveAssign>, 43);
  291. V v2(std::in_place_type<MoveAssign>, 42);
  292. MoveAssign::reset();
  293. V &vref = (v1 = std::move(v2));
  294. assert(&vref == &v1);
  295. assert(v1.index() == 1);
  296. assert(std::get<1>(v1).value == 42);
  297. assert(MoveAssign::move_construct == 0);
  298. assert(MoveAssign::move_assign == 1);
  299. }
  300. #ifndef TEST_HAS_NO_EXCEPTIONS
  301. using MET = MakeEmptyT;
  302. {
  303. using V = std::variant<int, MET, std::string>;
  304. V v1(std::in_place_type<MET>);
  305. MET &mref = std::get<1>(v1);
  306. V v2(std::in_place_type<MET>);
  307. try {
  308. v1 = std::move(v2);
  309. assert(false);
  310. } catch (...) {
  311. }
  312. assert(v1.index() == 1);
  313. assert(&std::get<1>(v1) == &mref);
  314. }
  315. #endif // TEST_HAS_NO_EXCEPTIONS
  316. // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
  317. #if TEST_STD_VER > 17
  318. {
  319. struct {
  320. constexpr Result<int> operator()() const {
  321. using V = std::variant<int>;
  322. V v(43);
  323. V v2(42);
  324. v = std::move(v2);
  325. return {v.index(), std::get<0>(v)};
  326. }
  327. } test;
  328. constexpr auto result = test();
  329. static_assert(result.index == 0, "");
  330. static_assert(result.value == 42, "");
  331. }
  332. {
  333. struct {
  334. constexpr Result<long> operator()() const {
  335. using V = std::variant<int, long, unsigned>;
  336. V v(43l);
  337. V v2(42l);
  338. v = std::move(v2);
  339. return {v.index(), std::get<1>(v)};
  340. }
  341. } test;
  342. constexpr auto result = test();
  343. static_assert(result.index == 1, "");
  344. static_assert(result.value == 42l, "");
  345. }
  346. {
  347. struct {
  348. constexpr Result<int> operator()() const {
  349. using V = std::variant<int, TMoveAssign, unsigned>;
  350. V v(std::in_place_type<TMoveAssign>, 43);
  351. V v2(std::in_place_type<TMoveAssign>, 42);
  352. v = std::move(v2);
  353. return {v.index(), std::get<1>(v).value};
  354. }
  355. } test;
  356. constexpr auto result = test();
  357. static_assert(result.index == 1, "");
  358. static_assert(result.value == 42, "");
  359. }
  360. #endif // > C++17
  361. }
  362. void test_move_assignment_different_index() {
  363. {
  364. using V = std::variant<int, long, unsigned>;
  365. V v1(43);
  366. V v2(42l);
  367. V &vref = (v1 = std::move(v2));
  368. assert(&vref == &v1);
  369. assert(v1.index() == 1);
  370. assert(std::get<1>(v1) == 42);
  371. }
  372. {
  373. using V = std::variant<int, MoveAssign, unsigned>;
  374. V v1(std::in_place_type<unsigned>, 43);
  375. V v2(std::in_place_type<MoveAssign>, 42);
  376. MoveAssign::reset();
  377. V &vref = (v1 = std::move(v2));
  378. assert(&vref == &v1);
  379. assert(v1.index() == 1);
  380. assert(std::get<1>(v1).value == 42);
  381. assert(MoveAssign::move_construct == 1);
  382. assert(MoveAssign::move_assign == 0);
  383. }
  384. #ifndef TEST_HAS_NO_EXCEPTIONS
  385. using MET = MakeEmptyT;
  386. {
  387. using V = std::variant<int, MET, std::string>;
  388. V v1(std::in_place_type<int>);
  389. V v2(std::in_place_type<MET>);
  390. try {
  391. v1 = std::move(v2);
  392. assert(false);
  393. } catch (...) {
  394. }
  395. assert(v1.valueless_by_exception());
  396. assert(v1.index() == std::variant_npos);
  397. }
  398. {
  399. using V = std::variant<int, MET, std::string>;
  400. V v1(std::in_place_type<MET>);
  401. V v2(std::in_place_type<std::string>, "hello");
  402. V &vref = (v1 = std::move(v2));
  403. assert(&vref == &v1);
  404. assert(v1.index() == 2);
  405. assert(std::get<2>(v1) == "hello");
  406. }
  407. #endif // TEST_HAS_NO_EXCEPTIONS
  408. // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
  409. #if TEST_STD_VER > 17
  410. {
  411. struct {
  412. constexpr Result<long> operator()() const {
  413. using V = std::variant<int, long, unsigned>;
  414. V v(43);
  415. V v2(42l);
  416. v = std::move(v2);
  417. return {v.index(), std::get<1>(v)};
  418. }
  419. } test;
  420. constexpr auto result = test();
  421. static_assert(result.index == 1, "");
  422. static_assert(result.value == 42l, "");
  423. }
  424. {
  425. struct {
  426. constexpr Result<long> operator()() const {
  427. using V = std::variant<int, TMoveAssign, unsigned>;
  428. V v(std::in_place_type<unsigned>, 43);
  429. V v2(std::in_place_type<TMoveAssign>, 42);
  430. v = std::move(v2);
  431. return {v.index(), std::get<1>(v).value};
  432. }
  433. } test;
  434. constexpr auto result = test();
  435. static_assert(result.index == 1, "");
  436. static_assert(result.value == 42, "");
  437. }
  438. #endif // > C++17
  439. }
  440. template <size_t NewIdx, class ValueType>
  441. constexpr bool test_constexpr_assign_imp(
  442. std::variant<long, void*, int>&& v, ValueType&& new_value)
  443. {
  444. std::variant<long, void*, int> v2(
  445. std::forward<ValueType>(new_value));
  446. const auto cp = v2;
  447. v = std::move(v2);
  448. return v.index() == NewIdx &&
  449. std::get<NewIdx>(v) == std::get<NewIdx>(cp);
  450. }
  451. void test_constexpr_move_assignment() {
  452. // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
  453. #if TEST_STD_VER > 17
  454. using V = std::variant<long, void*, int>;
  455. static_assert(std::is_trivially_copyable<V>::value, "");
  456. static_assert(std::is_trivially_move_assignable<V>::value, "");
  457. static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), "");
  458. static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), "");
  459. static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), "");
  460. static_assert(test_constexpr_assign_imp<2>(V(42l), 101), "");
  461. #endif // > C++17
  462. }
  463. int main(int, char**) {
  464. test_move_assignment_empty_empty();
  465. test_move_assignment_non_empty_empty();
  466. test_move_assignment_empty_non_empty();
  467. test_move_assignment_same_index();
  468. test_move_assignment_different_index();
  469. test_move_assignment_sfinae();
  470. test_move_assignment_noexcept();
  471. test_constexpr_move_assignment();
  472. return 0;
  473. }