[gn build] Port 0ee037b861f9
[llvm-project.git] / libcxx / test / std / utilities / variant / variant.variant / variant.assign / copy.pass.cpp
bloba6d3f34114eb715c0bef9180071be75dbd5459f4
1 //===----------------------------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14
11 // <variant>
13 // template <class ...Types> class variant;
15 // constexpr variant& operator=(variant const&);
17 #include <cassert>
18 #include <string>
19 #include <type_traits>
20 #include <variant>
22 #include "test_macros.h"
24 struct NoCopy {
25 NoCopy(const NoCopy&) = delete;
26 NoCopy& operator=(const NoCopy&) = default;
29 struct CopyOnly {
30 CopyOnly(const CopyOnly&) = default;
31 CopyOnly(CopyOnly&&) = delete;
32 CopyOnly& operator=(const CopyOnly&) = default;
33 CopyOnly& operator=(CopyOnly&&) = delete;
36 struct MoveOnly {
37 MoveOnly(const MoveOnly&) = delete;
38 MoveOnly(MoveOnly&&) = default;
39 MoveOnly& operator=(const MoveOnly&) = default;
42 struct MoveOnlyNT {
43 MoveOnlyNT(const MoveOnlyNT&) = delete;
44 MoveOnlyNT(MoveOnlyNT&&) {}
45 MoveOnlyNT& operator=(const MoveOnlyNT&) = default;
48 struct CopyAssign {
49 constexpr CopyAssign(int v, int* alv, int* cpy_ctr, int* cpy_assi, int* move_ctr, int* move_assi)
50 : value(v),
51 alive(alv),
52 copy_construct(cpy_ctr),
53 copy_assign(cpy_assi),
54 move_construct(move_ctr),
55 move_assign(move_assi) {
56 ++*alive;
58 constexpr CopyAssign(const CopyAssign& o)
59 : value(o.value),
60 alive(o.alive),
61 copy_construct(o.copy_construct),
62 copy_assign(o.copy_assign),
63 move_construct(o.move_construct),
64 move_assign(o.move_assign) {
65 ++*alive;
66 ++*copy_construct;
68 constexpr CopyAssign(CopyAssign&& o) noexcept
69 : value(o.value),
70 alive(o.alive),
71 copy_construct(o.copy_construct),
72 copy_assign(o.copy_assign),
73 move_construct(o.move_construct),
74 move_assign(o.move_assign) {
75 o.value = -1;
76 ++*alive;
77 ++*move_construct;
79 constexpr CopyAssign& operator=(const CopyAssign& o) {
80 value = o.value;
81 alive = o.alive;
82 copy_construct = o.copy_construct;
83 copy_assign = o.copy_assign;
84 move_construct = o.move_construct;
85 move_assign = o.move_assign;
86 ++*copy_assign;
87 return *this;
89 constexpr CopyAssign& operator=(CopyAssign&& o) noexcept {
90 value = o.value;
91 alive = o.alive;
92 copy_construct = o.copy_construct;
93 copy_assign = o.copy_assign;
94 move_construct = o.move_construct;
95 move_assign = o.move_assign;
96 o.value = -1;
97 ++*move_assign;
98 return *this;
100 TEST_CONSTEXPR_CXX20 ~CopyAssign() { --*alive; }
101 int value;
102 int* alive;
103 int* copy_construct;
104 int* copy_assign;
105 int* move_construct;
106 int* move_assign;
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) {
123 value = that.value;
124 return *this;
126 NTCopyAssign& operator=(NTCopyAssign&&) = delete;
127 int value;
130 static_assert(!std::is_trivially_copy_assignable<NTCopyAssign>::value, "");
131 static_assert(std::is_copy_assignable<NTCopyAssign>::value, "");
133 struct TCopyAssign {
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;
139 int value;
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) {
150 value = that.value;
151 that.value = -1;
152 return *this;
154 int value;
157 static_assert(std::is_trivially_copy_assignable_v<TCopyAssignNTMoveAssign>, "");
159 #ifndef TEST_HAS_NO_EXCEPTIONS
160 struct CopyThrows {
161 CopyThrows() = default;
162 CopyThrows(const CopyThrows&) { throw 42; }
163 CopyThrows& operator=(const CopyThrows&) { throw 42; }
166 struct CopyCannotThrow {
167 static int alive;
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 {
173 assert(false);
174 return *this;
178 int CopyCannotThrow::alive = 0;
180 struct MoveThrows {
181 static int alive;
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;
192 struct MakeEmptyT {
193 static int alive;
194 MakeEmptyT() { ++alive; }
195 MakeEmptyT(const MakeEmptyT&) {
196 ++alive;
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>);
211 try {
212 v = std::move(v2);
213 assert(false);
214 } catch (...) {
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>);
283 makeEmpty(v1);
284 V v2(std::in_place_index<0>);
285 makeEmpty(v2);
286 V& vref = (v1 = v2);
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>);
301 makeEmpty(v2);
302 V& vref = (v1 = v2);
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>);
311 makeEmpty(v2);
312 V& vref = (v1 = v2);
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>);
326 makeEmpty(v1);
327 V v2(std::in_place_index<0>, 42);
328 V& vref = (v1 = v2);
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>);
336 makeEmpty(v1);
337 V v2(std::in_place_type<std::string>, "hello");
338 V& vref = (v1 = v2);
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>
347 struct Result {
348 std::size_t index;
349 T value;
352 TEST_CONSTEXPR_CXX20 void test_copy_assignment_same_index() {
354 using V = std::variant<int>;
355 V v1(43);
356 V v2(42);
357 V& vref = (v1 = v2);
358 assert(&vref == &v1);
359 assert(v1.index() == 0);
360 assert(std::get<0>(v1) == 42);
363 using V = std::variant<int, long, unsigned>;
364 V v1(43l);
365 V v2(42l);
366 V& vref = (v1 = v2);
367 assert(&vref == &v1);
368 assert(v1.index() == 1);
369 assert(std::get<1>(v1) == 42);
372 using V = std::variant<int, CopyAssign, unsigned>;
373 int alive = 0;
374 int copy_construct = 0;
375 int copy_assign = 0;
376 int move_construct = 0;
377 int move_assign = 0;
378 V v1(std::in_place_type<CopyAssign>, 43, &alive, &copy_construct, &copy_assign, &move_construct, &move_assign);
379 V v2(std::in_place_type<CopyAssign>, 42, &alive, &copy_construct, &copy_assign, &move_construct, &move_assign);
380 V& vref = (v1 = v2);
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).
391 struct {
392 constexpr Result<int> operator()() const {
393 using V = std::variant<int>;
394 V v(43);
395 V v2(42);
396 v = v2;
397 return {v.index(), std::get<0>(v)};
399 } test;
400 constexpr auto result = test();
401 static_assert(result.index == 0, "");
402 static_assert(result.value == 42, "");
405 struct {
406 constexpr Result<long> operator()() const {
407 using V = std::variant<int, long, unsigned>;
408 V v(43l);
409 V v2(42l);
410 v = v2;
411 return {v.index(), std::get<1>(v)};
413 } test;
414 constexpr auto result = test();
415 static_assert(result.index == 1, "");
416 static_assert(result.value == 42l, "");
419 struct {
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);
424 v = v2;
425 return {v.index(), std::get<1>(v).value};
427 } test;
428 constexpr auto result = test();
429 static_assert(result.index == 1, "");
430 static_assert(result.value == 42, "");
433 struct {
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);
438 v = v2;
439 return {v.index(), std::get<1>(v).value};
441 } test;
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>;
451 V v1(43);
452 V v2(42l);
453 V& vref = (v1 = v2);
454 assert(&vref == &v1);
455 assert(v1.index() == 1);
456 assert(std::get<1>(v1) == 42);
459 using V = std::variant<int, CopyAssign, unsigned>;
460 int alive = 0;
461 int copy_construct = 0;
462 int copy_assign = 0;
463 int move_construct = 0;
464 int move_assign = 0;
465 V v1(std::in_place_type<unsigned>, 43u);
466 V v2(std::in_place_type<CopyAssign>, 42, &alive, &copy_construct, &copy_assign, &move_construct, &move_assign);
467 assert(copy_construct == 0);
468 assert(move_construct == 0);
469 assert(alive == 1);
470 V& vref = (v1 = v2);
471 assert(&vref == &v1);
472 assert(v1.index() == 1);
473 assert(std::get<1>(v1).value == 42);
474 assert(alive == 2);
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).
482 struct {
483 constexpr Result<long> operator()() const {
484 using V = std::variant<int, long, unsigned>;
485 V v(43);
486 V v2(42l);
487 v = v2;
488 return {v.index(), std::get<1>(v)};
490 } test;
491 constexpr auto result = test();
492 static_assert(result.index == 1, "");
493 static_assert(result.value == 42l, "");
496 struct {
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);
501 v = v2;
502 return {v.index(), std::get<1>(v).value};
504 } test;
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;
514 // same index
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>);
520 try {
521 v1 = v2;
522 assert(false);
523 } catch (...) {
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>);
534 try {
535 v1 = v2;
536 assert(false);
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.
549 v1 = v2;
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);
560 v1 = v2;
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");
569 V& vref = (v1 = v2);
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");
580 V& vref = (v1 = v2);
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));
594 v = cp;
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 {
611 int i = 0;
612 constexpr NonTrivialCopyAssign(int ii) : i(ii) {}
613 constexpr NonTrivialCopyAssign(const NonTrivialCopyAssign& other) : i(other.i) {}
614 constexpr NonTrivialCopyAssign& operator=(const NonTrivialCopyAssign& o) {
615 i = o.i;
616 return *this;
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();
646 return true;
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();
654 return true;
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());
665 #endif
666 return 0;