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