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

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