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 = T> 12 // constexpr explicit(!is_convertible_v<U, T>) expected(U&& v); 13 // 14 // Constraints: 15 // - is_same_v<remove_cvref_t<U>, in_place_t> is false; and 16 // - is_same_v<expected, remove_cvref_t<U>> is false; and 17 // - remove_cvref_t<U> is not a specialization of unexpected; and 18 // - is_constructible_v<T, U> is true. 19 // 20 // Effects: Direct-non-list-initializes val with std::forward<U>(v). 21 // 22 // Postconditions: has_value() is true. 23 // 24 // Throws: Any exception thrown by the initialization of val. 25 26 #include <cassert> 27 #include <expected> 28 #include <type_traits> 29 #include <utility> 30 31 #include "MoveOnly.h" 32 #include "test_macros.h" 33 #include "../../types.h" 34 35 // Test Constraints: 36 static_assert(std::is_constructible_v<std::expected<int, int>, int>); 37 38 // is_same_v<remove_cvref_t<U>, in_place_t> 39 struct FromJustInplace { 40 FromJustInplace(std::in_place_t); 41 }; 42 static_assert(!std::is_constructible_v<std::expected<FromJustInplace, int>, std::in_place_t>); 43 static_assert(!std::is_constructible_v<std::expected<FromJustInplace, int>, std::in_place_t const&>); 44 45 // is_same_v<expected, remove_cvref_t<U>> 46 // Note that result is true because it is covered by the constructors that take expected 47 static_assert(std::is_constructible_v<std::expected<int, int>, std::expected<int, int>&>); 48 49 // remove_cvref_t<U> is a specialization of unexpected 50 // Note that result is true because it is covered by the constructors that take unexpected 51 static_assert(std::is_constructible_v<std::expected<int, int>, std::unexpected<int>&>); 52 53 // !is_constructible_v<T, U> 54 struct foo {}; 55 static_assert(!std::is_constructible_v<std::expected<int, int>, foo>); 56 57 // test explicit(!is_convertible_v<U, T>) 58 struct NotConvertible { 59 explicit NotConvertible(int); 60 }; 61 static_assert(std::is_convertible_v<int, std::expected<int, int>>); 62 static_assert(!std::is_convertible_v<int, std::expected<NotConvertible, int>>); 63 64 struct CopyOnly { 65 int i; 66 constexpr CopyOnly(int ii) : i(ii) {} 67 CopyOnly(const CopyOnly&) = default; 68 CopyOnly(CopyOnly&&) = delete; 69 friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; } 70 }; 71 72 struct BaseError {}; 73 struct DerivedError : BaseError {}; 74 75 template <class T, class E = int> 76 constexpr void testInt() { 77 std::expected<T, E> e(5); 78 assert(e.has_value()); 79 assert(e.value() == 5); 80 } 81 82 template <class T, class E = int> 83 constexpr void testLValue() { 84 T t(5); 85 std::expected<T, E> e(t); 86 assert(e.has_value()); 87 assert(e.value() == 5); 88 } 89 90 template <class T, class E = int> 91 constexpr void testRValue() { 92 std::expected<T, E> e(T(5)); 93 assert(e.has_value()); 94 assert(e.value() == 5); 95 } 96 97 constexpr bool test() { 98 testInt<int>(); 99 testInt<CopyOnly>(); 100 testInt<MoveOnly>(); 101 testInt<TailClobberer<0>, bool>(); 102 testLValue<int>(); 103 testLValue<CopyOnly>(); 104 testLValue<TailClobberer<0>, bool>(); 105 testRValue<int>(); 106 testRValue<MoveOnly>(); 107 testRValue<TailClobberer<0>, bool>(); 108 109 // Test default template argument. 110 // Without it, the template parameter cannot be deduced from an initializer list 111 { 112 struct Bar { 113 int i; 114 int j; 115 constexpr Bar(int ii, int jj) : i(ii), j(jj) {} 116 }; 117 118 std::expected<Bar, int> e({5, 6}); 119 assert(e.value().i == 5); 120 assert(e.value().j == 6); 121 } 122 123 // https://cplusplus.github.io/LWG/issue3836 124 125 // Test & 126 { 127 std::expected<bool, DerivedError> e1(false); 128 std::expected<bool, BaseError> e2(e1); 129 assert(e2.has_value()); 130 assert(!e2.value()); // yes, e2 holds "false" since LWG3836 131 } 132 133 // Test && 134 { 135 std::expected<bool, DerivedError> e1(false); 136 std::expected<bool, BaseError> e2(std::move(e1)); 137 assert(e2.has_value()); 138 assert(!e2.value()); // yes, e2 holds "false" since LWG3836 139 } 140 141 // Test const& 142 { 143 const std::expected<bool, DerivedError> e1(false); 144 std::expected<bool, BaseError> e2(e1); 145 assert(e2.has_value()); 146 assert(!e2.value()); // yes, e2 holds "false" since LWG3836 147 } 148 149 // Test const&& 150 { 151 const std::expected<bool, DerivedError> e1(false); 152 std::expected<bool, BaseError> e2(std::move(e1)); 153 assert(e2.has_value()); 154 assert(!e2.value()); // yes, e2 holds "false" since LWG3836 155 } 156 return true; 157 } 158 159 void testException() { 160 #ifndef TEST_HAS_NO_EXCEPTIONS 161 struct Throwing { 162 Throwing(int) { throw Except{}; }; 163 }; 164 165 try { 166 std::expected<Throwing, int> u(5); 167 assert(false); 168 } catch (Except) { 169 } 170 #endif // TEST_HAS_NO_EXCEPTIONS 171 } 172 173 int main(int, char**) { 174 test(); 175 static_assert(test()); 176 testException(); 177 return 0; 178 } 179