xref: /llvm-project/libcxx/test/std/utilities/expected/expected.void/swap/member.swap.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 void swap(expected& rhs) noexcept(see below);
12e356f681SHui Xie //
13e356f681SHui Xie // Constraints:
14e356f681SHui Xie // is_swappable_v<E> is true and is_move_constructible_v<E> is true.
15e356f681SHui Xie //
16e356f681SHui Xie // Throws: Any exception thrown by the expressions in the Effects.
17e356f681SHui Xie //
18e356f681SHui Xie // Remarks: The exception specification is equivalent to:
19e356f681SHui Xie // is_nothrow_move_constructible_v<E> && is_nothrow_swappable_v<E>.
20e356f681SHui Xie 
21e356f681SHui Xie #include <cassert>
22e356f681SHui Xie #include <expected>
23e356f681SHui Xie #include <type_traits>
24e356f681SHui Xie #include <utility>
25e356f681SHui Xie 
26e356f681SHui Xie #include "../../types.h"
27e356f681SHui Xie #include "test_macros.h"
28e356f681SHui Xie 
29e356f681SHui Xie // Test Constraints:
30e356f681SHui Xie template <class E>
31e356f681SHui Xie concept HasMemberSwap = requires(std::expected<void, E> x, std::expected<void, E> y) { x.swap(y); };
32e356f681SHui Xie 
33e356f681SHui Xie static_assert(HasMemberSwap<int>);
34e356f681SHui Xie 
35e356f681SHui Xie struct NotSwappable {};
36e356f681SHui Xie void swap(NotSwappable&, NotSwappable&) = delete;
37e356f681SHui Xie 
38e356f681SHui Xie // !is_swappable_v<E>
39e356f681SHui Xie static_assert(!HasMemberSwap<NotSwappable>);
40e356f681SHui Xie 
41f5832babSStephan T. Lavavej struct NotMoveConstructible {
42f5832babSStephan T. Lavavej   NotMoveConstructible(NotMoveConstructible&&) = delete;
43f5832babSStephan T. Lavavej   friend void swap(NotMoveConstructible&, NotMoveConstructible&) {}
44e356f681SHui Xie };
45e356f681SHui Xie 
46e356f681SHui Xie // !is_move_constructible_v<E>
47f5832babSStephan T. Lavavej static_assert(!HasMemberSwap<NotMoveConstructible>);
48e356f681SHui Xie 
49e356f681SHui Xie // Test noexcept
50e356f681SHui Xie struct MoveMayThrow {
51e356f681SHui Xie   MoveMayThrow(MoveMayThrow&&) noexcept(false);
52e356f681SHui Xie   friend void swap(MoveMayThrow&, MoveMayThrow&) noexcept {}
53e356f681SHui Xie };
54e356f681SHui Xie 
55e356f681SHui Xie template <class E>
56134c9159SJan Kokemüller concept MemberSwapNoexcept = //
57e356f681SHui Xie     requires(std::expected<void, E> x, std::expected<void, E> y) {
58e356f681SHui Xie       { x.swap(y) } noexcept;
59e356f681SHui Xie     };
60e356f681SHui Xie 
61e356f681SHui Xie static_assert(MemberSwapNoexcept<int>);
62e356f681SHui Xie 
63e356f681SHui Xie // !is_nothrow_move_constructible_v<E>
64e356f681SHui Xie static_assert(!MemberSwapNoexcept<MoveMayThrow>);
65e356f681SHui Xie 
66e356f681SHui Xie struct SwapMayThrow {
67e356f681SHui Xie   friend void swap(SwapMayThrow&, SwapMayThrow&) noexcept(false) {}
68e356f681SHui Xie };
69e356f681SHui Xie 
70e356f681SHui Xie // !is_nothrow_swappable_v<E>
71e356f681SHui Xie static_assert(!MemberSwapNoexcept<SwapMayThrow>);
72e356f681SHui Xie 
73e356f681SHui Xie constexpr bool test() {
74e356f681SHui Xie   // this->has_value() && rhs.has_value()
75e356f681SHui Xie   {
76e356f681SHui Xie     std::expected<void, int> x;
77e356f681SHui Xie     std::expected<void, int> y;
78e356f681SHui Xie     x.swap(y);
79e356f681SHui Xie 
80e356f681SHui Xie     assert(x.has_value());
81e356f681SHui Xie     assert(y.has_value());
82e356f681SHui Xie   }
83e356f681SHui Xie 
84e356f681SHui Xie   // !this->has_value() && !rhs.has_value()
85e356f681SHui Xie   {
86e356f681SHui Xie     std::expected<void, ADLSwap> x(std::unexpect, 5);
87e356f681SHui Xie     std::expected<void, ADLSwap> y(std::unexpect, 10);
88e356f681SHui Xie     x.swap(y);
89e356f681SHui Xie 
90e356f681SHui Xie     assert(!x.has_value());
91e356f681SHui Xie     assert(x.error().i == 10);
92e356f681SHui Xie     assert(x.error().adlSwapCalled);
93e356f681SHui Xie     assert(!y.has_value());
94e356f681SHui Xie     assert(y.error().i == 5);
95e356f681SHui Xie     assert(y.error().adlSwapCalled);
96e356f681SHui Xie   }
97e356f681SHui Xie 
98e356f681SHui Xie   // this->has_value() && !rhs.has_value()
99e356f681SHui Xie   {
100e356f681SHui Xie     Traced::state s{};
101e356f681SHui Xie     std::expected<void, Traced> e1(std::in_place);
102e356f681SHui Xie     std::expected<void, Traced> e2(std::unexpect, s, 10);
103e356f681SHui Xie 
104e356f681SHui Xie     e1.swap(e2);
105e356f681SHui Xie 
106e356f681SHui Xie     assert(!e1.has_value());
107e356f681SHui Xie     assert(e1.error().data_ == 10);
108e356f681SHui Xie     assert(e2.has_value());
109e356f681SHui Xie 
110e356f681SHui Xie     assert(s.moveCtorCalled);
111e356f681SHui Xie     assert(s.dtorCalled);
112e356f681SHui Xie   }
113e356f681SHui Xie 
114e356f681SHui Xie   // !this->has_value() && rhs.has_value()
115e356f681SHui Xie   {
116e356f681SHui Xie     Traced::state s{};
117e356f681SHui Xie     std::expected<void, Traced> e1(std::unexpect, s, 10);
118e356f681SHui Xie     std::expected<void, Traced> e2(std::in_place);
119e356f681SHui Xie 
120e356f681SHui Xie     e1.swap(e2);
121e356f681SHui Xie 
122e356f681SHui Xie     assert(e1.has_value());
123e356f681SHui Xie     assert(!e2.has_value());
124e356f681SHui Xie     assert(e2.error().data_ == 10);
125e356f681SHui Xie 
126e356f681SHui Xie     assert(s.moveCtorCalled);
127e356f681SHui Xie     assert(s.dtorCalled);
128e356f681SHui Xie   }
129e356f681SHui Xie 
130134c9159SJan Kokemüller   // TailClobberer
131134c9159SJan Kokemüller   {
132134c9159SJan Kokemüller     std::expected<void, TailClobbererNonTrivialMove<1>> x(std::in_place);
133134c9159SJan Kokemüller     std::expected<void, TailClobbererNonTrivialMove<1>> y(std::unexpect);
134134c9159SJan Kokemüller 
135134c9159SJan Kokemüller     x.swap(y);
136134c9159SJan Kokemüller 
137134c9159SJan Kokemüller     // The next line would fail if adjusting the "has value" flag happened
138134c9159SJan Kokemüller     // _before_ constructing the member object inside the `swap`.
139134c9159SJan Kokemüller     assert(!x.has_value());
140134c9159SJan Kokemüller     assert(y.has_value());
141134c9159SJan Kokemüller   }
142134c9159SJan Kokemüller 
1434f469053SJan Kokemüller   // CheckForInvalidWrites
1444f469053SJan Kokemüller   {
1454f469053SJan Kokemüller     {
1464f469053SJan Kokemüller       CheckForInvalidWrites<true, true> x(std::unexpect);
1474f469053SJan Kokemüller       CheckForInvalidWrites<true, true> y;
1484f469053SJan Kokemüller 
1494f469053SJan Kokemüller       x.swap(y);
1504f469053SJan Kokemüller 
1514f469053SJan Kokemüller       assert(x.check());
1524f469053SJan Kokemüller       assert(y.check());
1534f469053SJan Kokemüller     }
1544f469053SJan Kokemüller     {
1554f469053SJan Kokemüller       CheckForInvalidWrites<false, true> x(std::unexpect);
1564f469053SJan Kokemüller       CheckForInvalidWrites<false, true> y;
1574f469053SJan Kokemüller 
1584f469053SJan Kokemüller       x.swap(y);
1594f469053SJan Kokemüller 
1604f469053SJan Kokemüller       assert(x.check());
1614f469053SJan Kokemüller       assert(y.check());
1624f469053SJan Kokemüller     }
1634f469053SJan Kokemüller   }
1644f469053SJan Kokemüller 
165e356f681SHui Xie   return true;
166e356f681SHui Xie }
167e356f681SHui Xie 
168e356f681SHui Xie void testException() {
169e356f681SHui Xie #ifndef TEST_HAS_NO_EXCEPTIONS
170e356f681SHui Xie   // !e1.has_value() && e2.has_value()
171e356f681SHui Xie   {
172e356f681SHui Xie     bool e1Destroyed = false;
173e356f681SHui Xie     std::expected<void, ThrowOnMove> e1(std::unexpect, e1Destroyed);
174e356f681SHui Xie     std::expected<void, ThrowOnMove> e2(std::in_place);
175e356f681SHui Xie     try {
176e356f681SHui Xie       e1.swap(e2);
177e356f681SHui Xie       assert(false);
178e356f681SHui Xie     } catch (Except) {
179e356f681SHui Xie       assert(!e1.has_value());
180e356f681SHui Xie       assert(e2.has_value());
181e356f681SHui Xie       assert(!e1Destroyed);
182e356f681SHui Xie     }
183e356f681SHui Xie   }
184e356f681SHui Xie 
185e356f681SHui Xie   // e1.has_value() && !e2.has_value()
186e356f681SHui Xie   {
187e356f681SHui Xie     bool e2Destroyed = false;
188e356f681SHui Xie     std::expected<void, ThrowOnMove> e1(std::in_place);
189e356f681SHui Xie     std::expected<void, ThrowOnMove> e2(std::unexpect, e2Destroyed);
190e356f681SHui Xie     try {
191e356f681SHui Xie       e1.swap(e2);
192e356f681SHui Xie       assert(false);
193e356f681SHui Xie     } catch (Except) {
194e356f681SHui Xie       assert(e1.has_value());
195e356f681SHui Xie       assert(!e2.has_value());
196e356f681SHui Xie       assert(!e2Destroyed);
197e356f681SHui Xie     }
198e356f681SHui Xie   }
199134c9159SJan Kokemüller 
200134c9159SJan Kokemüller   // TailClobberer
201134c9159SJan Kokemüller   {
202134c9159SJan Kokemüller     std::expected<void, TailClobbererNonTrivialMove<0, false, true>> x(std::in_place);
203134c9159SJan Kokemüller     std::expected<void, TailClobbererNonTrivialMove<0, false, true>> y(std::unexpect);
204134c9159SJan Kokemüller     try {
205134c9159SJan Kokemüller       x.swap(y);
206134c9159SJan Kokemüller       assert(false);
207134c9159SJan Kokemüller     } catch (Except) {
208134c9159SJan Kokemüller       // This would fail if `TailClobbererNonTrivialMove<0, false, true>`
209134c9159SJan Kokemüller       // clobbered the flag before throwing the exception.
210134c9159SJan Kokemüller       assert(x.has_value());
211134c9159SJan Kokemüller       assert(!y.has_value());
212134c9159SJan Kokemüller     }
213134c9159SJan Kokemüller   }
214e356f681SHui Xie #endif // TEST_HAS_NO_EXCEPTIONS
215e356f681SHui Xie }
216e356f681SHui Xie 
217e356f681SHui Xie int main(int, char**) {
218e356f681SHui Xie   test();
219e356f681SHui Xie   static_assert(test());
220e356f681SHui Xie   testException();
221e356f681SHui Xie   return 0;
222e356f681SHui Xie }
223