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

source code of libcxx/test/std/utilities/optional/optional.object/optional.object.assign/const_optional_U.pass.cpp