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