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;
XX33     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;
Y1Y145     Y1(const int&) {}
46     Y1& operator=(const Y1&) = delete;
47 };
48 
49 struct Y2
50 {
51     Y2() = default;
52     Y2(const int&) = delete;
operator =Y253     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 
resetAssignableFrom67   static void reset() {
68       type_constructed = int_constructed = 0;
69       type_assigned = int_assigned = 0;
70   }
71 
72   AssignableFrom() = default;
73 
AssignableFromAssignableFrom74   explicit AssignableFrom(T) { ++type_constructed; }
operator =AssignableFrom75   AssignableFrom& operator=(T) { ++type_assigned; return *this; }
76 
AssignableFromAssignableFrom77   AssignableFrom(int) { ++int_constructed; }
operator =AssignableFrom78   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 
test_with_test_type()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 
test_ambiguous_assign()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 
test()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 
main(int,char **)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