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