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++98, 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 #include <type_traits>
18 #include <memory>
19 #include <cassert>
20 
21 #include "test_macros.h"
22 #include "archetypes.h"
23 
24 using std::optional;
25 
26 struct X
27 {
28     static bool throw_now;
29 
30     X() = default;
31     X(int &&)
32     {
33         if (throw_now)
34             TEST_THROW(6);
35     }
36 };
37 
38 bool X::throw_now = false;
39 
40 struct Y1
41 {
42     Y1() = default;
43     Y1(const int&) {}
44     Y1& operator=(const Y1&) = delete;
45 };
46 
47 struct Y2
48 {
49     Y2() = default;
50     Y2(const int&) = delete;
51     Y2& operator=(const int&) { return *this; }
52 };
53 
54 class B {};
55 class D : public B {};
56 
57 
58 template <class T>
59 struct AssignableFrom {
60   static int type_constructed;
61   static int type_assigned;
62 static int int_constructed;
63   static int int_assigned;
64 
65   static void reset() {
66       type_constructed = int_constructed = 0;
67       type_assigned = int_assigned = 0;
68   }
69 
70   AssignableFrom() = default;
71 
72   explicit AssignableFrom(T) { ++type_constructed; }
73   AssignableFrom& operator=(T) { ++type_assigned; return *this; }
74 
75   AssignableFrom(int) { ++int_constructed; }
76   AssignableFrom& operator=(int) { ++int_assigned; return *this; }
77 private:
78   AssignableFrom(AssignableFrom const&) = delete;
79   AssignableFrom& operator=(AssignableFrom const&) = delete;
80 };
81 
82 template <class T> int AssignableFrom<T>::type_constructed = 0;
83 template <class T> int AssignableFrom<T>::type_assigned = 0;
84 template <class T> int AssignableFrom<T>::int_constructed = 0;
85 template <class T> int AssignableFrom<T>::int_assigned = 0;
86 
87 void test_with_test_type() {
88     using T = TestTypes::TestType;
89     T::reset();
90     { // non-empty to empty
91         T::reset_constructors();
92         optional<T> opt;
93         optional<int> other(42);
94         opt = std::move(other);
95         assert(T::alive == 1);
96         assert(T::constructed == 1);
97         assert(T::value_constructed == 1);
98         assert(T::assigned == 0);
99         assert(T::destroyed == 0);
100         assert(static_cast<bool>(other) == true);
101         assert(*other == 42);
102         assert(static_cast<bool>(opt) == true);
103         assert(*opt == T(42));
104     }
105     assert(T::alive == 0);
106     { // non-empty to non-empty
107         optional<T> opt(101);
108         optional<int> other(42);
109         T::reset_constructors();
110         opt = std::move(other);
111         assert(T::alive == 1);
112         assert(T::constructed == 0);
113         assert(T::assigned == 1);
114         assert(T::value_assigned == 1);
115         assert(T::destroyed == 0);
116         assert(static_cast<bool>(other) == true);
117         assert(*other == 42);
118         assert(static_cast<bool>(opt) == true);
119         assert(*opt == T(42));
120     }
121     assert(T::alive == 0);
122     { // empty to non-empty
123         optional<T> opt(101);
124         optional<int> other;
125         T::reset_constructors();
126         opt = std::move(other);
127         assert(T::alive == 0);
128         assert(T::constructed == 0);
129         assert(T::assigned == 0);
130         assert(T::destroyed == 1);
131         assert(static_cast<bool>(other) == false);
132         assert(static_cast<bool>(opt) == false);
133     }
134     assert(T::alive == 0);
135     { // empty to empty
136         optional<T> opt;
137         optional<int> other;
138         T::reset_constructors();
139         opt = std::move(other);
140         assert(T::alive == 0);
141         assert(T::constructed == 0);
142         assert(T::assigned == 0);
143         assert(T::destroyed == 0);
144         assert(static_cast<bool>(other) == false);
145         assert(static_cast<bool>(opt) == false);
146     }
147     assert(T::alive == 0);
148 }
149 
150 
151 void test_ambiguous_assign() {
152     using OptInt = std::optional<int>;
153     {
154         using T = AssignableFrom<OptInt&&>;
155         T::reset();
156         {
157             OptInt a(42);
158             std::optional<T> t;
159             t = std::move(a);
160             assert(T::type_constructed == 1);
161             assert(T::type_assigned == 0);
162             assert(T::int_constructed == 0);
163             assert(T::int_assigned == 0);
164         }
165         {
166             using Opt = std::optional<T>;
167             static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, "");
168             static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
169             static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
170         }
171     }
172     {
173         using T = AssignableFrom<OptInt const&&>;
174         T::reset();
175         {
176             const OptInt a(42);
177             std::optional<T> t;
178             t = std::move(a);
179             assert(T::type_constructed == 1);
180             assert(T::type_assigned == 0);
181             assert(T::int_constructed == 0);
182             assert(T::int_assigned == 0);
183         }
184         T::reset();
185         {
186             OptInt a(42);
187             std::optional<T> t;
188             t = std::move(a);
189             assert(T::type_constructed == 1);
190             assert(T::type_assigned == 0);
191             assert(T::int_constructed == 0);
192             assert(T::int_assigned == 0);
193         }
194         {
195             using Opt = std::optional<T>;
196             static_assert(std::is_assignable<Opt&, OptInt&&>::value, "");
197             static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
198             static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
199         }
200     }
201 }
202 
203 
204 int main(int, char**)
205 {
206     test_with_test_type();
207     test_ambiguous_assign();
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         optional<std::unique_ptr<B>> opt;
242         optional<std::unique_ptr<D>> other(new D());
243         opt = std::move(other);
244         assert(static_cast<bool>(opt) == true);
245         assert(static_cast<bool>(other) == true);
246         assert(opt->get() != nullptr);
247         assert(other->get() == nullptr);
248     }
249 #ifndef TEST_HAS_NO_EXCEPTIONS
250     {
251         optional<X> opt;
252         optional<int> opt2(42);
253         assert(static_cast<bool>(opt2) == true);
254         try
255         {
256             X::throw_now = true;
257             opt = std::move(opt2);
258             assert(false);
259         }
260         catch (int i)
261         {
262             assert(i == 6);
263             assert(static_cast<bool>(opt) == false);
264         }
265     }
266 #endif
267 
268   return 0;
269 }
270