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 //===----------------------------------------------------------------------===//
8
9 // UNSUPPORTED: c++03, c++11, c++14
10
11 // <variant>
12
13 // template <class ...Types> class variant;
14
15 // constexpr variant& operator=(variant const&);
16
17 #include <cassert>
18 #include <string>
19 #include <type_traits>
20 #include <variant>
21
22 #include "test_macros.h"
23
24 struct NoCopy {
25 NoCopy(const NoCopy&) = delete;
26 NoCopy& operator=(const NoCopy&) = default;
27 };
28
29 struct CopyOnly {
30 CopyOnly(const CopyOnly&) = default;
31 CopyOnly(CopyOnly&&) = delete;
32 CopyOnly& operator=(const CopyOnly&) = default;
33 CopyOnly& operator=(CopyOnly&&) = delete;
34 };
35
36 struct MoveOnly {
37 MoveOnly(const MoveOnly&) = delete;
38 MoveOnly(MoveOnly&&) = default;
39 MoveOnly& operator=(const MoveOnly&) = default;
40 };
41
42 struct MoveOnlyNT {
43 MoveOnlyNT(const MoveOnlyNT&) = delete;
MoveOnlyNTMoveOnlyNT44 MoveOnlyNT(MoveOnlyNT&&) {}
45 MoveOnlyNT& operator=(const MoveOnlyNT&) = default;
46 };
47
48 struct CopyAssign {
CopyAssignCopyAssign49 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;
57 }
CopyAssignCopyAssign58 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;
67 }
CopyAssignCopyAssign68 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;
78 }
operator =CopyAssign79 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;
88 }
operator =CopyAssign89 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;
99 }
~CopyAssignCopyAssign100 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;
107 };
108
109 struct CopyMaybeThrows {
110 CopyMaybeThrows(const CopyMaybeThrows&);
111 CopyMaybeThrows& operator=(const CopyMaybeThrows&);
112 };
113 struct CopyDoesThrow {
114 CopyDoesThrow(const CopyDoesThrow&) noexcept(false);
115 CopyDoesThrow& operator=(const CopyDoesThrow&) noexcept(false);
116 };
117
118 struct NTCopyAssign {
NTCopyAssignNTCopyAssign119 constexpr NTCopyAssign(int v) : value(v) {}
120 NTCopyAssign(const NTCopyAssign&) = default;
121 NTCopyAssign(NTCopyAssign&&) = default;
operator =NTCopyAssign122 NTCopyAssign& operator=(const NTCopyAssign& that) {
123 value = that.value;
124 return *this;
125 };
126 NTCopyAssign& operator=(NTCopyAssign&&) = delete;
127 int value;
128 };
129
130 static_assert(!std::is_trivially_copy_assignable<NTCopyAssign>::value, "");
131 static_assert(std::is_copy_assignable<NTCopyAssign>::value, "");
132
133 struct TCopyAssign {
TCopyAssignTCopyAssign134 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;
140 };
141
142 static_assert(std::is_trivially_copy_assignable<TCopyAssign>::value, "");
143
144 struct TCopyAssignNTMoveAssign {
TCopyAssignNTMoveAssignTCopyAssignNTMoveAssign145 constexpr TCopyAssignNTMoveAssign(int v) : value(v) {}
146 TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign&) = default;
147 TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign&&) = default;
148 TCopyAssignNTMoveAssign& operator=(const TCopyAssignNTMoveAssign&) = default;
operator =TCopyAssignNTMoveAssign149 TCopyAssignNTMoveAssign& operator=(TCopyAssignNTMoveAssign&& that) {
150 value = that.value;
151 that.value = -1;
152 return *this;
153 }
154 int value;
155 };
156
157 static_assert(std::is_trivially_copy_assignable_v<TCopyAssignNTMoveAssign>, "");
158
159 #ifndef TEST_HAS_NO_EXCEPTIONS
160 struct CopyThrows {
161 CopyThrows() = default;
CopyThrowsCopyThrows162 CopyThrows(const CopyThrows&) { throw 42; }
operator =CopyThrows163 CopyThrows& operator=(const CopyThrows&) { throw 42; }
164 };
165
166 struct CopyCannotThrow {
167 static int alive;
CopyCannotThrowCopyCannotThrow168 CopyCannotThrow() { ++alive; }
CopyCannotThrowCopyCannotThrow169 CopyCannotThrow(const CopyCannotThrow&) noexcept { ++alive; }
CopyCannotThrowCopyCannotThrow170 CopyCannotThrow(CopyCannotThrow&&) noexcept { assert(false); }
171 CopyCannotThrow& operator=(const CopyCannotThrow&) noexcept = default;
operator =CopyCannotThrow172 CopyCannotThrow& operator=(CopyCannotThrow&&) noexcept {
173 assert(false);
174 return *this;
175 }
176 };
177
178 int CopyCannotThrow::alive = 0;
179
180 struct MoveThrows {
181 static int alive;
MoveThrowsMoveThrows182 MoveThrows() { ++alive; }
MoveThrowsMoveThrows183 MoveThrows(const MoveThrows&) { ++alive; }
MoveThrowsMoveThrows184 MoveThrows(MoveThrows&&) { throw 42; }
operator =MoveThrows185 MoveThrows& operator=(const MoveThrows&) { return *this; }
operator =MoveThrows186 MoveThrows& operator=(MoveThrows&&) { throw 42; }
~MoveThrowsMoveThrows187 ~MoveThrows() { --alive; }
188 };
189
190 int MoveThrows::alive = 0;
191
192 struct MakeEmptyT {
193 static int alive;
MakeEmptyTMakeEmptyT194 MakeEmptyT() { ++alive; }
MakeEmptyTMakeEmptyT195 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.
199 }
MakeEmptyTMakeEmptyT200 MakeEmptyT(MakeEmptyT&&) { throw 42; }
operator =MakeEmptyT201 MakeEmptyT& operator=(const MakeEmptyT&) { throw 42; }
operator =MakeEmptyT202 MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }
~MakeEmptyTMakeEmptyT203 ~MakeEmptyT() { --alive; }
204 };
205
206 int MakeEmptyT::alive = 0;
207
208 template <class Variant>
makeEmpty(Variant & v)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());
216 }
217 }
218 #endif // TEST_HAS_NO_EXCEPTIONS
219
test_copy_assignment_not_noexcept()220 constexpr void test_copy_assignment_not_noexcept() {
221 {
222 using V = std::variant<CopyMaybeThrows>;
223 static_assert(!std::is_nothrow_copy_assignable<V>::value, "");
224 }
225 {
226 using V = std::variant<int, CopyDoesThrow>;
227 static_assert(!std::is_nothrow_copy_assignable<V>::value, "");
228 }
229 }
230
test_copy_assignment_sfinae()231 constexpr void test_copy_assignment_sfinae() {
232 {
233 using V = std::variant<int, long>;
234 static_assert(std::is_copy_assignable<V>::value, "");
235 }
236 {
237 using V = std::variant<int, CopyOnly>;
238 static_assert(std::is_copy_assignable<V>::value, "");
239 }
240 {
241 using V = std::variant<int, NoCopy>;
242 static_assert(!std::is_copy_assignable<V>::value, "");
243 }
244 {
245 using V = std::variant<int, MoveOnly>;
246 static_assert(!std::is_copy_assignable<V>::value, "");
247 }
248 {
249 using V = std::variant<int, MoveOnlyNT>;
250 static_assert(!std::is_copy_assignable<V>::value, "");
251 }
252
253 // Make sure we properly propagate triviality (see P0602R4).
254 {
255 using V = std::variant<int, long>;
256 static_assert(std::is_trivially_copy_assignable<V>::value, "");
257 }
258 {
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, "");
262 }
263 {
264 using V = std::variant<int, TCopyAssign>;
265 static_assert(std::is_trivially_copy_assignable<V>::value, "");
266 }
267 {
268 using V = std::variant<int, TCopyAssignNTMoveAssign>;
269 static_assert(std::is_trivially_copy_assignable<V>::value, "");
270 }
271 {
272 using V = std::variant<int, CopyOnly>;
273 static_assert(std::is_trivially_copy_assignable<V>::value, "");
274 }
275 }
276
test_copy_assignment_empty_empty()277 void test_copy_assignment_empty_empty() {
278 #ifndef TEST_HAS_NO_EXCEPTIONS
279 using MET = MakeEmptyT;
280 {
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);
290 }
291 #endif // TEST_HAS_NO_EXCEPTIONS
292 }
293
test_copy_assignment_non_empty_empty()294 void test_copy_assignment_non_empty_empty() {
295 #ifndef TEST_HAS_NO_EXCEPTIONS
296 using MET = MakeEmptyT;
297 {
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);
306 }
307 {
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);
316 }
317 #endif // TEST_HAS_NO_EXCEPTIONS
318 }
319
test_copy_assignment_empty_non_empty()320 void test_copy_assignment_empty_non_empty() {
321 #ifndef TEST_HAS_NO_EXCEPTIONS
322 using MET = MakeEmptyT;
323 {
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);
332 }
333 {
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");
342 }
343 #endif // TEST_HAS_NO_EXCEPTIONS
344 }
345
346 template <typename T>
347 struct Result {
348 std::size_t index;
349 T value;
350 };
351
test_copy_assignment_same_index()352 TEST_CONSTEXPR_CXX20 void test_copy_assignment_same_index() {
353 {
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);
361 }
362 {
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);
370 }
371 {
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, ©_construct, ©_assign, &move_construct, &move_assign);
379 V v2(std::in_place_type<CopyAssign>, 42, &alive, ©_construct, ©_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);
387 }
388
389 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
390 {
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)};
398 }
399 } test;
400 constexpr auto result = test();
401 static_assert(result.index == 0, "");
402 static_assert(result.value == 42, "");
403 }
404 {
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)};
412 }
413 } test;
414 constexpr auto result = test();
415 static_assert(result.index == 1, "");
416 static_assert(result.value == 42l, "");
417 }
418 {
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};
426 }
427 } test;
428 constexpr auto result = test();
429 static_assert(result.index == 1, "");
430 static_assert(result.value == 42, "");
431 }
432 {
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};
440 }
441 } test;
442 constexpr auto result = test();
443 static_assert(result.index == 1, "");
444 static_assert(result.value == 42, "");
445 }
446 }
447
test_copy_assignment_different_index()448 TEST_CONSTEXPR_CXX20 void test_copy_assignment_different_index() {
449 {
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);
457 }
458 {
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, ©_construct, ©_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);
478 }
479
480 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
481 {
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)};
489 }
490 } test;
491 constexpr auto result = test();
492 static_assert(result.index == 1, "");
493 static_assert(result.value == 42l, "");
494 }
495 {
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};
503 }
504 } test;
505 constexpr auto result = test();
506 static_assert(result.index == 1, "");
507 static_assert(result.value == 42, "");
508 }
509 }
510
test_assignment_throw()511 void test_assignment_throw() {
512 #ifndef TEST_HAS_NO_EXCEPTIONS
513 using MET = MakeEmptyT;
514 // same index
515 {
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 (...) {
524 }
525 assert(v1.index() == 1);
526 assert(&std::get<1>(v1) == &mref);
527 }
528
529 // difference indices
530 {
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 (...) { /* ... */
538 }
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());
542 }
543 {
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);
553 }
554 {
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);
564 }
565 {
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");
575 }
576 {
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");
586 }
587 #endif // TEST_HAS_NO_EXCEPTIONS
588 }
589
590 template <std::size_t NewIdx, class T, class ValueType>
test_constexpr_assign_imp(T && v,ValueType && new_value)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));
597 }
598
test_constexpr_copy_assignment_trivial()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);
608 }
609
610 struct NonTrivialCopyAssign {
611 int i = 0;
NonTrivialCopyAssignNonTrivialCopyAssign612 constexpr NonTrivialCopyAssign(int ii) : i(ii) {}
NonTrivialCopyAssignNonTrivialCopyAssign613 constexpr NonTrivialCopyAssign(const NonTrivialCopyAssign& other) : i(other.i) {}
operator =NonTrivialCopyAssign614 constexpr NonTrivialCopyAssign& operator=(const NonTrivialCopyAssign& o) {
615 i = o.i;
616 return *this;
617 }
618 TEST_CONSTEXPR_CXX20 ~NonTrivialCopyAssign() = default;
operator ==(const NonTrivialCopyAssign & x,const NonTrivialCopyAssign & y)619 friend constexpr bool operator==(const NonTrivialCopyAssign& x, const NonTrivialCopyAssign& y) { return x.i == y.i; }
620 };
621
test_constexpr_copy_assignment_non_trivial()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));
632 }
633
non_constexpr_test()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();
639 }
640
cxx17_constexpr_test()641 constexpr bool cxx17_constexpr_test() {
642 test_copy_assignment_sfinae();
643 test_copy_assignment_not_noexcept();
644 test_constexpr_copy_assignment_trivial();
645
646 return true;
647 }
648
cxx20_constexpr_test()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();
653
654 return true;
655 }
656
main(int,char **)657 int main(int, char**) {
658 non_constexpr_test();
659 cxx17_constexpr_test();
660 cxx20_constexpr_test();
661
662 static_assert(cxx17_constexpr_test());
663 #if TEST_STD_VER >= 20
664 static_assert(cxx20_constexpr_test());
665 #endif
666 return 0;
667 }
668