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 | // template <class U> optional<T>& operator=(U&& v); |
13 | |
14 | #include <optional> |
15 | #include <type_traits> |
16 | #include <cassert> |
17 | #include <memory> |
18 | |
19 | #include "test_macros.h" |
20 | #include "archetypes.h" |
21 | |
22 | using std::optional; |
23 | |
24 | struct ThrowAssign { |
25 | static int dtor_called; |
26 | ThrowAssign() = default; |
27 | ThrowAssign(int) { TEST_THROW(42); } |
28 | ThrowAssign& operator=(int) { |
29 | TEST_THROW(42); |
30 | } |
31 | ~ThrowAssign() { ++dtor_called; } |
32 | }; |
33 | int ThrowAssign::dtor_called = 0; |
34 | |
35 | template <class T, class Arg = T, bool Expect = true> |
36 | void assert_assignable() { |
37 | static_assert(std::is_assignable<optional<T>&, Arg>::value == Expect, "" ); |
38 | static_assert(!std::is_assignable<const optional<T>&, Arg>::value, "" ); |
39 | } |
40 | |
41 | struct MismatchType { |
42 | explicit MismatchType(int) {} |
43 | explicit MismatchType(char*) {} |
44 | explicit MismatchType(int*) = delete; |
45 | MismatchType& operator=(int) { return *this; } |
46 | MismatchType& operator=(int*) { return *this; } |
47 | MismatchType& operator=(char*) = delete; |
48 | }; |
49 | |
50 | struct FromOptionalType { |
51 | using Opt = std::optional<FromOptionalType>; |
52 | FromOptionalType() = default; |
53 | FromOptionalType(FromOptionalType const&) = delete; |
54 | template <class Dummy = void> |
55 | constexpr FromOptionalType(Opt&) { Dummy::BARK; } |
56 | template <class Dummy = void> |
57 | constexpr FromOptionalType& operator=(Opt&) { Dummy::BARK; return *this; } |
58 | }; |
59 | |
60 | void test_sfinae() { |
61 | using I = TestTypes::TestType; |
62 | using E = ExplicitTestTypes::TestType; |
63 | assert_assignable<int>(); |
64 | assert_assignable<int, int&>(); |
65 | assert_assignable<int, int const&>(); |
66 | // Implicit test type |
67 | assert_assignable<I, I const&>(); |
68 | assert_assignable<I, I&&>(); |
69 | assert_assignable<I, int>(); |
70 | assert_assignable<I, void*, false>(); |
71 | // Explicit test type |
72 | assert_assignable<E, E const&>(); |
73 | assert_assignable<E, E &&>(); |
74 | assert_assignable<E, int>(); |
75 | assert_assignable<E, void*, false>(); |
76 | // Mismatch type |
77 | assert_assignable<MismatchType, int>(); |
78 | assert_assignable<MismatchType, int*, false>(); |
79 | assert_assignable<MismatchType, char*, false>(); |
80 | // Type constructible from optional |
81 | assert_assignable<FromOptionalType, std::optional<FromOptionalType>&, false>(); |
82 | } |
83 | |
84 | void test_with_test_type() |
85 | { |
86 | using T = TestTypes::TestType; |
87 | T::reset(); |
88 | { // to empty |
89 | optional<T> opt; |
90 | opt = 3; |
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>(opt) == true); |
97 | assert(*opt == T(3)); |
98 | } |
99 | { // to existing |
100 | optional<T> opt(42); |
101 | T::reset_constructors(); |
102 | opt = 3; |
103 | assert(T::alive == 1); |
104 | assert(T::constructed == 0); |
105 | assert(T::assigned == 1); |
106 | assert(T::value_assigned == 1); |
107 | assert(T::destroyed == 0); |
108 | assert(static_cast<bool>(opt) == true); |
109 | assert(*opt == T(3)); |
110 | } |
111 | { // test default argument |
112 | optional<T> opt; |
113 | T::reset_constructors(); |
114 | opt = {1, 2}; |
115 | assert(T::alive == 1); |
116 | assert(T::constructed == 2); |
117 | assert(T::value_constructed == 1); |
118 | assert(T::move_constructed == 1); |
119 | assert(T::assigned == 0); |
120 | assert(T::destroyed == 1); |
121 | assert(static_cast<bool>(opt) == true); |
122 | assert(*opt == T(1, 2)); |
123 | } |
124 | { // test default argument |
125 | optional<T> opt(42); |
126 | T::reset_constructors(); |
127 | opt = {1, 2}; |
128 | assert(T::alive == 1); |
129 | assert(T::constructed == 1); |
130 | assert(T::value_constructed == 1); |
131 | assert(T::assigned == 1); |
132 | assert(T::move_assigned == 1); |
133 | assert(T::destroyed == 1); |
134 | assert(static_cast<bool>(opt) == true); |
135 | assert(*opt == T(1, 2)); |
136 | } |
137 | { // test default argument |
138 | optional<T> opt; |
139 | T::reset_constructors(); |
140 | opt = {1}; |
141 | assert(T::alive == 1); |
142 | assert(T::constructed == 2); |
143 | assert(T::value_constructed == 1); |
144 | assert(T::move_constructed == 1); |
145 | assert(T::assigned == 0); |
146 | assert(T::destroyed == 1); |
147 | assert(static_cast<bool>(opt) == true); |
148 | assert(*opt == T(1)); |
149 | } |
150 | { // test default argument |
151 | optional<T> opt(42); |
152 | T::reset_constructors(); |
153 | opt = {}; |
154 | assert(static_cast<bool>(opt) == false); |
155 | assert(T::alive == 0); |
156 | assert(T::constructed == 0); |
157 | assert(T::assigned == 0); |
158 | assert(T::destroyed == 1); |
159 | } |
160 | } |
161 | |
162 | template <class T, class Value = int> |
163 | void test_with_type() { |
164 | { // to empty |
165 | optional<T> opt; |
166 | opt = Value(3); |
167 | assert(static_cast<bool>(opt) == true); |
168 | assert(*opt == T(3)); |
169 | } |
170 | { // to existing |
171 | optional<T> opt(Value(42)); |
172 | opt = Value(3); |
173 | assert(static_cast<bool>(opt) == true); |
174 | assert(*opt == T(3)); |
175 | } |
176 | { // test const |
177 | optional<T> opt(Value(42)); |
178 | const T t(Value(3)); |
179 | opt = t; |
180 | assert(static_cast<bool>(opt) == true); |
181 | assert(*opt == T(3)); |
182 | } |
183 | { // test default argument |
184 | optional<T> opt; |
185 | opt = {Value(1)}; |
186 | assert(static_cast<bool>(opt) == true); |
187 | assert(*opt == T(1)); |
188 | } |
189 | { // test default argument |
190 | optional<T> opt(Value(42)); |
191 | opt = {}; |
192 | assert(static_cast<bool>(opt) == false); |
193 | } |
194 | } |
195 | |
196 | template <class T> |
197 | void test_with_type_multi() { |
198 | test_with_type<T>(); |
199 | { // test default argument |
200 | optional<T> opt; |
201 | opt = {1, 2}; |
202 | assert(static_cast<bool>(opt) == true); |
203 | assert(*opt == T(1, 2)); |
204 | } |
205 | { // test default argument |
206 | optional<T> opt(42); |
207 | opt = {1, 2}; |
208 | assert(static_cast<bool>(opt) == true); |
209 | assert(*opt == T(1, 2)); |
210 | } |
211 | } |
212 | |
213 | void test_throws() |
214 | { |
215 | #ifndef TEST_HAS_NO_EXCEPTIONS |
216 | using T = ThrowAssign; |
217 | { |
218 | optional<T> opt; |
219 | try { |
220 | opt = 42; |
221 | assert(false); |
222 | } catch (int) {} |
223 | assert(static_cast<bool>(opt) == false); |
224 | } |
225 | assert(T::dtor_called == 0); |
226 | { |
227 | T::dtor_called = 0; |
228 | optional<T> opt(std::in_place); |
229 | try { |
230 | opt = 42; |
231 | assert(false); |
232 | } catch (int) {} |
233 | assert(static_cast<bool>(opt) == true); |
234 | assert(T::dtor_called == 0); |
235 | } |
236 | assert(T::dtor_called == 1); |
237 | #endif |
238 | } |
239 | |
240 | enum MyEnum { Zero, One, Two, Three, FortyTwo = 42 }; |
241 | |
242 | using Fn = void(*)(); |
243 | |
244 | // https://llvm.org/PR38638 |
245 | template <class T> |
246 | constexpr T pr38638(T v) |
247 | { |
248 | std::optional<T> o; |
249 | o = v; |
250 | return *o + 2; |
251 | } |
252 | |
253 | |
254 | int main(int, char**) |
255 | { |
256 | test_sfinae(); |
257 | // Test with instrumented type |
258 | test_with_test_type(); |
259 | // Test with various scalar types |
260 | test_with_type<int>(); |
261 | test_with_type<MyEnum, MyEnum>(); |
262 | test_with_type<int, MyEnum>(); |
263 | test_with_type<Fn, Fn>(); |
264 | // Test types with multi argument constructors |
265 | test_with_type_multi<ConstexprTestTypes::TestType>(); |
266 | test_with_type_multi<TrivialTestTypes::TestType>(); |
267 | // Test move only types |
268 | { |
269 | optional<std::unique_ptr<int>> opt; |
270 | opt = std::unique_ptr<int>(new int(3)); |
271 | assert(static_cast<bool>(opt) == true); |
272 | assert(**opt == 3); |
273 | } |
274 | { |
275 | optional<std::unique_ptr<int>> opt(std::unique_ptr<int>(new int(2))); |
276 | opt = std::unique_ptr<int>(new int(3)); |
277 | assert(static_cast<bool>(opt) == true); |
278 | assert(**opt == 3); |
279 | } |
280 | test_throws(); |
281 | |
282 | static_assert(pr38638(v: 3) == 5, "" ); |
283 | |
284 | return 0; |
285 | } |
286 | |