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 G>
12e356f681SHui Xie //   constexpr expected& operator=(const unexpected<G>& e);
13e356f681SHui Xie //
14e356f681SHui Xie // Let GF be const G&
15e356f681SHui Xie // Constraints:
16e356f681SHui Xie // - is_constructible_v<E, GF> is true; and
17e356f681SHui Xie // - is_assignable_v<E&, GF> is true; and
18e356f681SHui Xie // - is_nothrow_constructible_v<E, GF> || is_nothrow_move_constructible_v<T> ||
19e356f681SHui Xie //   is_nothrow_move_constructible_v<E> is true.
20e356f681SHui Xie //
21e356f681SHui Xie // Effects:
22e356f681SHui Xie // - If has_value() is true, equivalent to:
23e356f681SHui Xie //   reinit-expected(unex, val, std::forward<GF>(e.error()));
24e356f681SHui Xie //   has_val = false;
25e356f681SHui Xie // - Otherwise, equivalent to: unex = std::forward<GF>(e.error());
26e356f681SHui Xie // Returns: *this.
27e356f681SHui Xie 
28e356f681SHui Xie #include <cassert>
29e356f681SHui Xie #include <concepts>
30e356f681SHui Xie #include <expected>
31e356f681SHui Xie #include <type_traits>
32e356f681SHui Xie #include <utility>
33e356f681SHui Xie 
34e356f681SHui Xie #include "../../types.h"
35e356f681SHui Xie #include "test_macros.h"
36e356f681SHui Xie 
37e356f681SHui Xie struct NotCopyConstructible {
38e356f681SHui Xie   NotCopyConstructible(const NotCopyConstructible&)            = delete;
39e356f681SHui Xie   NotCopyConstructible& operator=(const NotCopyConstructible&) = default;
40e356f681SHui Xie };
41e356f681SHui Xie 
42e356f681SHui Xie struct NotCopyAssignable {
43e356f681SHui Xie   NotCopyAssignable(const NotCopyAssignable&)            = default;
44e356f681SHui Xie   NotCopyAssignable& operator=(const NotCopyAssignable&) = delete;
45e356f681SHui Xie };
46e356f681SHui Xie 
47e356f681SHui Xie struct MoveMayThrow {
48e356f681SHui Xie   MoveMayThrow(MoveMayThrow const&)            = default;
49e356f681SHui Xie   MoveMayThrow& operator=(const MoveMayThrow&) = default;
50e356f681SHui Xie   MoveMayThrow(MoveMayThrow&&) noexcept(false) {}
51e356f681SHui Xie   MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; }
52e356f681SHui Xie };
53e356f681SHui Xie 
54e356f681SHui Xie // Test constraints
55e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<int, int>&, const std::unexpected<int>&>);
56e356f681SHui Xie 
57e356f681SHui Xie // !is_constructible_v<E, GF>
58e356f681SHui Xie static_assert(
59e356f681SHui Xie     !std::is_assignable_v<std::expected<int, NotCopyConstructible>&, const std::unexpected<NotCopyConstructible>&>);
60e356f681SHui Xie 
61e356f681SHui Xie // !is_assignable_v<E&, GF>
62e356f681SHui Xie static_assert(!std::is_assignable_v<std::expected<int, NotCopyAssignable>&, const std::unexpected<NotCopyAssignable>&>);
63e356f681SHui Xie 
64e356f681SHui Xie template <bool moveNoexcept, bool convertNoexcept>
65e356f681SHui Xie struct MaybeNoexcept {
66e356f681SHui Xie   explicit MaybeNoexcept(int) noexcept(convertNoexcept);
67e356f681SHui Xie   MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept);
68e356f681SHui Xie   MaybeNoexcept& operator=(MaybeNoexcept&&) = default;
69e356f681SHui Xie   MaybeNoexcept& operator=(int);
70e356f681SHui Xie };
71e356f681SHui Xie 
72e356f681SHui Xie // !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> &&
73e356f681SHui Xie // is_nothrow_move_constructible_v<E>
74e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<true, false>>&,
75e356f681SHui Xie                                    const std::unexpected<int>&>);
76e356f681SHui Xie 
77e356f681SHui Xie // is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> &&
78e356f681SHui Xie // !is_nothrow_move_constructible_v<E>
79e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<false, true>>&,
80e356f681SHui Xie                                    const std::unexpected<int>&>);
81e356f681SHui Xie 
82e356f681SHui Xie // !is_nothrow_constructible_v<E, GF> && is_nothrow_move_constructible_v<T> &&
83e356f681SHui Xie // !is_nothrow_move_constructible_v<E>
84e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<true, true>, MaybeNoexcept<false, false>>&,
85e356f681SHui Xie                                    const std::unexpected<int>&>);
86e356f681SHui Xie 
87e356f681SHui Xie // !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> &&
88e356f681SHui Xie // !is_nothrow_move_constructible_v<E>
89e356f681SHui Xie static_assert(!std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<false, false>>&,
90e356f681SHui Xie                                     const std::unexpected<int>&>);
91e356f681SHui Xie 
92e356f681SHui Xie constexpr bool test() {
93e356f681SHui Xie   // - If has_value() is true, equivalent to:
94e356f681SHui Xie   //   reinit-expected(unex, val, std::forward<GF>(e.error()));
95e356f681SHui Xie   // is_nothrow_constructible_v<E, GF>
96e356f681SHui Xie   //
97e356f681SHui Xie   //  In this case, it should call the branch
98e356f681SHui Xie   //    destroy_at(addressof(oldval));
99e356f681SHui Xie   //    construct_at(addressof(newval), std::forward<Args>(args)...);
100e356f681SHui Xie   {
101e356f681SHui Xie     BothNoexcept::state oldState{};
102e356f681SHui Xie     std::expected<BothNoexcept, BothNoexcept> e(std::in_place, oldState, 5);
103e356f681SHui Xie     const std::unexpected<int> un(10);
104e356f681SHui Xie     decltype(auto) x = (e = un);
105e356f681SHui Xie     static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, BothNoexcept>&>);
106e356f681SHui Xie     assert(&x == &e);
107e356f681SHui Xie 
108e356f681SHui Xie     assert(!oldState.moveCtorCalled);
109e356f681SHui Xie     assert(oldState.dtorCalled);
110e356f681SHui Xie     assert(e.error().copiedFromInt);
111e356f681SHui Xie   }
112e356f681SHui Xie 
113e356f681SHui Xie   // - If has_value() is true, equivalent to:
114e356f681SHui Xie   //   reinit-expected(unex, val, std::forward<GF>(e.error()));
115e356f681SHui Xie   // !is_nothrow_constructible_v<E, GF> && is_nothrow_move_constructible_v<E>
116e356f681SHui Xie   //
117e356f681SHui Xie   //  In this case, it should call the branch
118e356f681SHui Xie   //  T tmp(std::forward<Args>(args)...);
119e356f681SHui Xie   //  destroy_at(addressof(oldval));
120e356f681SHui Xie   //  construct_at(addressof(newval), std::move(tmp));
121e356f681SHui Xie   {
122e356f681SHui Xie     BothNoexcept::state oldState{};
123e356f681SHui Xie     std::expected<BothNoexcept, MoveNoexceptConvThrow> e(std::in_place, oldState, 5);
124e356f681SHui Xie     const std::unexpected<int> un(10);
125e356f681SHui Xie     decltype(auto) x = (e = un);
126e356f681SHui Xie     static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, MoveNoexceptConvThrow>&>);
127e356f681SHui Xie     assert(&x == &e);
128e356f681SHui Xie 
129e356f681SHui Xie     assert(!oldState.moveCtorCalled);
130e356f681SHui Xie     assert(oldState.dtorCalled);
131e356f681SHui Xie     assert(!e.error().copiedFromInt);
132e356f681SHui Xie     assert(e.error().movedFromTmp);
133e356f681SHui Xie   }
134e356f681SHui Xie 
135e356f681SHui Xie   // - If has_value() is true, equivalent to:
136e356f681SHui Xie   //   reinit-expected(unex, val, std::forward<GF>(e.error()));
137e356f681SHui Xie   // !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<E>
138e356f681SHui Xie   // is_nothrow_move_constructible_v<T>
139e356f681SHui Xie   //
140e356f681SHui Xie   //  In this case, it should call the branch
141e356f681SHui Xie   //  U tmp(std::move(oldval));
142e356f681SHui Xie   //  destroy_at(addressof(oldval));
143e356f681SHui Xie   //  try {
144e356f681SHui Xie   //    construct_at(addressof(newval), std::forward<Args>(args)...);
145e356f681SHui Xie   //  } catch (...) {
146e356f681SHui Xie   //    construct_at(addressof(oldval), std::move(tmp));
147e356f681SHui Xie   //    throw;
148e356f681SHui Xie   //  }
149e356f681SHui Xie   {
150e356f681SHui Xie     BothNoexcept::state oldState{};
151e356f681SHui Xie     std::expected<BothNoexcept, BothMayThrow> e(std::in_place, oldState, 5);
152e356f681SHui Xie     const std::unexpected<int> un(10);
153e356f681SHui Xie     decltype(auto) x = (e = un);
154e356f681SHui Xie     static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, BothMayThrow>&>);
155e356f681SHui Xie     assert(&x == &e);
156e356f681SHui Xie 
157e356f681SHui Xie     assert(oldState.moveCtorCalled);
158e356f681SHui Xie     assert(oldState.dtorCalled);
159e356f681SHui Xie     assert(e.error().copiedFromInt);
160e356f681SHui Xie   }
161e356f681SHui Xie 
162e356f681SHui Xie   // Otherwise, equivalent to: unex = std::forward<GF>(e.error());
163e356f681SHui Xie   {
164e356f681SHui Xie     Traced::state oldState{};
165e356f681SHui Xie     Traced::state newState{};
166e356f681SHui Xie     std::expected<int, Traced> e1(std::unexpect, oldState, 5);
167e356f681SHui Xie     const std::unexpected<Traced> e(std::in_place, newState, 10);
168e356f681SHui Xie     decltype(auto) x = (e1 = e);
169e356f681SHui Xie     static_assert(std::same_as<decltype(x), std::expected<int, Traced>&>);
170e356f681SHui Xie     assert(&x == &e1);
171e356f681SHui Xie 
172e356f681SHui Xie     assert(!e1.has_value());
173e356f681SHui Xie     assert(e1.error().data_ == 10);
174e356f681SHui Xie     assert(oldState.copyAssignCalled);
175e356f681SHui Xie   }
176e356f681SHui Xie   return true;
177e356f681SHui Xie }
178e356f681SHui Xie 
179e356f681SHui Xie void testException() {
180e356f681SHui Xie #ifndef TEST_HAS_NO_EXCEPTIONS
181e356f681SHui Xie   std::expected<int, ThrowOnConvert> e1(std::in_place, 5);
182e356f681SHui Xie   const std::unexpected<int> un(10);
183e356f681SHui Xie   try {
184e356f681SHui Xie     e1 = un;
185e356f681SHui Xie     assert(false);
186e356f681SHui Xie   } catch (Except) {
187e356f681SHui Xie     assert(e1.has_value());
188e356f681SHui Xie     assert(*e1 == 5);
189e356f681SHui Xie   }
190e356f681SHui Xie #endif // TEST_HAS_NO_EXCEPTIONS
191e356f681SHui Xie }
192e356f681SHui Xie 
193e356f681SHui Xie int main(int, char**) {
194e356f681SHui Xie   test();
195e356f681SHui Xie   static_assert(test());
196e356f681SHui Xie   testException();
197e356f681SHui Xie   return 0;
198e356f681SHui Xie }
199