]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
Vendor import of libc++ trunk r302418:
[FreeBSD/FreeBSD.git] / test / std / utilities / variant / variant.variant / variant.assign / move.pass.cpp
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 // XFAIL: with_system_cxx_lib=macosx10.12
14 // XFAIL: with_system_cxx_lib=macosx10.11
15 // XFAIL: with_system_cxx_lib=macosx10.10
16 // XFAIL: with_system_cxx_lib=macosx10.9
17 // XFAIL: with_system_cxx_lib=macosx10.7
18 // XFAIL: with_system_cxx_lib=macosx10.8
19
20 // <variant>
21
22 // template <class ...Types> class variant;
23
24 // variant& operator=(variant&&) noexcept(see below);
25
26 #include <cassert>
27 #include <string>
28 #include <type_traits>
29 #include <utility>
30 #include <variant>
31
32 #include "test_macros.h"
33 #include "variant_test_helpers.hpp"
34
35 struct NoCopy {
36   NoCopy(const NoCopy &) = delete;
37   NoCopy &operator=(const NoCopy &) = default;
38 };
39
40 struct CopyOnly {
41   CopyOnly(const CopyOnly &) = default;
42   CopyOnly(CopyOnly &&) = delete;
43   CopyOnly &operator=(const CopyOnly &) = default;
44   CopyOnly &operator=(CopyOnly &&) = delete;
45 };
46
47 struct MoveOnly {
48   MoveOnly(const MoveOnly &) = delete;
49   MoveOnly(MoveOnly &&) = default;
50   MoveOnly &operator=(const MoveOnly &) = delete;
51   MoveOnly &operator=(MoveOnly &&) = default;
52 };
53
54 struct MoveOnlyNT {
55   MoveOnlyNT(const MoveOnlyNT &) = delete;
56   MoveOnlyNT(MoveOnlyNT &&) {}
57   MoveOnlyNT &operator=(const MoveOnlyNT &) = delete;
58   MoveOnlyNT &operator=(MoveOnlyNT &&) = default;
59 };
60
61 struct MoveOnlyOddNothrow {
62   MoveOnlyOddNothrow(MoveOnlyOddNothrow &&) noexcept(false) {}
63   MoveOnlyOddNothrow(const MoveOnlyOddNothrow &) = delete;
64   MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow &&) noexcept = default;
65   MoveOnlyOddNothrow &operator=(const MoveOnlyOddNothrow &) = delete;
66 };
67
68 struct MoveAssignOnly {
69   MoveAssignOnly(MoveAssignOnly &&) = delete;
70   MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
71 };
72
73 struct MoveAssign {
74   static int move_construct;
75   static int move_assign;
76   static void reset() { move_construct = move_assign = 0; }
77   MoveAssign(int v) : value(v) {}
78   MoveAssign(MoveAssign &&o) : value(o.value) {
79     ++move_construct;
80     o.value = -1;
81   }
82   MoveAssign &operator=(MoveAssign &&o) {
83     value = o.value;
84     ++move_assign;
85     o.value = -1;
86     return *this;
87   }
88   int value;
89 };
90
91 int MoveAssign::move_construct = 0;
92 int MoveAssign::move_assign = 0;
93
94 void test_move_assignment_noexcept() {
95   {
96     using V = std::variant<int>;
97     static_assert(std::is_nothrow_move_assignable<V>::value, "");
98   }
99   {
100     using V = std::variant<MoveOnly>;
101     static_assert(std::is_nothrow_move_assignable<V>::value, "");
102   }
103   {
104     using V = std::variant<int, long>;
105     static_assert(std::is_nothrow_move_assignable<V>::value, "");
106   }
107   {
108     using V = std::variant<int, MoveOnly>;
109     static_assert(std::is_nothrow_move_assignable<V>::value, "");
110   }
111   {
112     using V = std::variant<MoveOnlyNT>;
113     static_assert(!std::is_nothrow_move_assignable<V>::value, "");
114   }
115   {
116     using V = std::variant<MoveOnlyOddNothrow>;
117     static_assert(!std::is_nothrow_move_assignable<V>::value, "");
118   }
119 }
120
121 void test_move_assignment_sfinae() {
122   {
123     using V = std::variant<int, long>;
124     static_assert(std::is_move_assignable<V>::value, "");
125   }
126   {
127     // variant only provides move assignment when both the move constructor
128     // and move assignment operator are well formed.
129     using V = std::variant<int, CopyOnly>;
130     static_assert(!std::is_move_assignable<V>::value, "");
131   }
132   {
133     using V = std::variant<int, NoCopy>;
134     static_assert(!std::is_move_assignable<V>::value, "");
135   }
136   {
137     using V = std::variant<int, MoveOnly>;
138     static_assert(std::is_move_assignable<V>::value, "");
139   }
140   {
141     using V = std::variant<int, MoveOnlyNT>;
142     static_assert(std::is_move_assignable<V>::value, "");
143   }
144   {
145     // variant only provides move assignment when the types also provide
146     // a move constructor.
147     using V = std::variant<int, MoveAssignOnly>;
148     static_assert(!std::is_move_assignable<V>::value, "");
149   }
150 }
151
152 void test_move_assignment_empty_empty() {
153 #ifndef TEST_HAS_NO_EXCEPTIONS
154   using MET = MakeEmptyT;
155   {
156     using V = std::variant<int, long, MET>;
157     V v1(std::in_place_index<0>);
158     makeEmpty(v1);
159     V v2(std::in_place_index<0>);
160     makeEmpty(v2);
161     V &vref = (v1 = std::move(v2));
162     assert(&vref == &v1);
163     assert(v1.valueless_by_exception());
164     assert(v1.index() == std::variant_npos);
165   }
166 #endif
167 }
168
169 void test_move_assignment_non_empty_empty() {
170 #ifndef TEST_HAS_NO_EXCEPTIONS
171   using MET = MakeEmptyT;
172   {
173     using V = std::variant<int, MET>;
174     V v1(std::in_place_index<0>, 42);
175     V v2(std::in_place_index<0>);
176     makeEmpty(v2);
177     V &vref = (v1 = std::move(v2));
178     assert(&vref == &v1);
179     assert(v1.valueless_by_exception());
180     assert(v1.index() == std::variant_npos);
181   }
182   {
183     using V = std::variant<int, MET, std::string>;
184     V v1(std::in_place_index<2>, "hello");
185     V v2(std::in_place_index<0>);
186     makeEmpty(v2);
187     V &vref = (v1 = std::move(v2));
188     assert(&vref == &v1);
189     assert(v1.valueless_by_exception());
190     assert(v1.index() == std::variant_npos);
191   }
192 #endif
193 }
194
195 void test_move_assignment_empty_non_empty() {
196 #ifndef TEST_HAS_NO_EXCEPTIONS
197   using MET = MakeEmptyT;
198   {
199     using V = std::variant<int, MET>;
200     V v1(std::in_place_index<0>);
201     makeEmpty(v1);
202     V v2(std::in_place_index<0>, 42);
203     V &vref = (v1 = std::move(v2));
204     assert(&vref == &v1);
205     assert(v1.index() == 0);
206     assert(std::get<0>(v1) == 42);
207   }
208   {
209     using V = std::variant<int, MET, std::string>;
210     V v1(std::in_place_index<0>);
211     makeEmpty(v1);
212     V v2(std::in_place_type<std::string>, "hello");
213     V &vref = (v1 = std::move(v2));
214     assert(&vref == &v1);
215     assert(v1.index() == 2);
216     assert(std::get<2>(v1) == "hello");
217   }
218 #endif
219 }
220
221 void test_move_assignment_same_index() {
222   {
223     using V = std::variant<int>;
224     V v1(43);
225     V v2(42);
226     V &vref = (v1 = std::move(v2));
227     assert(&vref == &v1);
228     assert(v1.index() == 0);
229     assert(std::get<0>(v1) == 42);
230   }
231   {
232     using V = std::variant<int, long, unsigned>;
233     V v1(43l);
234     V v2(42l);
235     V &vref = (v1 = std::move(v2));
236     assert(&vref == &v1);
237     assert(v1.index() == 1);
238     assert(std::get<1>(v1) == 42);
239   }
240   {
241     using V = std::variant<int, MoveAssign, unsigned>;
242     V v1(std::in_place_type<MoveAssign>, 43);
243     V v2(std::in_place_type<MoveAssign>, 42);
244     MoveAssign::reset();
245     V &vref = (v1 = std::move(v2));
246     assert(&vref == &v1);
247     assert(v1.index() == 1);
248     assert(std::get<1>(v1).value == 42);
249     assert(MoveAssign::move_construct == 0);
250     assert(MoveAssign::move_assign == 1);
251   }
252 #ifndef TEST_HAS_NO_EXCEPTIONS
253   using MET = MakeEmptyT;
254   {
255     using V = std::variant<int, MET, std::string>;
256     V v1(std::in_place_type<MET>);
257     MET &mref = std::get<1>(v1);
258     V v2(std::in_place_type<MET>);
259     try {
260       v1 = std::move(v2);
261       assert(false);
262     } catch (...) {
263     }
264     assert(v1.index() == 1);
265     assert(&std::get<1>(v1) == &mref);
266   }
267 #endif
268 }
269
270 void test_move_assignment_different_index() {
271   {
272     using V = std::variant<int, long, unsigned>;
273     V v1(43);
274     V v2(42l);
275     V &vref = (v1 = std::move(v2));
276     assert(&vref == &v1);
277     assert(v1.index() == 1);
278     assert(std::get<1>(v1) == 42);
279   }
280   {
281     using V = std::variant<int, MoveAssign, unsigned>;
282     V v1(std::in_place_type<unsigned>, 43);
283     V v2(std::in_place_type<MoveAssign>, 42);
284     MoveAssign::reset();
285     V &vref = (v1 = std::move(v2));
286     assert(&vref == &v1);
287     assert(v1.index() == 1);
288     assert(std::get<1>(v1).value == 42);
289     assert(MoveAssign::move_construct == 1);
290     assert(MoveAssign::move_assign == 0);
291   }
292 #ifndef TEST_HAS_NO_EXCEPTIONS
293   using MET = MakeEmptyT;
294   {
295     using V = std::variant<int, MET, std::string>;
296     V v1(std::in_place_type<int>);
297     V v2(std::in_place_type<MET>);
298     try {
299       v1 = std::move(v2);
300       assert(false);
301     } catch (...) {
302     }
303     assert(v1.valueless_by_exception());
304     assert(v1.index() == std::variant_npos);
305   }
306   {
307     using V = std::variant<int, MET, std::string>;
308     V v1(std::in_place_type<MET>);
309     V v2(std::in_place_type<std::string>, "hello");
310     V &vref = (v1 = std::move(v2));
311     assert(&vref == &v1);
312     assert(v1.index() == 2);
313     assert(std::get<2>(v1) == "hello");
314   }
315 #endif
316 }
317
318 int main() {
319   test_move_assignment_empty_empty();
320   test_move_assignment_non_empty_empty();
321   test_move_assignment_empty_non_empty();
322   test_move_assignment_same_index();
323   test_move_assignment_different_index();
324   test_move_assignment_sfinae();
325   test_move_assignment_noexcept();
326 }