move.pass.cpp 15 KB

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