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