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

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