xref: /llvm-project/libcxx/test/std/utilities/expected/expected.void/ctor/ctor.move.pass.cpp (revision 6a54dfbfe534276d644d7f9c027f0deeb748dd53)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10 
11 // constexpr expected(expected&& rhs) noexcept(is_nothrow_move_constructible_v<E>);
12 //
13 // Constraints: is_move_constructible_v<E> is true.
14 //
15 // Effects: If rhs.has_value() is false, direct-non-list-initializes unex with std::move(rhs.error()).
16 //
17 // Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true.
18 //
19 // Throws: Any exception thrown by the initialization of unex.
20 //
21 // Remarks: This constructor is trivial if is_trivially_move_constructible_v<E> is true.
22 
23 #include <cassert>
24 #include <expected>
25 #include <type_traits>
26 #include <utility>
27 
28 #include "test_macros.h"
29 #include "../../types.h"
30 
31 struct NonMovable {
32   NonMovable(NonMovable&&) = delete;
33 };
34 
35 struct MovableNonTrivial {
36   int i;
37   constexpr MovableNonTrivial(int ii) : i(ii) {}
38   constexpr MovableNonTrivial(MovableNonTrivial&& o) : i(o.i) { o.i = 0; }
39   friend constexpr bool operator==(const MovableNonTrivial&, const MovableNonTrivial&) = default;
40 };
41 
42 struct MoveMayThrow {
43   MoveMayThrow(MoveMayThrow&&) {}
44 };
45 
46 // Test Constraints:
47 // - is_move_constructible_v<E> is true.
48 static_assert(std::is_move_constructible_v<std::expected<void, int>>);
49 static_assert(std::is_move_constructible_v<std::expected<void, MovableNonTrivial>>);
50 static_assert(!std::is_move_constructible_v<std::expected<void, NonMovable>>);
51 
52 // Test: This constructor is trivial if is_trivially_move_constructible_v<E> is true.
53 static_assert(std::is_trivially_move_constructible_v<std::expected<void, int>>);
54 static_assert(!std::is_trivially_move_constructible_v<std::expected<void, MovableNonTrivial>>);
55 
56 // Test: noexcept(is_nothrow_move_constructible_v<E>)
57 static_assert(std::is_nothrow_move_constructible_v<std::expected<int, int>>);
58 static_assert(!std::is_nothrow_move_constructible_v<std::expected<MoveMayThrow, int>>);
59 static_assert(!std::is_nothrow_move_constructible_v<std::expected<int, MoveMayThrow>>);
60 static_assert(!std::is_nothrow_move_constructible_v<std::expected<MoveMayThrow, MoveMayThrow>>);
61 
62 constexpr bool test() {
63   // move the error non-trivial
64   {
65     std::expected<void, MovableNonTrivial> e1(std::unexpect, 5);
66     auto e2 = std::move(e1);
67     assert(!e2.has_value());
68     assert(e2.error().i == 5);
69     assert(!e1.has_value());
70     assert(e1.error().i == 0);
71   }
72 
73   // move the error trivial
74   {
75     std::expected<void, int> e1(std::unexpect, 5);
76     auto e2 = std::move(e1);
77     assert(!e2.has_value());
78     assert(e2.error() == 5);
79     assert(!e1.has_value());
80   }
81 
82   // move TailClobbererNonTrivialMove as error
83   {
84     std::expected<void, TailClobbererNonTrivialMove<1>> e1(std::unexpect);
85     auto e2 = std::move(e1);
86     assert(!e2.has_value());
87     assert(!e1.has_value());
88   }
89 
90   return true;
91 }
92 
93 void testException() {
94 #ifndef TEST_HAS_NO_EXCEPTIONS
95   struct Throwing {
96     Throwing() = default;
97     Throwing(Throwing&&) { throw Except{}; }
98   };
99 
100   // throw on moving error
101   {
102     std::expected<void, Throwing> e1(std::unexpect);
103     try {
104       [[maybe_unused]] auto e2 = std::move(e1);
105       assert(false);
106     } catch (Except) {
107     }
108   }
109 
110 #endif // TEST_HAS_NO_EXCEPTIONS
111 }
112 
113 int main(int, char**) {
114   test();
115   static_assert(test());
116   testException();
117   return 0;
118 }
119