xref: /llvm-project/libcxx/test/std/utilities/expected/expected.void/assign/assign.move.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 // constexpr expected& operator=(expected&& rhs) noexcept(see below);
12e356f681SHui Xie //
13e356f681SHui Xie // Effects:
14e356f681SHui Xie // - If this->has_value() && rhs.has_value() is true, no effects.
15e356f681SHui Xie // - Otherwise, if this->has_value() is true, equivalent to:
16e356f681SHui Xie //   construct_at(addressof(unex), std::move(rhs.unex));
17e356f681SHui Xie //   has_val = false;
18e356f681SHui Xie // - Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true.
19e356f681SHui Xie // - Otherwise, equivalent to unex = std::move(rhs.error()).
20e356f681SHui Xie //
21e356f681SHui Xie // Returns: *this.
22e356f681SHui Xie //
23e356f681SHui Xie // Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v<E> && is_nothrow_move_assignable_v<E>.
24e356f681SHui Xie //
25e356f681SHui Xie // This operator is defined as deleted unless is_move_constructible_v<E> is true and is_move_assignable_v<E> is true.
26e356f681SHui Xie 
27e356f681SHui Xie #include <cassert>
28e356f681SHui Xie #include <concepts>
29e356f681SHui Xie #include <expected>
30e356f681SHui Xie #include <type_traits>
31e356f681SHui Xie #include <utility>
32e356f681SHui Xie 
33e356f681SHui Xie #include "../../types.h"
34e356f681SHui Xie #include "test_macros.h"
35e356f681SHui Xie 
36e356f681SHui Xie struct NotMoveConstructible {
37e356f681SHui Xie   NotMoveConstructible(NotMoveConstructible&&)            = delete;
38e356f681SHui Xie   NotMoveConstructible& operator=(NotMoveConstructible&&) = default;
39e356f681SHui Xie };
40e356f681SHui Xie 
41e356f681SHui Xie struct NotMoveAssignable {
42e356f681SHui Xie   NotMoveAssignable(NotMoveAssignable&&)            = default;
43e356f681SHui Xie   NotMoveAssignable& operator=(NotMoveAssignable&&) = delete;
44e356f681SHui Xie };
45e356f681SHui Xie 
46e356f681SHui Xie // Test constraints
47e356f681SHui Xie static_assert(std::is_move_assignable_v<std::expected<void, int>>);
48e356f681SHui Xie 
49e356f681SHui Xie // !is_move_assignable_v<E>
50e356f681SHui Xie static_assert(!std::is_move_assignable_v<std::expected<void, NotMoveAssignable>>);
51e356f681SHui Xie 
52e356f681SHui Xie // !is_move_constructible_v<E>
53e356f681SHui Xie static_assert(!std::is_move_assignable_v<std::expected<void, NotMoveConstructible>>);
54e356f681SHui Xie 
55e356f681SHui Xie // Test noexcept
56e356f681SHui Xie struct MoveCtorMayThrow {
57e356f681SHui Xie   MoveCtorMayThrow(MoveCtorMayThrow&&) noexcept(false) {}
58e356f681SHui Xie   MoveCtorMayThrow& operator=(MoveCtorMayThrow&&) noexcept = default;
59e356f681SHui Xie };
60e356f681SHui Xie 
61e356f681SHui Xie struct MoveAssignMayThrow {
62e356f681SHui Xie   MoveAssignMayThrow(MoveAssignMayThrow&&) noexcept = default;
63e356f681SHui Xie   MoveAssignMayThrow& operator=(MoveAssignMayThrow&&) noexcept(false) { return *this; }
64e356f681SHui Xie };
65e356f681SHui Xie 
66e356f681SHui Xie // Test noexcept
67e356f681SHui Xie static_assert(std::is_nothrow_move_assignable_v<std::expected<void, int>>);
68e356f681SHui Xie 
69e356f681SHui Xie // !is_nothrow_move_assignable_v<E>
70e356f681SHui Xie static_assert(!std::is_nothrow_move_assignable_v<std::expected<void, MoveAssignMayThrow>>);
71e356f681SHui Xie 
72e356f681SHui Xie // !is_nothrow_move_constructible_v<E>
73e356f681SHui Xie static_assert(!std::is_nothrow_move_assignable_v<std::expected<void, MoveCtorMayThrow>>);
74e356f681SHui Xie 
75e356f681SHui Xie constexpr bool test() {
76e356f681SHui Xie   // If this->has_value() && rhs.has_value() is true, no effects.
77e356f681SHui Xie   {
78e356f681SHui Xie     std::expected<void, int> e1;
79e356f681SHui Xie     std::expected<void, int> e2;
80e356f681SHui Xie     decltype(auto) x = (e1 = std::move(e2));
81e356f681SHui Xie     static_assert(std::same_as<decltype(x), std::expected<void, int>&>);
82e356f681SHui Xie     assert(&x == &e1);
83e356f681SHui Xie     assert(e1.has_value());
84e356f681SHui Xie   }
85e356f681SHui Xie 
86e356f681SHui Xie   // Otherwise, if this->has_value() is true, equivalent to:
87e356f681SHui Xie   // construct_at(addressof(unex), std::move(rhs.unex));
88e356f681SHui Xie   // has_val = false;
89e356f681SHui Xie   {
90e356f681SHui Xie     Traced::state state{};
91e356f681SHui Xie     std::expected<void, Traced> e1;
92e356f681SHui Xie     std::expected<void, Traced> e2(std::unexpect, state, 5);
93e356f681SHui Xie     decltype(auto) x = (e1 = std::move(e2));
94e356f681SHui Xie     static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);
95e356f681SHui Xie     assert(&x == &e1);
96e356f681SHui Xie     assert(!e1.has_value());
97e356f681SHui Xie     assert(e1.error().data_ == 5);
98e356f681SHui Xie 
99e356f681SHui Xie     assert(state.moveCtorCalled);
100e356f681SHui Xie   }
101e356f681SHui Xie 
102e356f681SHui Xie   // Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true.
103e356f681SHui Xie   {
104e356f681SHui Xie     Traced::state state{};
105e356f681SHui Xie     std::expected<void, Traced> e1(std::unexpect, state, 5);
106e356f681SHui Xie     std::expected<void, Traced> e2;
107e356f681SHui Xie     decltype(auto) x = (e1 = std::move(e2));
108e356f681SHui Xie     static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);
109e356f681SHui Xie     assert(&x == &e1);
110e356f681SHui Xie     assert(e1.has_value());
111e356f681SHui Xie 
112e356f681SHui Xie     assert(state.dtorCalled);
113e356f681SHui Xie   }
114e356f681SHui Xie 
115e356f681SHui Xie   // Otherwise, equivalent to unex = rhs.error().
116e356f681SHui Xie   {
117e356f681SHui Xie     Traced::state state{};
118e356f681SHui Xie     std::expected<void, Traced> e1(std::unexpect, state, 5);
119e356f681SHui Xie     std::expected<void, Traced> e2(std::unexpect, state, 10);
120e356f681SHui Xie     decltype(auto) x = (e1 = std::move(e2));
121e356f681SHui Xie     static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>);
122e356f681SHui Xie     assert(&x == &e1);
123e356f681SHui Xie     assert(!e1.has_value());
124e356f681SHui Xie     assert(e1.error().data_ == 10);
125e356f681SHui Xie 
126e356f681SHui Xie     assert(state.moveAssignCalled);
127e356f681SHui Xie   }
128e356f681SHui Xie 
1294f469053SJan Kokemüller   // CheckForInvalidWrites
1304f469053SJan Kokemüller   {
1314f469053SJan Kokemüller     {
1324f469053SJan Kokemüller       CheckForInvalidWrites<true, true> e1;
1334f469053SJan Kokemüller       CheckForInvalidWrites<true, true> e2(std::unexpect);
1344f469053SJan Kokemüller 
1354f469053SJan Kokemüller       e1 = std::move(e2);
1364f469053SJan Kokemüller 
1374f469053SJan Kokemüller       assert(e1.check());
1384f469053SJan Kokemüller       assert(e2.check());
1394f469053SJan Kokemüller     }
1404f469053SJan Kokemüller     {
1414f469053SJan Kokemüller       CheckForInvalidWrites<false, true> e1;
1424f469053SJan Kokemüller       CheckForInvalidWrites<false, true> e2(std::unexpect);
1434f469053SJan Kokemüller 
1444f469053SJan Kokemüller       e1 = std::move(e2);
1454f469053SJan Kokemüller 
1464f469053SJan Kokemüller       assert(e1.check());
1474f469053SJan Kokemüller       assert(e2.check());
1484f469053SJan Kokemüller     }
1494f469053SJan Kokemüller   }
1504f469053SJan Kokemüller 
151e356f681SHui Xie   return true;
152e356f681SHui Xie }
153e356f681SHui Xie 
154e356f681SHui Xie void testException() {
155e356f681SHui Xie #ifndef TEST_HAS_NO_EXCEPTIONS
156e356f681SHui Xie   std::expected<void, ThrowOnMoveConstruct> e1(std::in_place);
157e356f681SHui Xie   std::expected<void, ThrowOnMoveConstruct> e2(std::unexpect);
158e356f681SHui Xie   try {
159e356f681SHui Xie     e1 = std::move(e2);
160e356f681SHui Xie     assert(false);
161e356f681SHui Xie   } catch (Except) {
162e356f681SHui Xie     assert(e1.has_value());
163e356f681SHui Xie   }
164e356f681SHui Xie #endif // TEST_HAS_NO_EXCEPTIONS
165e356f681SHui Xie }
166e356f681SHui Xie 
167e356f681SHui Xie int main(int, char**) {
168e356f681SHui Xie   test();
169e356f681SHui Xie   static_assert(test());
170e356f681SHui Xie   testException();
171e356f681SHui Xie   return 0;
172e356f681SHui Xie }
173