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, c++17
10 
11 // <copyable-box>& operator=(<copyable-box> const&)
12 
13 // ADDITIONAL_COMPILE_FLAGS: -Wno-self-assign-overloaded
14 
15 #include <ranges>
16 
17 #include <cassert>
18 #include <type_traits>
19 #include <utility> // in_place_t
20 
21 #include "test_macros.h"
22 #include "types.h"
23 
test()24 constexpr bool test() {
25   // Test the primary template
26   {
27     using Box = std::ranges::__movable_box<CopyConstructible>;
28     static_assert(std::is_copy_assignable_v<Box>);
29     static_assert(!std::is_nothrow_copy_assignable_v<Box>);
30 
31     {
32       Box x(std::in_place, 5);
33       Box const y(std::in_place, 10);
34       Box& result = (x = y);
35 
36       assert(&result == &x);
37       assert(x.__has_value());
38       assert(y.__has_value());
39       assert((*x).value == 10);
40     }
41     // check self-assignment
42     {
43       Box x(std::in_place, 5);
44       Box& result = (x = x);
45 
46       assert(&result == &x);
47       assert(x.__has_value());
48       assert((*x).value == 5);
49     }
50   }
51 
52   // Test optimization #1 for copy-assignment
53   {
54     using Box = std::ranges::__movable_box<Copyable>;
55     static_assert(std::is_copy_assignable_v<Box>);
56     static_assert(!std::is_nothrow_copy_assignable_v<Box>);
57 
58     {
59       Box x(std::in_place, 5);
60       Box const y(std::in_place, 10);
61       Box& result = (x = y);
62 
63       assert(&result == &x);
64       assert(x.__has_value());
65       assert(y.__has_value());
66       assert((*x).value == 10);
67       assert((*x).did_copy_assign);
68     }
69     // check self-assignment (should use the underlying type's assignment too)
70     {
71       Box x(std::in_place, 5);
72       Box& result = (x = x);
73 
74       assert(&result == &x);
75       assert(x.__has_value());
76       assert((*x).value == 5);
77       assert((*x).did_copy_assign);
78     }
79   }
80 
81   // Test optimization #2 for copy-assignment
82   {
83     using Box = std::ranges::__movable_box<NothrowCopyConstructible>;
84     static_assert(std::is_copy_assignable_v<Box>);
85     static_assert(std::is_nothrow_copy_assignable_v<Box>);
86 
87     {
88       Box x(std::in_place, 5);
89       Box const y(std::in_place, 10);
90       Box& result = (x = y);
91 
92       assert(&result == &x);
93       assert(x.__has_value());
94       assert(y.__has_value());
95       assert((*x).value == 10);
96     }
97     // check self-assignment
98     {
99       Box x(std::in_place, 5);
100       Box& result = (x = x);
101 
102       assert(&result == &x);
103       assert(x.__has_value());
104       assert((*x).value == 5);
105     }
106   }
107 
108   return true;
109 }
110 
111 // Tests for the empty state. Those can't be constexpr, since they are only reached
112 // through throwing an exception.
113 #if !defined(TEST_HAS_NO_EXCEPTIONS)
test_empty_state()114 void test_empty_state() {
115   using Box = std::ranges::__movable_box<ThrowsOnCopy>;
116 
117   // assign non-empty to empty
118   {
119     Box x = create_empty_box();
120     Box const y(std::in_place, 10);
121     Box& result = (x = y);
122 
123     assert(&result == &x);
124     assert(x.__has_value());
125     assert(y.__has_value());
126     assert((*x).value == 10);
127   }
128   // assign empty to non-empty
129   {
130     Box x(std::in_place, 5);
131     Box const y = create_empty_box();
132     Box& result = (x = y);
133 
134     assert(&result == &x);
135     assert(!x.__has_value());
136     assert(!y.__has_value());
137   }
138   // assign empty to empty
139   {
140     Box x       = create_empty_box();
141     Box const y = create_empty_box();
142     Box& result = (x = y);
143 
144     assert(&result == &x);
145     assert(!x.__has_value());
146     assert(!y.__has_value());
147   }
148   // check self-assignment in empty case
149   {
150     Box x       = create_empty_box();
151     Box& result = (x = x);
152 
153     assert(&result == &x);
154     assert(!x.__has_value());
155   }
156 }
157 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
158 
main(int,char **)159 int main(int, char**) {
160   assert(test());
161   static_assert(test());
162 
163 #if !defined(TEST_HAS_NO_EXCEPTIONS)
164   test_empty_state();
165 #endif
166 
167   return 0;
168 }
169