1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14
13 // template <class ...Types> class variant;
15 // constexpr variant& operator=(variant&&) noexcept(see below);
19 #include <type_traits>
23 #include "test_macros.h"
24 #include "variant_test_helpers.h"
27 NoCopy(const NoCopy
&) = delete;
28 NoCopy
& operator=(const NoCopy
&) = default;
32 CopyOnly(const CopyOnly
&) = default;
33 CopyOnly(CopyOnly
&&) = delete;
34 CopyOnly
& operator=(const CopyOnly
&) = default;
35 CopyOnly
& operator=(CopyOnly
&&) = delete;
39 MoveOnly(const MoveOnly
&) = delete;
40 MoveOnly(MoveOnly
&&) = default;
41 MoveOnly
& operator=(const MoveOnly
&) = delete;
42 MoveOnly
& operator=(MoveOnly
&&) = default;
46 MoveOnlyNT(const MoveOnlyNT
&) = delete;
47 MoveOnlyNT(MoveOnlyNT
&&) {}
48 MoveOnlyNT
& operator=(const MoveOnlyNT
&) = delete;
49 MoveOnlyNT
& operator=(MoveOnlyNT
&&) = default;
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;
59 struct MoveAssignOnly
{
60 MoveAssignOnly(MoveAssignOnly
&&) = delete;
61 MoveAssignOnly
& operator=(MoveAssignOnly
&&) = default;
65 constexpr MoveAssign(int v
, int* move_ctor
, int* move_assi
)
66 : value(v
), move_construct(move_ctor
), move_assign(move_assi
) {}
67 constexpr MoveAssign(MoveAssign
&& o
) : value(o
.value
), move_construct(o
.move_construct
), move_assign(o
.move_assign
) {
71 constexpr MoveAssign
& operator=(MoveAssign
&& o
) {
73 move_construct
= o
.move_construct
;
74 move_assign
= o
.move_assign
;
85 constexpr NTMoveAssign(int v
) : value(v
) {}
86 NTMoveAssign(const NTMoveAssign
&) = default;
87 NTMoveAssign(NTMoveAssign
&&) = default;
88 NTMoveAssign
& operator=(const NTMoveAssign
& that
) = default;
89 NTMoveAssign
& operator=(NTMoveAssign
&& that
) {
97 static_assert(!std::is_trivially_move_assignable
<NTMoveAssign
>::value
, "");
98 static_assert(std::is_move_assignable
<NTMoveAssign
>::value
, "");
101 constexpr TMoveAssign(int v
) : value(v
) {}
102 TMoveAssign(const TMoveAssign
&) = delete;
103 TMoveAssign(TMoveAssign
&&) = default;
104 TMoveAssign
& operator=(const TMoveAssign
&) = delete;
105 TMoveAssign
& operator=(TMoveAssign
&&) = default;
109 static_assert(std::is_trivially_move_assignable
<TMoveAssign
>::value
, "");
111 struct TMoveAssignNTCopyAssign
{
112 constexpr TMoveAssignNTCopyAssign(int v
) : value(v
) {}
113 TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign
&) = default;
114 TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign
&&) = default;
115 TMoveAssignNTCopyAssign
& operator=(const TMoveAssignNTCopyAssign
& that
) {
119 TMoveAssignNTCopyAssign
& operator=(TMoveAssignNTCopyAssign
&&) = default;
123 static_assert(std::is_trivially_move_assignable_v
<TMoveAssignNTCopyAssign
>, "");
125 struct TrivialCopyNontrivialMove
{
126 TrivialCopyNontrivialMove(TrivialCopyNontrivialMove
const&) = default;
127 TrivialCopyNontrivialMove(TrivialCopyNontrivialMove
&&) noexcept
{}
128 TrivialCopyNontrivialMove
& operator=(TrivialCopyNontrivialMove
const&) = default;
129 TrivialCopyNontrivialMove
& operator=(TrivialCopyNontrivialMove
&&) noexcept
{ return *this; }
132 static_assert(std::is_trivially_copy_assignable_v
<TrivialCopyNontrivialMove
>, "");
133 static_assert(!std::is_trivially_move_assignable_v
<TrivialCopyNontrivialMove
>, "");
135 constexpr void test_move_assignment_noexcept() {
137 using V
= std::variant
<int>;
138 static_assert(std::is_nothrow_move_assignable
<V
>::value
, "");
141 using V
= std::variant
<MoveOnly
>;
142 static_assert(std::is_nothrow_move_assignable
<V
>::value
, "");
145 using V
= std::variant
<int, long>;
146 static_assert(std::is_nothrow_move_assignable
<V
>::value
, "");
149 using V
= std::variant
<int, MoveOnly
>;
150 static_assert(std::is_nothrow_move_assignable
<V
>::value
, "");
153 using V
= std::variant
<MoveOnlyNT
>;
154 static_assert(!std::is_nothrow_move_assignable
<V
>::value
, "");
157 using V
= std::variant
<MoveOnlyOddNothrow
>;
158 static_assert(!std::is_nothrow_move_assignable
<V
>::value
, "");
162 constexpr void test_move_assignment_sfinae() {
164 using V
= std::variant
<int, long>;
165 static_assert(std::is_move_assignable
<V
>::value
, "");
168 using V
= std::variant
<int, CopyOnly
>;
169 static_assert(std::is_move_assignable
<V
>::value
, "");
172 using V
= std::variant
<int, NoCopy
>;
173 static_assert(!std::is_move_assignable
<V
>::value
, "");
176 using V
= std::variant
<int, MoveOnly
>;
177 static_assert(std::is_move_assignable
<V
>::value
, "");
180 using V
= std::variant
<int, MoveOnlyNT
>;
181 static_assert(std::is_move_assignable
<V
>::value
, "");
184 // variant only provides move assignment when the types also provide
185 // a move constructor.
186 using V
= std::variant
<int, MoveAssignOnly
>;
187 static_assert(!std::is_move_assignable
<V
>::value
, "");
190 // Make sure we properly propagate triviality (see P0602R4).
192 using V
= std::variant
<int, long>;
193 static_assert(std::is_trivially_move_assignable
<V
>::value
, "");
196 using V
= std::variant
<int, NTMoveAssign
>;
197 static_assert(!std::is_trivially_move_assignable
<V
>::value
, "");
198 static_assert(std::is_move_assignable
<V
>::value
, "");
201 using V
= std::variant
<int, TMoveAssign
>;
202 static_assert(std::is_trivially_move_assignable
<V
>::value
, "");
205 using V
= std::variant
<int, TMoveAssignNTCopyAssign
>;
206 static_assert(std::is_trivially_move_assignable
<V
>::value
, "");
209 using V
= std::variant
<int, TrivialCopyNontrivialMove
>;
210 static_assert(!std::is_trivially_move_assignable
<V
>::value
, "");
213 using V
= std::variant
<int, CopyOnly
>;
214 static_assert(std::is_trivially_move_assignable
<V
>::value
, "");
218 void test_move_assignment_empty_empty() {
219 #ifndef TEST_HAS_NO_EXCEPTIONS
220 using MET
= MakeEmptyT
;
222 using V
= std::variant
<int, long, MET
>;
223 V
v1(std::in_place_index
<0>);
225 V
v2(std::in_place_index
<0>);
227 V
& vref
= (v1
= std::move(v2
));
228 assert(&vref
== &v1
);
229 assert(v1
.valueless_by_exception());
230 assert(v1
.index() == std::variant_npos
);
232 #endif // TEST_HAS_NO_EXCEPTIONS
235 void test_move_assignment_non_empty_empty() {
236 #ifndef TEST_HAS_NO_EXCEPTIONS
237 using MET
= MakeEmptyT
;
239 using V
= std::variant
<int, MET
>;
240 V
v1(std::in_place_index
<0>, 42);
241 V
v2(std::in_place_index
<0>);
243 V
& vref
= (v1
= std::move(v2
));
244 assert(&vref
== &v1
);
245 assert(v1
.valueless_by_exception());
246 assert(v1
.index() == std::variant_npos
);
249 using V
= std::variant
<int, MET
, std::string
>;
250 V
v1(std::in_place_index
<2>, "hello");
251 V
v2(std::in_place_index
<0>);
253 V
& vref
= (v1
= std::move(v2
));
254 assert(&vref
== &v1
);
255 assert(v1
.valueless_by_exception());
256 assert(v1
.index() == std::variant_npos
);
258 #endif // TEST_HAS_NO_EXCEPTIONS
261 void test_move_assignment_empty_non_empty() {
262 #ifndef TEST_HAS_NO_EXCEPTIONS
263 using MET
= MakeEmptyT
;
265 using V
= std::variant
<int, MET
>;
266 V
v1(std::in_place_index
<0>);
268 V
v2(std::in_place_index
<0>, 42);
269 V
& vref
= (v1
= std::move(v2
));
270 assert(&vref
== &v1
);
271 assert(v1
.index() == 0);
272 assert(std::get
<0>(v1
) == 42);
275 using V
= std::variant
<int, MET
, std::string
>;
276 V
v1(std::in_place_index
<0>);
278 V
v2(std::in_place_type
<std::string
>, "hello");
279 V
& vref
= (v1
= std::move(v2
));
280 assert(&vref
== &v1
);
281 assert(v1
.index() == 2);
282 assert(std::get
<2>(v1
) == "hello");
284 #endif // TEST_HAS_NO_EXCEPTIONS
287 template <typename T
>
293 TEST_CONSTEXPR_CXX20
void test_move_assignment_same_index() {
295 using V
= std::variant
<int>;
298 V
& vref
= (v1
= std::move(v2
));
299 assert(&vref
== &v1
);
300 assert(v1
.index() == 0);
301 assert(std::get
<0>(v1
) == 42);
304 using V
= std::variant
<int, long, unsigned>;
307 V
& vref
= (v1
= std::move(v2
));
308 assert(&vref
== &v1
);
309 assert(v1
.index() == 1);
310 assert(std::get
<1>(v1
) == 42);
313 using V
= std::variant
<int, MoveAssign
, unsigned>;
314 int move_construct
= 0;
316 V
v1(std::in_place_type
<MoveAssign
>, 43, &move_construct
, &move_assign
);
317 V
v2(std::in_place_type
<MoveAssign
>, 42, &move_construct
, &move_assign
);
318 V
& vref
= (v1
= std::move(v2
));
319 assert(&vref
== &v1
);
320 assert(v1
.index() == 1);
321 assert(std::get
<1>(v1
).value
== 42);
322 assert(move_construct
== 0);
323 assert(move_assign
== 1);
326 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
329 constexpr Result
<int> operator()() const {
330 using V
= std::variant
<int>;
334 return {v
.index(), std::get
<0>(v
)};
337 constexpr auto result
= test();
338 static_assert(result
.index
== 0, "");
339 static_assert(result
.value
== 42, "");
343 constexpr Result
<long> operator()() const {
344 using V
= std::variant
<int, long, unsigned>;
348 return {v
.index(), std::get
<1>(v
)};
351 constexpr auto result
= test();
352 static_assert(result
.index
== 1, "");
353 static_assert(result
.value
== 42l, "");
357 constexpr Result
<int> operator()() const {
358 using V
= std::variant
<int, TMoveAssign
, unsigned>;
359 V
v(std::in_place_type
<TMoveAssign
>, 43);
360 V
v2(std::in_place_type
<TMoveAssign
>, 42);
362 return {v
.index(), std::get
<1>(v
).value
};
365 constexpr auto result
= test();
366 static_assert(result
.index
== 1, "");
367 static_assert(result
.value
== 42, "");
371 TEST_CONSTEXPR_CXX20
void test_move_assignment_different_index() {
373 using V
= std::variant
<int, long, unsigned>;
376 V
& vref
= (v1
= std::move(v2
));
377 assert(&vref
== &v1
);
378 assert(v1
.index() == 1);
379 assert(std::get
<1>(v1
) == 42);
382 using V
= std::variant
<int, MoveAssign
, unsigned>;
383 int move_construct
= 0;
385 V
v1(std::in_place_type
<unsigned>, 43u);
386 V
v2(std::in_place_type
<MoveAssign
>, 42, &move_construct
, &move_assign
);
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(move_construct
== 1);
392 assert(move_assign
== 0);
395 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
398 constexpr Result
<long> operator()() const {
399 using V
= std::variant
<int, long, unsigned>;
403 return {v
.index(), std::get
<1>(v
)};
406 constexpr auto result
= test();
407 static_assert(result
.index
== 1, "");
408 static_assert(result
.value
== 42l, "");
412 constexpr Result
<long> operator()() const {
413 using V
= std::variant
<int, TMoveAssign
, unsigned>;
414 V
v(std::in_place_type
<unsigned>, 43u);
415 V
v2(std::in_place_type
<TMoveAssign
>, 42);
417 return {v
.index(), std::get
<1>(v
).value
};
420 constexpr auto result
= test();
421 static_assert(result
.index
== 1, "");
422 static_assert(result
.value
== 42, "");
426 void test_assignment_throw() {
427 #ifndef TEST_HAS_NO_EXCEPTIONS
428 using MET
= MakeEmptyT
;
431 using V
= std::variant
<int, MET
, std::string
>;
432 V
v1(std::in_place_type
<MET
>);
433 MET
& mref
= std::get
<1>(v1
);
434 V
v2(std::in_place_type
<MET
>);
440 assert(v1
.index() == 1);
441 assert(&std::get
<1>(v1
) == &mref
);
446 using V
= std::variant
<int, MET
, std::string
>;
447 V
v1(std::in_place_type
<int>);
448 V
v2(std::in_place_type
<MET
>);
454 assert(v1
.valueless_by_exception());
455 assert(v1
.index() == std::variant_npos
);
458 using V
= std::variant
<int, MET
, std::string
>;
459 V
v1(std::in_place_type
<MET
>);
460 V
v2(std::in_place_type
<std::string
>, "hello");
461 V
& vref
= (v1
= std::move(v2
));
462 assert(&vref
== &v1
);
463 assert(v1
.index() == 2);
464 assert(std::get
<2>(v1
) == "hello");
466 #endif // TEST_HAS_NO_EXCEPTIONS
469 template <std::size_t NewIdx
, class T
, class ValueType
>
470 constexpr void test_constexpr_assign_imp(T
&& v
, ValueType
&& new_value
) {
471 using Variant
= std::decay_t
<T
>;
472 Variant
v2(std::forward
<ValueType
>(new_value
));
475 assert(v
.index() == NewIdx
);
476 assert(std::get
<NewIdx
>(v
) == std::get
<NewIdx
>(cp
));
479 constexpr void test_constexpr_move_assignment_trivial() {
480 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
481 using V
= std::variant
<long, void*, int>;
482 static_assert(std::is_trivially_copyable
<V
>::value
, "");
483 static_assert(std::is_trivially_move_assignable
<V
>::value
, "");
484 test_constexpr_assign_imp
<0>(V(42l), 101l);
485 test_constexpr_assign_imp
<0>(V(nullptr), 101l);
486 test_constexpr_assign_imp
<1>(V(42l), nullptr);
487 test_constexpr_assign_imp
<2>(V(42l), 101);
490 struct NonTrivialMoveAssign
{
492 constexpr NonTrivialMoveAssign(int ii
) : i(ii
) {}
493 constexpr NonTrivialMoveAssign(const NonTrivialMoveAssign
& other
) = default;
494 constexpr NonTrivialMoveAssign(NonTrivialMoveAssign
&& other
) : i(other
.i
) {}
495 constexpr NonTrivialMoveAssign
& operator=(const NonTrivialMoveAssign
&) = default;
496 constexpr NonTrivialMoveAssign
& operator=(NonTrivialMoveAssign
&& o
) {
500 TEST_CONSTEXPR_CXX20
~NonTrivialMoveAssign() = default;
501 friend constexpr bool operator==(const NonTrivialMoveAssign
& x
, const NonTrivialMoveAssign
& y
) { return x
.i
== y
.i
; }
504 TEST_CONSTEXPR_CXX20
void test_constexpr_move_assignment_non_trivial() {
505 using V
= std::variant
<long, void*, NonTrivialMoveAssign
>;
506 static_assert(!std::is_trivially_copyable
<V
>::value
);
507 static_assert(!std::is_trivially_move_assignable
<V
>::value
);
508 test_constexpr_assign_imp
<0>(V(42l), 101l);
509 test_constexpr_assign_imp
<0>(V(nullptr), 101l);
510 test_constexpr_assign_imp
<1>(V(42l), nullptr);
511 test_constexpr_assign_imp
<2>(V(42l), NonTrivialMoveAssign(5));
512 test_constexpr_assign_imp
<2>(V(NonTrivialMoveAssign(3)), NonTrivialMoveAssign(5));
515 void non_constexpr_test() {
516 test_move_assignment_empty_empty();
517 test_move_assignment_non_empty_empty();
518 test_move_assignment_empty_non_empty();
519 test_assignment_throw();
522 constexpr bool cxx17_constexpr_test() {
523 test_move_assignment_sfinae();
524 test_move_assignment_noexcept();
525 test_constexpr_move_assignment_trivial();
530 TEST_CONSTEXPR_CXX20
bool cxx20_constexpr_test() {
531 test_move_assignment_same_index();
532 test_move_assignment_different_index();
533 test_constexpr_move_assignment_non_trivial();
538 int main(int, char**) {
539 non_constexpr_test();
540 cxx17_constexpr_test();
541 cxx20_constexpr_test();
543 static_assert(cxx17_constexpr_test());
544 #if TEST_STD_VER >= 20
545 static_assert(cxx20_constexpr_test());