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