xref: /llvm-project/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp (revision f5832bab6f5024cabe32a9f668b7f44e6b7cfef5)
1 //===----------------------------------------------------------------------===//
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 
8 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
9 
10 //  template<class U = T>
11 //   constexpr expected& operator=(U&& v);
12 //
13 // Constraints:
14 // - is_same_v<expected, remove_cvref_t<U>> is false; and
15 // - remove_cvref_t<U> is not a specialization of unexpected; and
16 // - is_constructible_v<T, U> is true; and
17 // - is_assignable_v<T&, U> is true; and
18 // - is_nothrow_constructible_v<T, U> || is_nothrow_move_constructible_v<T> ||
19 //   is_nothrow_move_constructible_v<E> is true.
20 //
21 // Effects:
22 // - If has_value() is true, equivalent to: val = std::forward<U>(v);
23 // - Otherwise, equivalent to:
24 //   reinit-expected(val, unex, std::forward<U>(v));
25 //   has_val = true;
26 // - Returns: *this.
27 
28 #include <cassert>
29 #include <concepts>
30 #include <expected>
31 #include <type_traits>
32 #include <utility>
33 
34 #include "../../types.h"
35 #include "test_macros.h"
36 
37 struct NotCopyConstructible {
38   NotCopyConstructible(const NotCopyConstructible&)            = delete;
39   NotCopyConstructible& operator=(const NotCopyConstructible&) = default;
40 };
41 
42 struct NotCopyAssignable {
43   NotCopyAssignable(const NotCopyAssignable&)            = default;
44   NotCopyAssignable& operator=(const NotCopyAssignable&) = delete;
45 };
46 
47 // Test constraints
48 static_assert(std::is_assignable_v<std::expected<int, int>&, int>);
49 
50 // is_same_v<expected, remove_cvref_t<U>>
51 // it is true because it covered by the copy assignment
52 static_assert(std::is_assignable_v<std::expected<int, int>&, std::expected<int, int>>);
53 
54 // remove_cvref_t<U> is a specialization of unexpected
55 // it is true because it covered the unexpected overload
56 static_assert(std::is_assignable_v<std::expected<int, int>&, std::unexpected<int>>);
57 
58 // !is_constructible_v<T, U>
59 struct NoCtorFromInt {
60   NoCtorFromInt(int) = delete;
61   NoCtorFromInt& operator=(int);
62 };
63 static_assert(!std::is_assignable_v<std::expected<NoCtorFromInt, int>&, int>);
64 
65 // !is_assignable_v<T&, U>
66 struct NoAssignFromInt {
67   explicit NoAssignFromInt(int);
68   NoAssignFromInt& operator=(int) = delete;
69 };
70 static_assert(!std::is_assignable_v<std::expected<NoAssignFromInt, int>&, int>);
71 
72 template <bool moveNoexcept, bool convertNoexcept>
73 struct MaybeNoexcept {
74   explicit MaybeNoexcept(int) noexcept(convertNoexcept);
75   MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept);
76   MaybeNoexcept& operator=(MaybeNoexcept&&) = default;
77   MaybeNoexcept& operator=(int);
78 };
79 
80 // !is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> &&
81 // is_nothrow_move_constructible_v<E>
82 static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, int>&, int>);
83 
84 // is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> &&
85 // !is_nothrow_move_constructible_v<E>
86 static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, true>, MaybeNoexcept<false, false>>&, int>);
87 
88 // !is_nothrow_constructible_v<T, U> && is_nothrow_move_constructible_v<T> &&
89 // !is_nothrow_move_constructible_v<E>
90 static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<true, false>, MaybeNoexcept<false, false>>&, int>);
91 
92 // !is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> &&
93 // !is_nothrow_move_constructible_v<E>
94 static_assert(!std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<false, false>>&, int>);
95 
96 constexpr bool test() {
97   // If has_value() is true, equivalent to: val = std::forward<U>(v);
98   // Copy
99   {
100     Traced::state oldState{};
101     Traced::state newState{};
102     std::expected<Traced, int> e1(std::in_place, oldState, 5);
103     Traced u(newState, 10);
104     decltype(auto) x = (e1 = u);
105     static_assert(std::same_as<decltype(x), std::expected<Traced, int>&>);
106     assert(&x == &e1);
107 
108     assert(e1.has_value());
109     assert(e1.value().data_ == 10);
110     assert(oldState.copyAssignCalled);
111   }
112 
113   // If has_value() is true, equivalent to: val = std::forward<U>(v);
114   // Move
115   {
116     Traced::state oldState{};
117     Traced::state newState{};
118     std::expected<Traced, int> e1(std::in_place, oldState, 5);
119     Traced u(newState, 10);
120     decltype(auto) x = (e1 = std::move(u));
121     static_assert(std::same_as<decltype(x), std::expected<Traced, int>&>);
122     assert(&x == &e1);
123 
124     assert(e1.has_value());
125     assert(e1.value().data_ == 10);
126     assert(oldState.moveAssignCalled);
127   }
128 
129   // Otherwise, equivalent to:
130   //   reinit-expected(val, unex, std::forward<U>(v));
131   // is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> &&
132   // !is_nothrow_move_constructible_v<E>
133   // copy
134   //
135   //  In this case, it should call the branch
136   //    destroy_at(addressof(oldval));
137   //    construct_at(addressof(newval), std::forward<Args>(args)...);
138   {
139     BothMayThrow::state oldState{};
140     std::expected<MoveThrowConvNoexcept, BothMayThrow> e1(std::unexpect, oldState, 5);
141     const int i      = 10;
142     decltype(auto) x = (e1 = i);
143     static_assert(std::same_as<decltype(x), std::expected<MoveThrowConvNoexcept, BothMayThrow>&>);
144     assert(&x == &e1);
145 
146     assert(e1.has_value());
147     assert(e1.value().data_ == 10);
148 
149     assert(!oldState.copyCtorCalled);
150     assert(!oldState.moveCtorCalled);
151     assert(oldState.dtorCalled);
152     assert(e1.value().copiedFromInt);
153   }
154 
155   // Otherwise, equivalent to:
156   //   reinit-expected(val, unex, std::forward<U>(v));
157   // is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> &&
158   // !is_nothrow_move_constructible_v<E>
159   // move
160   //
161   //  In this case, it should call the branch
162   //    destroy_at(addressof(oldval));
163   //    construct_at(addressof(newval), std::forward<Args>(args)...);
164   {
165     BothMayThrow::state oldState{};
166     std::expected<MoveThrowConvNoexcept, BothMayThrow> e1(std::unexpect, oldState, 5);
167     decltype(auto) x = (e1 = 10);
168     static_assert(std::same_as<decltype(x), std::expected<MoveThrowConvNoexcept, BothMayThrow>&>);
169     assert(&x == &e1);
170 
171     assert(e1.has_value());
172     assert(e1.value().data_ == 10);
173 
174     assert(!oldState.copyCtorCalled);
175     assert(!oldState.moveCtorCalled);
176     assert(oldState.dtorCalled);
177     assert(e1.value().movedFromInt);
178   }
179 
180   // Otherwise, equivalent to:
181   //   reinit-expected(val, unex, std::forward<U>(v));
182   // !is_nothrow_constructible_v<T, U> && is_nothrow_move_constructible_v<T> &&
183   // !is_nothrow_move_constructible_v<E>
184   // copy
185   //
186   //  In this case, it should call the branch
187   //  T tmp(std::forward<Args>(args)...);
188   //  destroy_at(addressof(oldval));
189   //  construct_at(addressof(newval), std::move(tmp));
190   {
191     BothMayThrow::state oldState{};
192     std::expected<MoveNoexceptConvThrow, BothMayThrow> e1(std::unexpect, oldState, 5);
193     const int i      = 10;
194     decltype(auto) x = (e1 = i);
195     static_assert(std::same_as<decltype(x), std::expected<MoveNoexceptConvThrow, BothMayThrow>&>);
196     assert(&x == &e1);
197 
198     assert(e1.has_value());
199     assert(e1.value().data_ == 10);
200 
201     assert(!oldState.copyCtorCalled);
202     assert(!oldState.moveCtorCalled);
203     assert(oldState.dtorCalled);
204     assert(!e1.value().copiedFromInt);
205     assert(e1.value().movedFromTmp);
206   }
207 
208   // Otherwise, equivalent to:
209   //   reinit-expected(val, unex, std::forward<U>(v));
210   // !is_nothrow_constructible_v<T, U> && is_nothrow_move_constructible_v<T> &&
211   // !is_nothrow_move_constructible_v<E>
212   // move
213   //
214   //  In this case, it should call the branch
215   //  T tmp(std::forward<Args>(args)...);
216   //  destroy_at(addressof(oldval));
217   //  construct_at(addressof(newval), std::move(tmp));
218   {
219     BothMayThrow::state oldState{};
220     std::expected<MoveNoexceptConvThrow, BothMayThrow> e1(std::unexpect, oldState, 5);
221     decltype(auto) x = (e1 = 10);
222     static_assert(std::same_as<decltype(x), std::expected<MoveNoexceptConvThrow, BothMayThrow>&>);
223     assert(&x == &e1);
224 
225     assert(e1.has_value());
226     assert(e1.value().data_ == 10);
227 
228     assert(!oldState.copyCtorCalled);
229     assert(!oldState.moveCtorCalled);
230     assert(oldState.dtorCalled);
231     assert(!e1.value().copiedFromInt);
232     assert(e1.value().movedFromTmp);
233   }
234 
235   // Otherwise, equivalent to:
236   //   reinit-expected(val, unex, std::forward<U>(v));
237   // !is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> &&
238   // is_nothrow_move_constructible_v<E>
239   // copy
240   //
241   //  In this case, it should call the branch
242   //  U tmp(std::move(oldval));
243   //  destroy_at(addressof(oldval));
244   //  try {
245   //    construct_at(addressof(newval), std::forward<Args>(args)...);
246   //  } catch (...) {
247   //    construct_at(addressof(oldval), std::move(tmp));
248   //    throw;
249   //  }
250   {
251     TracedNoexcept::state oldState{};
252     std::expected<BothMayThrow, TracedNoexcept> e1(std::unexpect, oldState, 5);
253     const int i      = 10;
254     decltype(auto) x = (e1 = i);
255     static_assert(std::same_as<decltype(x), std::expected<BothMayThrow, TracedNoexcept>&>);
256     assert(&x == &e1);
257 
258     assert(e1.has_value());
259     assert(e1.value().data_ == 10);
260 
261     assert(!oldState.copyCtorCalled);
262     assert(oldState.moveCtorCalled);
263     assert(oldState.dtorCalled);
264     assert(e1.value().copiedFromInt);
265   }
266 
267   // Otherwise, equivalent to:
268   //   reinit-expected(val, unex, std::forward<U>(v));
269   // !is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> &&
270   // is_nothrow_move_constructible_v<E>
271   // move
272   //
273   //  In this case, it should call the branch
274   //  U tmp(std::move(oldval));
275   //  destroy_at(addressof(oldval));
276   //  try {
277   //    construct_at(addressof(newval), std::forward<Args>(args)...);
278   //  } catch (...) {
279   //    construct_at(addressof(oldval), std::move(tmp));
280   //    throw;
281   //  }
282   {
283     TracedNoexcept::state oldState{};
284     std::expected<BothMayThrow, TracedNoexcept> e1(std::unexpect, oldState, 5);
285     decltype(auto) x = (e1 = 10);
286     static_assert(std::same_as<decltype(x), std::expected<BothMayThrow, TracedNoexcept>&>);
287     assert(&x == &e1);
288 
289     assert(e1.has_value());
290     assert(e1.value().data_ == 10);
291 
292     assert(!oldState.copyCtorCalled);
293     assert(oldState.moveCtorCalled);
294     assert(oldState.dtorCalled);
295     assert(e1.value().movedFromInt);
296   }
297 
298   // Test default template argument.
299   // Without it, the template parameter cannot be deduced from an initializer list
300   {
301     struct Bar {
302       int i;
303       int j;
304       constexpr Bar(int ii, int jj) : i(ii), j(jj) {}
305     };
306 
307     std::expected<Bar, int> e({5, 6});
308     e = {7, 8};
309     assert(e.value().i == 7);
310     assert(e.value().j == 8);
311   }
312 
313   return true;
314 }
315 
316 void testException() {
317 #ifndef TEST_HAS_NO_EXCEPTIONS
318   std::expected<ThrowOnConvert, int> e1(std::unexpect, 5);
319   try {
320     e1 = 10;
321     assert(false);
322   } catch (Except) {
323     assert(!e1.has_value());
324     assert(e1.error() == 5);
325   }
326 
327 #endif // TEST_HAS_NO_EXCEPTIONS
328 }
329 
330 int main(int, char**) {
331   test();
332   static_assert(test());
333   testException();
334   return 0;
335 }
336