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(see below);
12//
13// Constraints:
14// - is_move_constructible_v<T> is true and
15// - is_move_constructible_v<E> is true.
16//
17// Effects: If rhs.has_value() is true, direct-non-list-initializes val with std::move(*rhs).
18// Otherwise, direct-non-list-initializes unex with std::move(rhs.error()).
19//
20// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true.
21//
22// Throws: Any exception thrown by the initialization of val or unex.
23//
24// Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v<T> && is_nothrow_move_constructible_v<E>.
25//
26// This constructor is trivial if
27// - is_trivially_move_constructible_v<T> is true and
28// - is_trivially_move_constructible_v<E> is true.
29
30#include <cassert>
31#include <expected>
32#include <type_traits>
33#include <utility>
34
35#include "test_macros.h"
36#include "../../types.h"
37
38struct NonMovable {
39 NonMovable(NonMovable&&) = delete;
40};
41
42struct MovableNonTrivial {
43 int i;
44 constexpr MovableNonTrivial(int ii) : i(ii) {}
45 constexpr MovableNonTrivial(MovableNonTrivial&& o) : i(o.i) { o.i = 0; }
46 friend constexpr bool operator==(const MovableNonTrivial&, const MovableNonTrivial&) = default;
47};
48
49struct MoveMayThrow {
50 MoveMayThrow(MoveMayThrow&&) {}
51};
52
53// Test Constraints:
54// - is_move_constructible_v<T> is true and
55// - is_move_constructible_v<E> is true.
56static_assert(std::is_move_constructible_v<std::expected<int, int>>);
57static_assert(std::is_move_constructible_v<std::expected<MovableNonTrivial, int>>);
58static_assert(std::is_move_constructible_v<std::expected<int, MovableNonTrivial>>);
59static_assert(std::is_move_constructible_v<std::expected<MovableNonTrivial, MovableNonTrivial>>);
60static_assert(!std::is_move_constructible_v<std::expected<NonMovable, int>>);
61static_assert(!std::is_move_constructible_v<std::expected<int, NonMovable>>);
62static_assert(!std::is_move_constructible_v<std::expected<NonMovable, NonMovable>>);
63
64// Test: This constructor is trivial if
65// - is_trivially_move_constructible_v<T> is true and
66// - is_trivially_move_constructible_v<E> is true.
67static_assert(std::is_trivially_move_constructible_v<std::expected<int, int>>);
68static_assert(!std::is_trivially_move_constructible_v<std::expected<MovableNonTrivial, int>>);
69static_assert(!std::is_trivially_move_constructible_v<std::expected<int, MovableNonTrivial>>);
70static_assert(!std::is_trivially_move_constructible_v<std::expected<MovableNonTrivial, MovableNonTrivial>>);
71
72// Test: The exception specification is equivalent to
73// is_nothrow_move_constructible_v<T> && is_nothrow_move_constructible_v<E>.
74static_assert(std::is_nothrow_move_constructible_v<std::expected<int, int>>);
75static_assert(!std::is_nothrow_move_constructible_v<std::expected<MoveMayThrow, int>>);
76static_assert(!std::is_nothrow_move_constructible_v<std::expected<int, MoveMayThrow>>);
77static_assert(!std::is_nothrow_move_constructible_v<std::expected<MoveMayThrow, MoveMayThrow>>);
78
79constexpr bool test() {
80 // move the value non-trivial
81 {
82 std::expected<MovableNonTrivial, int> e1(5);
83 auto e2 = std::move(e1);
84 assert(e2.has_value());
85 assert(e2.value().i == 5);
86 assert(e1.has_value());
87 assert(e1.value().i == 0);
88 }
89
90 // move the error non-trivial
91 {
92 std::expected<int, MovableNonTrivial> e1(std::unexpect, 5);
93 auto e2 = std::move(e1);
94 assert(!e2.has_value());
95 assert(e2.error().i == 5);
96 assert(!e1.has_value());
97 assert(e1.error().i == 0);
98 }
99
100 // move the value trivial
101 {
102 std::expected<int, int> e1(5);
103 auto e2 = std::move(e1);
104 assert(e2.has_value());
105 assert(e2.value() == 5);
106 assert(e1.has_value());
107 }
108
109 // move the error trivial
110 {
111 std::expected<int, int> e1(std::unexpect, 5);
112 auto e2 = std::move(e1);
113 assert(!e2.has_value());
114 assert(e2.error() == 5);
115 assert(!e1.has_value());
116 }
117
118 // move TailClobbererNonTrivialMove as value
119 {
120 std::expected<TailClobbererNonTrivialMove<0>, bool> e1;
121 auto e2 = std::move(e1);
122 assert(e2.has_value());
123 assert(e1.has_value());
124 }
125
126 // move TailClobbererNonTrivialMove as error
127 {
128 std::expected<bool, TailClobbererNonTrivialMove<1>> e1(std::unexpect);
129 auto e2 = std::move(e1);
130 assert(!e2.has_value());
131 assert(!e1.has_value());
132 }
133
134 return true;
135}
136
137void testException() {
138#ifndef TEST_HAS_NO_EXCEPTIONS
139 struct Throwing {
140 Throwing() = default;
141 Throwing(Throwing&&) { throw Except{}; }
142 };
143
144 // throw on moving value
145 {
146 std::expected<Throwing, int> e1;
147 try {
148 [[maybe_unused]] auto e2 = std::move(e1);
149 assert(false);
150 } catch (Except) {
151 }
152 }
153
154 // throw on moving error
155 {
156 std::expected<int, Throwing> e1(std::unexpect);
157 try {
158 [[maybe_unused]] auto e2 = std::move(e1);
159 assert(false);
160 } catch (Except) {
161 }
162 }
163
164#endif // TEST_HAS_NO_EXCEPTIONS
165}
166
167int main(int, char**) {
168 test();
169 static_assert(test());
170 testException();
171 return 0;
172}
173

source code of libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.move.pass.cpp