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 | // <optional> |
11 | |
12 | // From LWG2451: |
13 | // template <class U> |
14 | // optional<T>& operator=(optional<U>&& rhs); |
15 | |
16 | #include <optional> |
17 | |
18 | #include <array> |
19 | #include <cassert> |
20 | #include <memory> |
21 | #include <type_traits> |
22 | |
23 | #include "test_macros.h" |
24 | #include "archetypes.h" |
25 | |
26 | using std::optional; |
27 | |
28 | struct X |
29 | { |
30 | static bool throw_now; |
31 | |
32 | X() = default; |
33 | X(int &&) |
34 | { |
35 | if (throw_now) |
36 | TEST_THROW(6); |
37 | } |
38 | }; |
39 | |
40 | bool X::throw_now = false; |
41 | |
42 | struct Y1 |
43 | { |
44 | Y1() = default; |
45 | Y1(const int&) {} |
46 | Y1& operator=(const Y1&) = delete; |
47 | }; |
48 | |
49 | struct Y2 |
50 | { |
51 | Y2() = default; |
52 | Y2(const int&) = delete; |
53 | Y2& operator=(const int&) { return *this; } |
54 | }; |
55 | |
56 | struct B { virtual ~B() = default; }; |
57 | class D : public B {}; |
58 | |
59 | |
60 | template <class T> |
61 | struct AssignableFrom { |
62 | static int type_constructed; |
63 | static int type_assigned; |
64 | static int int_constructed; |
65 | static int int_assigned; |
66 | |
67 | static void reset() { |
68 | type_constructed = int_constructed = 0; |
69 | type_assigned = int_assigned = 0; |
70 | } |
71 | |
72 | AssignableFrom() = default; |
73 | |
74 | explicit AssignableFrom(T) { ++type_constructed; } |
75 | AssignableFrom& operator=(T) { ++type_assigned; return *this; } |
76 | |
77 | AssignableFrom(int) { ++int_constructed; } |
78 | AssignableFrom& operator=(int) { ++int_assigned; return *this; } |
79 | private: |
80 | AssignableFrom(AssignableFrom const&) = delete; |
81 | AssignableFrom& operator=(AssignableFrom const&) = delete; |
82 | }; |
83 | |
84 | template <class T> int AssignableFrom<T>::type_constructed = 0; |
85 | template <class T> int AssignableFrom<T>::type_assigned = 0; |
86 | template <class T> int AssignableFrom<T>::int_constructed = 0; |
87 | template <class T> int AssignableFrom<T>::int_assigned = 0; |
88 | |
89 | void test_with_test_type() { |
90 | using T = TestTypes::TestType; |
91 | T::reset(); |
92 | { // non-empty to empty |
93 | T::reset_constructors(); |
94 | optional<T> opt; |
95 | optional<int> other(42); |
96 | opt = std::move(other); |
97 | assert(T::alive == 1); |
98 | assert(T::constructed == 1); |
99 | assert(T::value_constructed == 1); |
100 | assert(T::assigned == 0); |
101 | assert(T::destroyed == 0); |
102 | assert(static_cast<bool>(other) == true); |
103 | assert(*other == 42); |
104 | assert(static_cast<bool>(opt) == true); |
105 | assert(*opt == T(42)); |
106 | } |
107 | assert(T::alive == 0); |
108 | { // non-empty to non-empty |
109 | optional<T> opt(101); |
110 | optional<int> other(42); |
111 | T::reset_constructors(); |
112 | opt = std::move(other); |
113 | assert(T::alive == 1); |
114 | assert(T::constructed == 0); |
115 | assert(T::assigned == 1); |
116 | assert(T::value_assigned == 1); |
117 | assert(T::destroyed == 0); |
118 | assert(static_cast<bool>(other) == true); |
119 | assert(*other == 42); |
120 | assert(static_cast<bool>(opt) == true); |
121 | assert(*opt == T(42)); |
122 | } |
123 | assert(T::alive == 0); |
124 | { // empty to non-empty |
125 | optional<T> opt(101); |
126 | optional<int> other; |
127 | T::reset_constructors(); |
128 | opt = std::move(other); |
129 | assert(T::alive == 0); |
130 | assert(T::constructed == 0); |
131 | assert(T::assigned == 0); |
132 | assert(T::destroyed == 1); |
133 | assert(static_cast<bool>(other) == false); |
134 | assert(static_cast<bool>(opt) == false); |
135 | } |
136 | assert(T::alive == 0); |
137 | { // empty to empty |
138 | optional<T> opt; |
139 | optional<int> other; |
140 | T::reset_constructors(); |
141 | opt = std::move(other); |
142 | assert(T::alive == 0); |
143 | assert(T::constructed == 0); |
144 | assert(T::assigned == 0); |
145 | assert(T::destroyed == 0); |
146 | assert(static_cast<bool>(other) == false); |
147 | assert(static_cast<bool>(opt) == false); |
148 | } |
149 | assert(T::alive == 0); |
150 | } |
151 | |
152 | |
153 | void test_ambiguous_assign() { |
154 | using OptInt = std::optional<int>; |
155 | { |
156 | using T = AssignableFrom<OptInt&&>; |
157 | T::reset(); |
158 | { |
159 | OptInt a(42); |
160 | std::optional<T> t; |
161 | t = std::move(a); |
162 | assert(T::type_constructed == 1); |
163 | assert(T::type_assigned == 0); |
164 | assert(T::int_constructed == 0); |
165 | assert(T::int_assigned == 0); |
166 | } |
167 | { |
168 | using Opt = std::optional<T>; |
169 | static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, "" ); |
170 | static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "" ); |
171 | static_assert(!std::is_assignable<Opt&, OptInt&>::value, "" ); |
172 | } |
173 | } |
174 | { |
175 | using T = AssignableFrom<OptInt const&&>; |
176 | T::reset(); |
177 | { |
178 | const OptInt a(42); |
179 | std::optional<T> t; |
180 | t = std::move(a); |
181 | assert(T::type_constructed == 1); |
182 | assert(T::type_assigned == 0); |
183 | assert(T::int_constructed == 0); |
184 | assert(T::int_assigned == 0); |
185 | } |
186 | T::reset(); |
187 | { |
188 | OptInt a(42); |
189 | std::optional<T> t; |
190 | t = std::move(a); |
191 | assert(T::type_constructed == 1); |
192 | assert(T::type_assigned == 0); |
193 | assert(T::int_constructed == 0); |
194 | assert(T::int_assigned == 0); |
195 | } |
196 | { |
197 | using Opt = std::optional<T>; |
198 | static_assert(std::is_assignable<Opt&, OptInt&&>::value, "" ); |
199 | static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "" ); |
200 | static_assert(!std::is_assignable<Opt&, OptInt&>::value, "" ); |
201 | } |
202 | } |
203 | } |
204 | |
205 | |
206 | TEST_CONSTEXPR_CXX20 bool test() |
207 | { |
208 | { |
209 | optional<int> opt; |
210 | optional<short> opt2; |
211 | opt = std::move(opt2); |
212 | assert(static_cast<bool>(opt2) == false); |
213 | assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); |
214 | } |
215 | { |
216 | optional<int> opt; |
217 | optional<short> opt2(short{2}); |
218 | opt = std::move(opt2); |
219 | assert(static_cast<bool>(opt2) == true); |
220 | assert(*opt2 == 2); |
221 | assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); |
222 | assert(*opt == *opt2); |
223 | } |
224 | { |
225 | optional<int> opt(3); |
226 | optional<short> opt2; |
227 | opt = std::move(opt2); |
228 | assert(static_cast<bool>(opt2) == false); |
229 | assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); |
230 | } |
231 | { |
232 | optional<int> opt(3); |
233 | optional<short> opt2(short{2}); |
234 | opt = std::move(opt2); |
235 | assert(static_cast<bool>(opt2) == true); |
236 | assert(*opt2 == 2); |
237 | assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); |
238 | assert(*opt == *opt2); |
239 | } |
240 | |
241 | enum class state_t { inactive, constructed, copy_assigned, move_assigned }; |
242 | class StateTracker { |
243 | public: |
244 | constexpr StateTracker(state_t& s) |
245 | : state_(&s) |
246 | { |
247 | *state_ = state_t::constructed; |
248 | } |
249 | |
250 | StateTracker(StateTracker&&) = default; |
251 | StateTracker(StateTracker const&) = default; |
252 | |
253 | constexpr StateTracker& operator=(StateTracker&& other) noexcept |
254 | { |
255 | *state_ = state_t::inactive; |
256 | state_ = other.state_; |
257 | *state_ = state_t::move_assigned; |
258 | other.state_ = nullptr; |
259 | return *this; |
260 | } |
261 | |
262 | constexpr StateTracker& operator=(StateTracker const& other) noexcept |
263 | { |
264 | *state_ = state_t::inactive; |
265 | state_ = other.state_; |
266 | *state_ = state_t::copy_assigned; |
267 | return *this; |
268 | } |
269 | private: |
270 | state_t* state_; |
271 | }; |
272 | { |
273 | auto state = std::array{state_t::inactive, state_t::inactive}; |
274 | auto opt1 = std::optional<StateTracker>(state[0]); |
275 | assert(state[0] == state_t::constructed); |
276 | |
277 | auto opt2 = std::optional<StateTracker>(state[1]); |
278 | assert(state[1] == state_t::constructed); |
279 | |
280 | opt1 = std::move(opt2); |
281 | assert(state[0] == state_t::inactive); |
282 | assert(state[1] == state_t::move_assigned); |
283 | } |
284 | { |
285 | auto state = std::array{state_t::inactive, state_t::inactive}; |
286 | auto opt1 = std::optional<StateTracker>(state[0]); |
287 | assert(state[0] == state_t::constructed); |
288 | |
289 | auto opt2 = std::optional<StateTracker>(state[1]); |
290 | assert(state[1] == state_t::constructed); |
291 | |
292 | opt1 = opt2; |
293 | assert(state[0] == state_t::inactive); |
294 | assert(state[1] == state_t::copy_assigned); |
295 | } |
296 | |
297 | return true; |
298 | } |
299 | |
300 | |
301 | int main(int, char**) |
302 | { |
303 | #if TEST_STD_VER > 17 |
304 | static_assert(test()); |
305 | #endif |
306 | test_with_test_type(); |
307 | test_ambiguous_assign(); |
308 | test(); |
309 | { |
310 | optional<std::unique_ptr<B>> opt; |
311 | optional<std::unique_ptr<D>> other(new D()); |
312 | opt = std::move(other); |
313 | assert(static_cast<bool>(opt) == true); |
314 | assert(static_cast<bool>(other) == true); |
315 | assert(opt->get() != nullptr); |
316 | assert(other->get() == nullptr); |
317 | } |
318 | #ifndef TEST_HAS_NO_EXCEPTIONS |
319 | { |
320 | optional<X> opt; |
321 | optional<int> opt2(42); |
322 | assert(static_cast<bool>(opt2) == true); |
323 | try |
324 | { |
325 | X::throw_now = true; |
326 | opt = std::move(opt2); |
327 | assert(false); |
328 | } |
329 | catch (int i) |
330 | { |
331 | assert(i == 6); |
332 | assert(static_cast<bool>(opt) == false); |
333 | } |
334 | } |
335 | #endif |
336 | |
337 | return 0; |
338 | } |
339 | |