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;
ThrowAssignThrowAssign27 ThrowAssign(int) { TEST_THROW(42); }
operator =ThrowAssign28 ThrowAssign& operator=(int) {
29 TEST_THROW(42);
30 }
~ThrowAssignThrowAssign31 ~ThrowAssign() { ++dtor_called; }
32 };
33 int ThrowAssign::dtor_called = 0;
34
35 template <class T, class Arg = T, bool Expect = true>
assert_assignable()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 {
MismatchTypeMismatchType42 explicit MismatchType(int) {}
MismatchTypeMismatchType43 explicit MismatchType(char*) {}
44 explicit MismatchType(int*) = delete;
operator =MismatchType45 MismatchType& operator=(int) { return *this; }
operator =MismatchType46 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>
FromOptionalTypeFromOptionalType55 constexpr FromOptionalType(Opt&) { Dummy::BARK; }
56 template <class Dummy = void>
operator =FromOptionalType57 constexpr FromOptionalType& operator=(Opt&) { Dummy::BARK; return *this; }
58 };
59
test_sfinae()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
test_with_test_type()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>
test_with_type()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>
test_with_type_multi()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
test_throws()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://bugs.llvm.org/show_bug.cgi?id=38638
245 template <class T>
pr38638(T v)246 constexpr T pr38638(T v)
247 {
248 std::optional<T> o;
249 o = v;
250 return *o + 2;
251 }
252
253
main(int,char **)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(3) == 5, "");
283
284 return 0;
285 }
286