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