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
26using std::optional;
27
28struct 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
40bool X::throw_now = false;
41
42struct Y1
43{
44 Y1() = default;
45 Y1(const int&) {}
46 Y1& operator=(const Y1&) = delete;
47};
48
49struct Y2
50{
51 Y2() = default;
52 Y2(const int&) = delete;
53 Y2& operator=(const int&) { return *this; }
54};
55
56struct B { virtual ~B() = default; };
57class D : public B {};
58
59
60template <class T>
61struct AssignableFrom {
62 static int type_constructed;
63 static int type_assigned;
64static 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; }
79private:
80 AssignableFrom(AssignableFrom const&) = delete;
81 AssignableFrom& operator=(AssignableFrom const&) = delete;
82};
83
84template <class T> int AssignableFrom<T>::type_constructed = 0;
85template <class T> int AssignableFrom<T>::type_assigned = 0;
86template <class T> int AssignableFrom<T>::int_constructed = 0;
87template <class T> int AssignableFrom<T>::int_assigned = 0;
88
89void 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
153void 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
206TEST_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
301int 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

source code of libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp