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