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 // template<class U, class G> 12 // constexpr explicit(see below) expected(const expected<U, G>&); 13 // 14 // Let: 15 // - UF be const U& 16 // - GF be const G& 17 // 18 // Constraints: 19 // - is_constructible_v<T, UF> is true; and 20 // - is_constructible_v<E, GF> is true; and 21 // - is_constructible_v<T, expected<U, G>&> is false; and 22 // - is_constructible_v<T, expected<U, G>> is false; and 23 // - is_constructible_v<T, const expected<U, G>&> is false; and 24 // - is_constructible_v<T, const expected<U, G>> is false; and 25 // - is_convertible_v<expected<U, G>&, T> is false; and 26 // - is_convertible_v<expected<U, G>&&, T> is false; and 27 // - is_convertible_v<const expected<U, G>&, T> is false; and 28 // - is_convertible_v<const expected<U, G>&&, T> is false; and 29 // - is_constructible_v<unexpected<E>, expected<U, G>&> is false; and 30 // - is_constructible_v<unexpected<E>, expected<U, G>> is false; and 31 // - is_constructible_v<unexpected<E>, const expected<U, G>&> is false; and 32 // - is_constructible_v<unexpected<E>, const expected<U, G>> is false. 33 // 34 // Effects: If rhs.has_value(), direct-non-list-initializes val with std::forward<UF>(*rhs). Otherwise, direct-non-list-initializes unex with std::forward<GF>(rhs.error()). 35 // 36 // Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true. 37 // 38 // Throws: Any exception thrown by the initialization of val or unex. 39 // 40 // Remarks: The expression inside explicit is equivalent to !is_convertible_v<UF, T> || !is_convertible_v<GF, E>. 41 42 #include <cassert> 43 #include <concepts> 44 #include <expected> 45 #include <type_traits> 46 #include <utility> 47 48 #include "test_macros.h" 49 #include "../../types.h" 50 51 // Test Constraints: 52 template <class T1, class Err1, class T2, class Err2> 53 concept canCstrFromExpected = std::is_constructible_v<std::expected<T1, Err1>, const std::expected<T2, Err2>&>; 54 55 struct CtorFromInt { 56 CtorFromInt(int); 57 }; 58 59 static_assert(canCstrFromExpected<CtorFromInt, int, int, int>); 60 61 struct NoCtorFromInt {}; 62 63 // !is_constructible_v<T, UF> 64 static_assert(!canCstrFromExpected<NoCtorFromInt, int, int, int>); 65 66 // !is_constructible_v<E, GF> 67 static_assert(!canCstrFromExpected<int, NoCtorFromInt, int, int>); 68 69 template <class T> 70 struct CtorFrom { 71 explicit CtorFrom(int) 72 requires(!std::same_as<T, int>); 73 explicit CtorFrom(T); 74 explicit CtorFrom(auto&&) = delete; 75 }; 76 77 // is_constructible_v<T, expected<U, G>&> 78 static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int>&>, int, int, int>); 79 80 // is_constructible_v<T, expected<U, G>> 81 static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int>&&>, int, int, int>); 82 83 // is_constructible_v<T, expected<U, G>&> 84 // note that this is true because it is covered by the other overload 85 // template<class U = T> constexpr explicit(see below) expected(U&& v); 86 // The fact that it is not ambiguous proves that the overload under testing is removed 87 static_assert(canCstrFromExpected<CtorFrom<std::expected<int, int> const&>, int, int, int>); 88 89 // is_constructible_v<T, expected<U, G>> 90 static_assert(!canCstrFromExpected<CtorFrom<std::expected<int, int> const&&>, int, int, int>); 91 92 template <class T> 93 struct ConvertFrom { 94 ConvertFrom(int) 95 requires(!std::same_as<T, int>); 96 ConvertFrom(T); 97 ConvertFrom(auto&&) = delete; 98 }; 99 100 // is_convertible_v<expected<U, G>&, T> 101 static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int>&>, int, int, int>); 102 103 // is_convertible_v<expected<U, G>&&, T> 104 static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int>&&>, int, int, int>); 105 106 // is_convertible_v<const expected<U, G>&, T> 107 // note that this is true because it is covered by the other overload 108 // template<class U = T> constexpr explicit(see below) expected(U&& v); 109 // The fact that it is not ambiguous proves that the overload under testing is removed 110 static_assert(canCstrFromExpected<ConvertFrom<std::expected<int, int> const&>, int, int, int>); 111 112 // is_convertible_v<const expected<U, G>&&, T> 113 static_assert(!canCstrFromExpected<ConvertFrom<std::expected<int, int> const&&>, int, int, int>); 114 115 // Note for below 4 tests, because their E is constructible from cvref of std::expected<int, int>, 116 // unexpected<E> will be constructible from cvref of std::expected<int, int> 117 // is_constructible_v<unexpected<E>, expected<U, G>&> 118 static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&>, int, int>); 119 120 // is_constructible_v<unexpected<E>, expected<U, G>> 121 static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int>&&>, int, int>); 122 123 // is_constructible_v<unexpected<E>, const expected<U, G>&> is false 124 static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&>, int, int>); 125 126 // is_constructible_v<unexpected<E>, const expected<U, G>> 127 static_assert(!canCstrFromExpected<int, CtorFrom<std::expected<int, int> const&&>, int, int>); 128 129 // test explicit 130 static_assert(std::is_convertible_v<const std::expected<int, int>&, std::expected<short, long>>); 131 132 // !is_convertible_v<UF, T> 133 static_assert(std::is_constructible_v<std::expected<CtorFrom<int>, int>, const std::expected<int, int>&>); 134 static_assert(!std::is_convertible_v<const std::expected<int, int>&, std::expected<CtorFrom<int>, int>>); 135 136 // !is_convertible_v<GF, E>. 137 static_assert(std::is_constructible_v<std::expected<int, CtorFrom<int>>, const std::expected<int, int>&>); 138 static_assert(!std::is_convertible_v<const std::expected<int, int>&, std::expected<int, CtorFrom<int>>>); 139 140 struct Data { 141 int i; 142 constexpr Data(int ii) : i(ii) {} 143 }; 144 145 constexpr bool test() { 146 // convert the value 147 { 148 const std::expected<int, int> e1(5); 149 std::expected<Data, int> e2 = e1; 150 assert(e2.has_value()); 151 assert(e2.value().i == 5); 152 assert(e1.has_value()); 153 assert(e1.value() == 5); 154 } 155 156 // convert the error 157 { 158 const std::expected<int, int> e1(std::unexpect, 5); 159 std::expected<int, Data> e2 = e1; 160 assert(!e2.has_value()); 161 assert(e2.error().i == 5); 162 assert(!e1.has_value()); 163 assert(e1.error() == 5); 164 } 165 166 // convert TailClobberer 167 { 168 const std::expected<TailClobbererNonTrivialMove<0>, char> e1; 169 std::expected<TailClobberer<0>, char> e2 = e1; 170 assert(e2.has_value()); 171 assert(e1.has_value()); 172 } 173 174 return true; 175 } 176 177 void testException() { 178 #ifndef TEST_HAS_NO_EXCEPTIONS 179 struct ThrowingInt { 180 ThrowingInt(int) { throw Except{}; } 181 }; 182 183 // throw on converting value 184 { 185 const std::expected<int, int> e1; 186 try { 187 [[maybe_unused]] std::expected<ThrowingInt, int> e2 = e1; 188 assert(false); 189 } catch (Except) { 190 } 191 } 192 193 // throw on converting error 194 { 195 const std::expected<int, int> e1(std::unexpect); 196 try { 197 [[maybe_unused]] std::expected<int, ThrowingInt> e2 = e1; 198 assert(false); 199 } catch (Except) { 200 } 201 } 202 203 #endif // TEST_HAS_NO_EXCEPTIONS 204 } 205 206 int main(int, char**) { 207 test(); 208 static_assert(test()); 209 testException(); 210 return 0; 211 } 212