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