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// template<class U, class G>
11// constexpr explicit(!is_convertible_v<G, E>) expected(expected<U, G>&& rhs);
12//
13// Let GF be G
14//
15// Constraints:
16// - is_void_v<U> is true; and
17// - is_constructible_v<E, GF> is true; and
18// - is_constructible_v<unexpected<E>, expected<U, G>&> is false; and
19// - is_constructible_v<unexpected<E>, expected<U, G>> is false; and
20// - is_constructible_v<unexpected<E>, const expected<U, G>&> is false; and
21// - is_constructible_v<unexpected<E>, const expected<U, G>> is false.
22//
23// Effects: If rhs.has_value() is false, direct-non-list-initializes unex with std::forward<GF>(rhs.error()).
24//
25// Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true.
26//
27// Throws: Any exception thrown by the initialization of unex.
28
29#include <cassert>
30#include <concepts>
31#include <expected>
32#include <type_traits>
33#include <utility>
34
35#include "MoveOnly.h"
36#include "test_macros.h"
37#include "../../types.h"
38
39// Test Constraints:
40template <class T1, class Err1, class T2, class Err2>
41concept canCstrFromExpected = std::is_constructible_v<std::expected<T1, Err1>, std::expected<T2, Err2>&&>;
42
43struct CtorFromInt {
44 CtorFromInt(int);
45};
46
47static_assert(canCstrFromExpected<void, CtorFromInt, void, int>);
48
49struct NoCtorFromInt {};
50
51// !is_void_v<U>
52static_assert(!canCstrFromExpected<void, int, int, int>);
53
54// !is_constructible_v<E, GF>
55static_assert(!canCstrFromExpected<void, NoCtorFromInt, void, int>);
56
57template <class T>
58struct CtorFrom {
59 explicit CtorFrom(int)
60 requires(!std::same_as<T, int>);
61 explicit CtorFrom(T);
62 explicit CtorFrom(auto&&) = delete;
63};
64
65// Note for below 4 tests, because their E is constructible from cvref of std::expected<void, int>,
66// unexpected<E> will be constructible from cvref of std::expected<void, int>
67// is_constructible_v<unexpected<E>, expected<U, G>&>
68static_assert(!canCstrFromExpected<void, CtorFrom<std::expected<void, int>&>, void, int>);
69
70// is_constructible_v<unexpected<E>, expected<U, G>>
71static_assert(!canCstrFromExpected<void, CtorFrom<std::expected<void, int>&&>, void, int>);
72
73// is_constructible_v<unexpected<E>, const expected<U, G>&> is false
74static_assert(!canCstrFromExpected<void, CtorFrom<std::expected<void, int> const&>, void, int>);
75
76// is_constructible_v<unexpected<E>, const expected<U, G>>
77static_assert(!canCstrFromExpected<void, CtorFrom<std::expected<void, int> const&&>, void, int>);
78
79// test explicit
80static_assert(std::is_convertible_v<std::expected<void, int>&&, std::expected<void, long>>);
81
82// !is_convertible_v<GF, E>.
83static_assert(std::is_constructible_v<std::expected<void, CtorFrom<int>>, std::expected<void, int>&&>);
84static_assert(!std::is_convertible_v<std::expected<void, int>&&, std::expected<void, CtorFrom<int>>>);
85
86struct Data {
87 MoveOnly data;
88 constexpr Data(MoveOnly&& m) : data(std::move(m)) {}
89};
90
91constexpr bool test() {
92 // convert the error
93 {
94 std::expected<void, MoveOnly> e1(std::unexpect, 5);
95 std::expected<void, Data> e2 = std::move(e1);
96 assert(!e2.has_value());
97 assert(e2.error().data.get() == 5);
98 assert(!e1.has_value());
99 assert(e1.error().get() == 0);
100 }
101
102 // convert TailClobberer
103 {
104 std::expected<void, TailClobbererNonTrivialMove<1>> e1(std::unexpect);
105 std::expected<void, TailClobberer<1>> e2 = std::move(e1);
106 assert(!e2.has_value());
107 assert(!e1.has_value());
108 }
109
110 return true;
111}
112
113void testException() {
114#ifndef TEST_HAS_NO_EXCEPTIONS
115 struct ThrowingInt {
116 ThrowingInt(int) { throw Except{}; }
117 };
118
119 // throw on converting error
120 {
121 const std::expected<void, int> e1(std::unexpect);
122 try {
123 [[maybe_unused]] std::expected<void, ThrowingInt> e2 = e1;
124 assert(false);
125 } catch (Except) {
126 }
127 }
128
129#endif // TEST_HAS_NO_EXCEPTIONS
130}
131
132int main(int, char**) {
133 test();
134 static_assert(test());
135 testException();
136 return 0;
137}
138

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