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 const&);
19 #include <type_traits>
22 #include "test_macros.h"
25 NoCopy(const NoCopy
&) = delete;
26 NoCopy
& operator=(const NoCopy
&) = default;
30 CopyOnly(const CopyOnly
&) = default;
31 CopyOnly(CopyOnly
&&) = delete;
32 CopyOnly
& operator=(const CopyOnly
&) = default;
33 CopyOnly
& operator=(CopyOnly
&&) = delete;
37 MoveOnly(const MoveOnly
&) = delete;
38 MoveOnly(MoveOnly
&&) = default;
39 MoveOnly
& operator=(const MoveOnly
&) = default;
43 MoveOnlyNT(const MoveOnlyNT
&) = delete;
44 MoveOnlyNT(MoveOnlyNT
&&) {}
45 MoveOnlyNT
& operator=(const MoveOnlyNT
&) = default;
49 constexpr CopyAssign(int v
, int* alv
, int* cpy_ctr
, int* cpy_assi
, int* move_ctr
, int* move_assi
)
52 copy_construct(cpy_ctr
),
53 copy_assign(cpy_assi
),
54 move_construct(move_ctr
),
55 move_assign(move_assi
) {
58 constexpr CopyAssign(const CopyAssign
& o
)
61 copy_construct(o
.copy_construct
),
62 copy_assign(o
.copy_assign
),
63 move_construct(o
.move_construct
),
64 move_assign(o
.move_assign
) {
68 constexpr CopyAssign(CopyAssign
&& o
) noexcept
71 copy_construct(o
.copy_construct
),
72 copy_assign(o
.copy_assign
),
73 move_construct(o
.move_construct
),
74 move_assign(o
.move_assign
) {
79 constexpr CopyAssign
& operator=(const CopyAssign
& o
) {
82 copy_construct
= o
.copy_construct
;
83 copy_assign
= o
.copy_assign
;
84 move_construct
= o
.move_construct
;
85 move_assign
= o
.move_assign
;
89 constexpr CopyAssign
& operator=(CopyAssign
&& o
) noexcept
{
92 copy_construct
= o
.copy_construct
;
93 copy_assign
= o
.copy_assign
;
94 move_construct
= o
.move_construct
;
95 move_assign
= o
.move_assign
;
100 TEST_CONSTEXPR_CXX20
~CopyAssign() { --*alive
; }
109 struct CopyMaybeThrows
{
110 CopyMaybeThrows(const CopyMaybeThrows
&);
111 CopyMaybeThrows
& operator=(const CopyMaybeThrows
&);
113 struct CopyDoesThrow
{
114 CopyDoesThrow(const CopyDoesThrow
&) noexcept(false);
115 CopyDoesThrow
& operator=(const CopyDoesThrow
&) noexcept(false);
118 struct NTCopyAssign
{
119 constexpr NTCopyAssign(int v
) : value(v
) {}
120 NTCopyAssign(const NTCopyAssign
&) = default;
121 NTCopyAssign(NTCopyAssign
&&) = default;
122 NTCopyAssign
& operator=(const NTCopyAssign
& that
) {
126 NTCopyAssign
& operator=(NTCopyAssign
&&) = delete;
130 static_assert(!std::is_trivially_copy_assignable
<NTCopyAssign
>::value
, "");
131 static_assert(std::is_copy_assignable
<NTCopyAssign
>::value
, "");
134 constexpr TCopyAssign(int v
) : value(v
) {}
135 TCopyAssign(const TCopyAssign
&) = default;
136 TCopyAssign(TCopyAssign
&&) = default;
137 TCopyAssign
& operator=(const TCopyAssign
&) = default;
138 TCopyAssign
& operator=(TCopyAssign
&&) = delete;
142 static_assert(std::is_trivially_copy_assignable
<TCopyAssign
>::value
, "");
144 struct TCopyAssignNTMoveAssign
{
145 constexpr TCopyAssignNTMoveAssign(int v
) : value(v
) {}
146 TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign
&) = default;
147 TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign
&&) = default;
148 TCopyAssignNTMoveAssign
& operator=(const TCopyAssignNTMoveAssign
&) = default;
149 TCopyAssignNTMoveAssign
& operator=(TCopyAssignNTMoveAssign
&& that
) {
157 static_assert(std::is_trivially_copy_assignable_v
<TCopyAssignNTMoveAssign
>, "");
159 #ifndef TEST_HAS_NO_EXCEPTIONS
161 CopyThrows() = default;
162 CopyThrows(const CopyThrows
&) { throw 42; }
163 CopyThrows
& operator=(const CopyThrows
&) { throw 42; }
166 struct CopyCannotThrow
{
168 CopyCannotThrow() { ++alive
; }
169 CopyCannotThrow(const CopyCannotThrow
&) noexcept
{ ++alive
; }
170 CopyCannotThrow(CopyCannotThrow
&&) noexcept
{ assert(false); }
171 CopyCannotThrow
& operator=(const CopyCannotThrow
&) noexcept
= default;
172 CopyCannotThrow
& operator=(CopyCannotThrow
&&) noexcept
{
178 int CopyCannotThrow::alive
= 0;
182 MoveThrows() { ++alive
; }
183 MoveThrows(const MoveThrows
&) { ++alive
; }
184 MoveThrows(MoveThrows
&&) { throw 42; }
185 MoveThrows
& operator=(const MoveThrows
&) { return *this; }
186 MoveThrows
& operator=(MoveThrows
&&) { throw 42; }
187 ~MoveThrows() { --alive
; }
190 int MoveThrows::alive
= 0;
194 MakeEmptyT() { ++alive
; }
195 MakeEmptyT(const MakeEmptyT
&) {
197 // Don't throw from the copy constructor since variant's assignment
198 // operator performs a copy before committing to the assignment.
200 MakeEmptyT(MakeEmptyT
&&) { throw 42; }
201 MakeEmptyT
& operator=(const MakeEmptyT
&) { throw 42; }
202 MakeEmptyT
& operator=(MakeEmptyT
&&) { throw 42; }
203 ~MakeEmptyT() { --alive
; }
206 int MakeEmptyT::alive
= 0;
208 template <class Variant
>
209 void makeEmpty(Variant
& v
) {
210 Variant
v2(std::in_place_type
<MakeEmptyT
>);
215 assert(v
.valueless_by_exception());
218 #endif // TEST_HAS_NO_EXCEPTIONS
220 constexpr void test_copy_assignment_not_noexcept() {
222 using V
= std::variant
<CopyMaybeThrows
>;
223 static_assert(!std::is_nothrow_copy_assignable
<V
>::value
, "");
226 using V
= std::variant
<int, CopyDoesThrow
>;
227 static_assert(!std::is_nothrow_copy_assignable
<V
>::value
, "");
231 constexpr void test_copy_assignment_sfinae() {
233 using V
= std::variant
<int, long>;
234 static_assert(std::is_copy_assignable
<V
>::value
, "");
237 using V
= std::variant
<int, CopyOnly
>;
238 static_assert(std::is_copy_assignable
<V
>::value
, "");
241 using V
= std::variant
<int, NoCopy
>;
242 static_assert(!std::is_copy_assignable
<V
>::value
, "");
245 using V
= std::variant
<int, MoveOnly
>;
246 static_assert(!std::is_copy_assignable
<V
>::value
, "");
249 using V
= std::variant
<int, MoveOnlyNT
>;
250 static_assert(!std::is_copy_assignable
<V
>::value
, "");
253 // Make sure we properly propagate triviality (see P0602R4).
255 using V
= std::variant
<int, long>;
256 static_assert(std::is_trivially_copy_assignable
<V
>::value
, "");
259 using V
= std::variant
<int, NTCopyAssign
>;
260 static_assert(!std::is_trivially_copy_assignable
<V
>::value
, "");
261 static_assert(std::is_copy_assignable
<V
>::value
, "");
264 using V
= std::variant
<int, TCopyAssign
>;
265 static_assert(std::is_trivially_copy_assignable
<V
>::value
, "");
268 using V
= std::variant
<int, TCopyAssignNTMoveAssign
>;
269 static_assert(std::is_trivially_copy_assignable
<V
>::value
, "");
272 using V
= std::variant
<int, CopyOnly
>;
273 static_assert(std::is_trivially_copy_assignable
<V
>::value
, "");
277 void test_copy_assignment_empty_empty() {
278 #ifndef TEST_HAS_NO_EXCEPTIONS
279 using MET
= MakeEmptyT
;
281 using V
= std::variant
<int, long, MET
>;
282 V
v1(std::in_place_index
<0>);
284 V
v2(std::in_place_index
<0>);
287 assert(&vref
== &v1
);
288 assert(v1
.valueless_by_exception());
289 assert(v1
.index() == std::variant_npos
);
291 #endif // TEST_HAS_NO_EXCEPTIONS
294 void test_copy_assignment_non_empty_empty() {
295 #ifndef TEST_HAS_NO_EXCEPTIONS
296 using MET
= MakeEmptyT
;
298 using V
= std::variant
<int, MET
>;
299 V
v1(std::in_place_index
<0>, 42);
300 V
v2(std::in_place_index
<0>);
303 assert(&vref
== &v1
);
304 assert(v1
.valueless_by_exception());
305 assert(v1
.index() == std::variant_npos
);
308 using V
= std::variant
<int, MET
, std::string
>;
309 V
v1(std::in_place_index
<2>, "hello");
310 V
v2(std::in_place_index
<0>);
313 assert(&vref
== &v1
);
314 assert(v1
.valueless_by_exception());
315 assert(v1
.index() == std::variant_npos
);
317 #endif // TEST_HAS_NO_EXCEPTIONS
320 void test_copy_assignment_empty_non_empty() {
321 #ifndef TEST_HAS_NO_EXCEPTIONS
322 using MET
= MakeEmptyT
;
324 using V
= std::variant
<int, MET
>;
325 V
v1(std::in_place_index
<0>);
327 V
v2(std::in_place_index
<0>, 42);
329 assert(&vref
== &v1
);
330 assert(v1
.index() == 0);
331 assert(std::get
<0>(v1
) == 42);
334 using V
= std::variant
<int, MET
, std::string
>;
335 V
v1(std::in_place_index
<0>);
337 V
v2(std::in_place_type
<std::string
>, "hello");
339 assert(&vref
== &v1
);
340 assert(v1
.index() == 2);
341 assert(std::get
<2>(v1
) == "hello");
343 #endif // TEST_HAS_NO_EXCEPTIONS
346 template <typename T
>
352 TEST_CONSTEXPR_CXX20
void test_copy_assignment_same_index() {
354 using V
= std::variant
<int>;
358 assert(&vref
== &v1
);
359 assert(v1
.index() == 0);
360 assert(std::get
<0>(v1
) == 42);
363 using V
= std::variant
<int, long, unsigned>;
367 assert(&vref
== &v1
);
368 assert(v1
.index() == 1);
369 assert(std::get
<1>(v1
) == 42);
372 using V
= std::variant
<int, CopyAssign
, unsigned>;
374 int copy_construct
= 0;
376 int move_construct
= 0;
378 V
v1(std::in_place_type
<CopyAssign
>, 43, &alive
, ©_construct
, ©_assign
, &move_construct
, &move_assign
);
379 V
v2(std::in_place_type
<CopyAssign
>, 42, &alive
, ©_construct
, ©_assign
, &move_construct
, &move_assign
);
381 assert(&vref
== &v1
);
382 assert(v1
.index() == 1);
383 assert(std::get
<1>(v1
).value
== 42);
384 assert(copy_construct
== 0);
385 assert(move_construct
== 0);
386 assert(copy_assign
== 1);
389 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
392 constexpr Result
<int> operator()() const {
393 using V
= std::variant
<int>;
397 return {v
.index(), std::get
<0>(v
)};
400 constexpr auto result
= test();
401 static_assert(result
.index
== 0, "");
402 static_assert(result
.value
== 42, "");
406 constexpr Result
<long> operator()() const {
407 using V
= std::variant
<int, long, unsigned>;
411 return {v
.index(), std::get
<1>(v
)};
414 constexpr auto result
= test();
415 static_assert(result
.index
== 1, "");
416 static_assert(result
.value
== 42l, "");
420 constexpr Result
<int> operator()() const {
421 using V
= std::variant
<int, TCopyAssign
, unsigned>;
422 V
v(std::in_place_type
<TCopyAssign
>, 43);
423 V
v2(std::in_place_type
<TCopyAssign
>, 42);
425 return {v
.index(), std::get
<1>(v
).value
};
428 constexpr auto result
= test();
429 static_assert(result
.index
== 1, "");
430 static_assert(result
.value
== 42, "");
434 constexpr Result
<int> operator()() const {
435 using V
= std::variant
<int, TCopyAssignNTMoveAssign
, unsigned>;
436 V
v(std::in_place_type
<TCopyAssignNTMoveAssign
>, 43);
437 V
v2(std::in_place_type
<TCopyAssignNTMoveAssign
>, 42);
439 return {v
.index(), std::get
<1>(v
).value
};
442 constexpr auto result
= test();
443 static_assert(result
.index
== 1, "");
444 static_assert(result
.value
== 42, "");
448 TEST_CONSTEXPR_CXX20
void test_copy_assignment_different_index() {
450 using V
= std::variant
<int, long, unsigned>;
454 assert(&vref
== &v1
);
455 assert(v1
.index() == 1);
456 assert(std::get
<1>(v1
) == 42);
459 using V
= std::variant
<int, CopyAssign
, unsigned>;
461 int copy_construct
= 0;
463 int move_construct
= 0;
465 V
v1(std::in_place_type
<unsigned>, 43u);
466 V
v2(std::in_place_type
<CopyAssign
>, 42, &alive
, ©_construct
, ©_assign
, &move_construct
, &move_assign
);
467 assert(copy_construct
== 0);
468 assert(move_construct
== 0);
471 assert(&vref
== &v1
);
472 assert(v1
.index() == 1);
473 assert(std::get
<1>(v1
).value
== 42);
475 assert(copy_construct
== 1);
476 assert(move_construct
== 1);
477 assert(copy_assign
== 0);
480 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
483 constexpr Result
<long> operator()() const {
484 using V
= std::variant
<int, long, unsigned>;
488 return {v
.index(), std::get
<1>(v
)};
491 constexpr auto result
= test();
492 static_assert(result
.index
== 1, "");
493 static_assert(result
.value
== 42l, "");
497 constexpr Result
<int> operator()() const {
498 using V
= std::variant
<int, TCopyAssign
, unsigned>;
499 V
v(std::in_place_type
<unsigned>, 43u);
500 V
v2(std::in_place_type
<TCopyAssign
>, 42);
502 return {v
.index(), std::get
<1>(v
).value
};
505 constexpr auto result
= test();
506 static_assert(result
.index
== 1, "");
507 static_assert(result
.value
== 42, "");
511 void test_assignment_throw() {
512 #ifndef TEST_HAS_NO_EXCEPTIONS
513 using MET
= MakeEmptyT
;
516 using V
= std::variant
<int, MET
, std::string
>;
517 V
v1(std::in_place_type
<MET
>);
518 MET
& mref
= std::get
<1>(v1
);
519 V
v2(std::in_place_type
<MET
>);
525 assert(v1
.index() == 1);
526 assert(&std::get
<1>(v1
) == &mref
);
529 // difference indices
531 using V
= std::variant
<int, CopyThrows
, std::string
>;
532 V
v1(std::in_place_type
<std::string
>, "hello");
533 V
v2(std::in_place_type
<CopyThrows
>);
537 } catch (...) { /* ... */
539 // Test that copy construction is used directly if move construction may throw,
540 // resulting in a valueless variant if copy throws.
541 assert(v1
.valueless_by_exception());
544 using V
= std::variant
<int, MoveThrows
, std::string
>;
545 V
v1(std::in_place_type
<std::string
>, "hello");
546 V
v2(std::in_place_type
<MoveThrows
>);
547 assert(MoveThrows::alive
== 1);
548 // Test that copy construction is used directly if move construction may throw.
550 assert(v1
.index() == 1);
551 assert(v2
.index() == 1);
552 assert(MoveThrows::alive
== 2);
555 // Test that direct copy construction is preferred when it cannot throw.
556 using V
= std::variant
<int, CopyCannotThrow
, std::string
>;
557 V
v1(std::in_place_type
<std::string
>, "hello");
558 V
v2(std::in_place_type
<CopyCannotThrow
>);
559 assert(CopyCannotThrow::alive
== 1);
561 assert(v1
.index() == 1);
562 assert(v2
.index() == 1);
563 assert(CopyCannotThrow::alive
== 2);
566 using V
= std::variant
<int, CopyThrows
, std::string
>;
567 V
v1(std::in_place_type
<CopyThrows
>);
568 V
v2(std::in_place_type
<std::string
>, "hello");
570 assert(&vref
== &v1
);
571 assert(v1
.index() == 2);
572 assert(std::get
<2>(v1
) == "hello");
573 assert(v2
.index() == 2);
574 assert(std::get
<2>(v2
) == "hello");
577 using V
= std::variant
<int, MoveThrows
, std::string
>;
578 V
v1(std::in_place_type
<MoveThrows
>);
579 V
v2(std::in_place_type
<std::string
>, "hello");
581 assert(&vref
== &v1
);
582 assert(v1
.index() == 2);
583 assert(std::get
<2>(v1
) == "hello");
584 assert(v2
.index() == 2);
585 assert(std::get
<2>(v2
) == "hello");
587 #endif // TEST_HAS_NO_EXCEPTIONS
590 template <std::size_t NewIdx
, class T
, class ValueType
>
591 constexpr void test_constexpr_assign_imp(T
&& v
, ValueType
&& new_value
) {
592 using Variant
= std::decay_t
<T
>;
593 const Variant
cp(std::forward
<ValueType
>(new_value
));
595 assert(v
.index() == NewIdx
);
596 assert(std::get
<NewIdx
>(v
) == std::get
<NewIdx
>(cp
));
599 constexpr void test_constexpr_copy_assignment_trivial() {
600 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
601 using V
= std::variant
<long, void*, int>;
602 static_assert(std::is_trivially_copyable
<V
>::value
, "");
603 static_assert(std::is_trivially_copy_assignable
<V
>::value
, "");
604 test_constexpr_assign_imp
<0>(V(42l), 101l);
605 test_constexpr_assign_imp
<0>(V(nullptr), 101l);
606 test_constexpr_assign_imp
<1>(V(42l), nullptr);
607 test_constexpr_assign_imp
<2>(V(42l), 101);
610 struct NonTrivialCopyAssign
{
612 constexpr NonTrivialCopyAssign(int ii
) : i(ii
) {}
613 constexpr NonTrivialCopyAssign(const NonTrivialCopyAssign
& other
) : i(other
.i
) {}
614 constexpr NonTrivialCopyAssign
& operator=(const NonTrivialCopyAssign
& o
) {
618 TEST_CONSTEXPR_CXX20
~NonTrivialCopyAssign() = default;
619 friend constexpr bool operator==(const NonTrivialCopyAssign
& x
, const NonTrivialCopyAssign
& y
) { return x
.i
== y
.i
; }
622 constexpr void test_constexpr_copy_assignment_non_trivial() {
623 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
624 using V
= std::variant
<long, void*, NonTrivialCopyAssign
>;
625 static_assert(!std::is_trivially_copyable
<V
>::value
, "");
626 static_assert(!std::is_trivially_copy_assignable
<V
>::value
, "");
627 test_constexpr_assign_imp
<0>(V(42l), 101l);
628 test_constexpr_assign_imp
<0>(V(nullptr), 101l);
629 test_constexpr_assign_imp
<1>(V(42l), nullptr);
630 test_constexpr_assign_imp
<2>(V(42l), NonTrivialCopyAssign(5));
631 test_constexpr_assign_imp
<2>(V(NonTrivialCopyAssign(3)), NonTrivialCopyAssign(5));
634 void non_constexpr_test() {
635 test_copy_assignment_empty_empty();
636 test_copy_assignment_non_empty_empty();
637 test_copy_assignment_empty_non_empty();
638 test_assignment_throw();
641 constexpr bool cxx17_constexpr_test() {
642 test_copy_assignment_sfinae();
643 test_copy_assignment_not_noexcept();
644 test_constexpr_copy_assignment_trivial();
649 TEST_CONSTEXPR_CXX20
bool cxx20_constexpr_test() {
650 test_copy_assignment_same_index();
651 test_copy_assignment_different_index();
652 test_constexpr_copy_assignment_non_trivial();
657 int main(int, char**) {
658 non_constexpr_test();
659 cxx17_constexpr_test();
660 cxx20_constexpr_test();
662 static_assert(cxx17_constexpr_test());
663 #if TEST_STD_VER >= 20
664 static_assert(cxx20_constexpr_test());