2 //===----------------------------------------------------------------------===//
4 // The LLVM Compiler Infrastructure
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.TXT for details.
9 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++98, c++03, c++11, c++14
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
22 // template <class ...Types> class variant;
24 // variant& operator=(variant&&) noexcept(see below);
28 #include <type_traits>
32 #include "test_macros.h"
33 #include "variant_test_helpers.hpp"
36 NoCopy(const NoCopy &) = delete;
37 NoCopy &operator=(const NoCopy &) = default;
41 CopyOnly(const CopyOnly &) = default;
42 CopyOnly(CopyOnly &&) = delete;
43 CopyOnly &operator=(const CopyOnly &) = default;
44 CopyOnly &operator=(CopyOnly &&) = delete;
48 MoveOnly(const MoveOnly &) = delete;
49 MoveOnly(MoveOnly &&) = default;
50 MoveOnly &operator=(const MoveOnly &) = delete;
51 MoveOnly &operator=(MoveOnly &&) = default;
55 MoveOnlyNT(const MoveOnlyNT &) = delete;
56 MoveOnlyNT(MoveOnlyNT &&) {}
57 MoveOnlyNT &operator=(const MoveOnlyNT &) = delete;
58 MoveOnlyNT &operator=(MoveOnlyNT &&) = default;
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;
68 struct MoveAssignOnly {
69 MoveAssignOnly(MoveAssignOnly &&) = delete;
70 MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
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) {
82 MoveAssign &operator=(MoveAssign &&o) {
91 int MoveAssign::move_construct = 0;
92 int MoveAssign::move_assign = 0;
94 void test_move_assignment_noexcept() {
96 using V = std::variant<int>;
97 static_assert(std::is_nothrow_move_assignable<V>::value, "");
100 using V = std::variant<MoveOnly>;
101 static_assert(std::is_nothrow_move_assignable<V>::value, "");
104 using V = std::variant<int, long>;
105 static_assert(std::is_nothrow_move_assignable<V>::value, "");
108 using V = std::variant<int, MoveOnly>;
109 static_assert(std::is_nothrow_move_assignable<V>::value, "");
112 using V = std::variant<MoveOnlyNT>;
113 static_assert(!std::is_nothrow_move_assignable<V>::value, "");
116 using V = std::variant<MoveOnlyOddNothrow>;
117 static_assert(!std::is_nothrow_move_assignable<V>::value, "");
121 void test_move_assignment_sfinae() {
123 using V = std::variant<int, long>;
124 static_assert(std::is_move_assignable<V>::value, "");
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, "");
133 using V = std::variant<int, NoCopy>;
134 static_assert(!std::is_move_assignable<V>::value, "");
137 using V = std::variant<int, MoveOnly>;
138 static_assert(std::is_move_assignable<V>::value, "");
141 using V = std::variant<int, MoveOnlyNT>;
142 static_assert(std::is_move_assignable<V>::value, "");
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, "");
152 void test_move_assignment_empty_empty() {
153 #ifndef TEST_HAS_NO_EXCEPTIONS
154 using MET = MakeEmptyT;
156 using V = std::variant<int, long, MET>;
157 V v1(std::in_place_index<0>);
159 V v2(std::in_place_index<0>);
161 V &vref = (v1 = std::move(v2));
162 assert(&vref == &v1);
163 assert(v1.valueless_by_exception());
164 assert(v1.index() == std::variant_npos);
169 void test_move_assignment_non_empty_empty() {
170 #ifndef TEST_HAS_NO_EXCEPTIONS
171 using MET = MakeEmptyT;
173 using V = std::variant<int, MET>;
174 V v1(std::in_place_index<0>, 42);
175 V v2(std::in_place_index<0>);
177 V &vref = (v1 = std::move(v2));
178 assert(&vref == &v1);
179 assert(v1.valueless_by_exception());
180 assert(v1.index() == std::variant_npos);
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>);
187 V &vref = (v1 = std::move(v2));
188 assert(&vref == &v1);
189 assert(v1.valueless_by_exception());
190 assert(v1.index() == std::variant_npos);
195 void test_move_assignment_empty_non_empty() {
196 #ifndef TEST_HAS_NO_EXCEPTIONS
197 using MET = MakeEmptyT;
199 using V = std::variant<int, MET>;
200 V v1(std::in_place_index<0>);
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);
209 using V = std::variant<int, MET, std::string>;
210 V v1(std::in_place_index<0>);
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");
221 void test_move_assignment_same_index() {
223 using V = std::variant<int>;
226 V &vref = (v1 = std::move(v2));
227 assert(&vref == &v1);
228 assert(v1.index() == 0);
229 assert(std::get<0>(v1) == 42);
232 using V = std::variant<int, long, unsigned>;
235 V &vref = (v1 = std::move(v2));
236 assert(&vref == &v1);
237 assert(v1.index() == 1);
238 assert(std::get<1>(v1) == 42);
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);
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);
252 #ifndef TEST_HAS_NO_EXCEPTIONS
253 using MET = MakeEmptyT;
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>);
264 assert(v1.index() == 1);
265 assert(&std::get<1>(v1) == &mref);
270 void test_move_assignment_different_index() {
272 using V = std::variant<int, long, unsigned>;
275 V &vref = (v1 = std::move(v2));
276 assert(&vref == &v1);
277 assert(v1.index() == 1);
278 assert(std::get<1>(v1) == 42);
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);
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);
292 #ifndef TEST_HAS_NO_EXCEPTIONS
293 using MET = MakeEmptyT;
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>);
303 assert(v1.valueless_by_exception());
304 assert(v1.index() == std::variant_npos);
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");
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();