1 //===----------------------------------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // UNSUPPORTED: c++98, c++03, c++11, c++14
11 // <optional>
12
13 // From LWG2451:
14 // template <class U>
15 // optional<T>& operator=(optional<U>&& rhs);
16
17 #include <optional>
18 #include <type_traits>
19 #include <memory>
20 #include <cassert>
21
22 #include "test_macros.h"
23 #include "archetypes.hpp"
24
25 using std::optional;
26
27 struct X
28 {
29 static bool throw_now;
30
31 X() = default;
XX32 X(int &&)
33 {
34 if (throw_now)
35 TEST_THROW(6);
36 }
37 };
38
39 bool X::throw_now = false;
40
41 struct Y1
42 {
43 Y1() = default;
Y1Y144 Y1(const int&) {}
45 Y1& operator=(const Y1&) = delete;
46 };
47
48 struct Y2
49 {
50 Y2() = default;
51 Y2(const int&) = delete;
operator =Y252 Y2& operator=(const int&) { return *this; }
53 };
54
55 class B {};
56 class D : public B {};
57
58
59 template <class T>
60 struct AssignableFrom {
61 static int type_constructed;
62 static int type_assigned;
63 static int int_constructed;
64 static int int_assigned;
65
resetAssignableFrom66 static void reset() {
67 type_constructed = int_constructed = 0;
68 type_assigned = int_assigned = 0;
69 }
70
71 AssignableFrom() = default;
72
AssignableFromAssignableFrom73 explicit AssignableFrom(T) { ++type_constructed; }
operator =AssignableFrom74 AssignableFrom& operator=(T) { ++type_assigned; return *this; }
75
AssignableFromAssignableFrom76 AssignableFrom(int) { ++int_constructed; }
operator =AssignableFrom77 AssignableFrom& operator=(int) { ++int_assigned; return *this; }
78 private:
79 AssignableFrom(AssignableFrom const&) = delete;
80 AssignableFrom& operator=(AssignableFrom const&) = delete;
81 };
82
83 template <class T> int AssignableFrom<T>::type_constructed = 0;
84 template <class T> int AssignableFrom<T>::type_assigned = 0;
85 template <class T> int AssignableFrom<T>::int_constructed = 0;
86 template <class T> int AssignableFrom<T>::int_assigned = 0;
87
test_with_test_type()88 void test_with_test_type() {
89 using T = TestTypes::TestType;
90 T::reset();
91 { // non-empty to empty
92 T::reset_constructors();
93 optional<T> opt;
94 optional<int> other(42);
95 opt = std::move(other);
96 assert(T::alive == 1);
97 assert(T::constructed == 1);
98 assert(T::value_constructed == 1);
99 assert(T::assigned == 0);
100 assert(T::destroyed == 0);
101 assert(static_cast<bool>(other) == true);
102 assert(*other == 42);
103 assert(static_cast<bool>(opt) == true);
104 assert(*opt == T(42));
105 }
106 assert(T::alive == 0);
107 { // non-empty to non-empty
108 optional<T> opt(101);
109 optional<int> other(42);
110 T::reset_constructors();
111 opt = std::move(other);
112 assert(T::alive == 1);
113 assert(T::constructed == 0);
114 assert(T::assigned == 1);
115 assert(T::value_assigned == 1);
116 assert(T::destroyed == 0);
117 assert(static_cast<bool>(other) == true);
118 assert(*other == 42);
119 assert(static_cast<bool>(opt) == true);
120 assert(*opt == T(42));
121 }
122 assert(T::alive == 0);
123 { // empty to non-empty
124 optional<T> opt(101);
125 optional<int> other;
126 T::reset_constructors();
127 opt = std::move(other);
128 assert(T::alive == 0);
129 assert(T::constructed == 0);
130 assert(T::assigned == 0);
131 assert(T::destroyed == 1);
132 assert(static_cast<bool>(other) == false);
133 assert(static_cast<bool>(opt) == false);
134 }
135 assert(T::alive == 0);
136 { // empty to empty
137 optional<T> opt;
138 optional<int> other;
139 T::reset_constructors();
140 opt = std::move(other);
141 assert(T::alive == 0);
142 assert(T::constructed == 0);
143 assert(T::assigned == 0);
144 assert(T::destroyed == 0);
145 assert(static_cast<bool>(other) == false);
146 assert(static_cast<bool>(opt) == false);
147 }
148 assert(T::alive == 0);
149 }
150
151
test_ambigious_assign()152 void test_ambigious_assign() {
153 using OptInt = std::optional<int>;
154 {
155 using T = AssignableFrom<OptInt&&>;
156 T::reset();
157 {
158 OptInt a(42);
159 std::optional<T> t;
160 t = std::move(a);
161 assert(T::type_constructed == 1);
162 assert(T::type_assigned == 0);
163 assert(T::int_constructed == 0);
164 assert(T::int_assigned == 0);
165 }
166 {
167 using Opt = std::optional<T>;
168 static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, "");
169 static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
170 static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
171 }
172 }
173 {
174 using T = AssignableFrom<OptInt const&&>;
175 T::reset();
176 {
177 const OptInt a(42);
178 std::optional<T> t;
179 t = std::move(a);
180 assert(T::type_constructed == 1);
181 assert(T::type_assigned == 0);
182 assert(T::int_constructed == 0);
183 assert(T::int_assigned == 0);
184 }
185 T::reset();
186 {
187 OptInt a(42);
188 std::optional<T> t;
189 t = std::move(a);
190 assert(T::type_constructed == 1);
191 assert(T::type_assigned == 0);
192 assert(T::int_constructed == 0);
193 assert(T::int_assigned == 0);
194 }
195 {
196 using Opt = std::optional<T>;
197 static_assert(std::is_assignable<Opt&, OptInt&&>::value, "");
198 static_assert(!std::is_assignable<Opt&, const OptInt&>::value, "");
199 static_assert(!std::is_assignable<Opt&, OptInt&>::value, "");
200 }
201 }
202 }
203
204
main()205 int main()
206 {
207 test_with_test_type();
208 test_ambigious_assign();
209 {
210 optional<int> opt;
211 optional<short> opt2;
212 opt = std::move(opt2);
213 assert(static_cast<bool>(opt2) == false);
214 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
215 }
216 {
217 optional<int> opt;
218 optional<short> opt2(short{2});
219 opt = std::move(opt2);
220 assert(static_cast<bool>(opt2) == true);
221 assert(*opt2 == 2);
222 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
223 assert(*opt == *opt2);
224 }
225 {
226 optional<int> opt(3);
227 optional<short> opt2;
228 opt = std::move(opt2);
229 assert(static_cast<bool>(opt2) == false);
230 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
231 }
232 {
233 optional<int> opt(3);
234 optional<short> opt2(short{2});
235 opt = std::move(opt2);
236 assert(static_cast<bool>(opt2) == true);
237 assert(*opt2 == 2);
238 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
239 assert(*opt == *opt2);
240 }
241 {
242 optional<std::unique_ptr<B>> opt;
243 optional<std::unique_ptr<D>> other(new D());
244 opt = std::move(other);
245 assert(static_cast<bool>(opt) == true);
246 assert(static_cast<bool>(other) == true);
247 assert(opt->get() != nullptr);
248 assert(other->get() == nullptr);
249 }
250 #ifndef TEST_HAS_NO_EXCEPTIONS
251 {
252 optional<X> opt;
253 optional<int> opt2(42);
254 assert(static_cast<bool>(opt2) == true);
255 try
256 {
257 X::throw_now = true;
258 opt = std::move(opt2);
259 assert(false);
260 }
261 catch (int i)
262 {
263 assert(i == 6);
264 assert(static_cast<bool>(opt) == false);
265 }
266 }
267 #endif
268 }
269