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 Err = E> 12 // constexpr explicit unexpected(Err&& e); 13 // 14 // Constraints: 15 // - is_same_v<remove_cvref_t<Err>, unexpected> is false; and 16 // - is_same_v<remove_cvref_t<Err>, in_place_t> is false; and 17 // - is_constructible_v<E, Err> is true. 18 // 19 // Effects: Direct-non-list-initializes unex with std::forward<Err>(e). 20 // Throws: Any exception thrown by the initialization of unex. 21 22 #include <cassert> 23 #include <concepts> 24 #include <expected> 25 #include <utility> 26 27 #include "test_macros.h" 28 29 // Test Constraints: 30 static_assert(std::constructible_from<std::unexpected<int>, int>); 31 32 // is_same_v<remove_cvref_t<Err>, unexpected> 33 struct CstrFromUnexpected { 34 CstrFromUnexpected(CstrFromUnexpected const&) = delete; 35 CstrFromUnexpected(std::unexpected<CstrFromUnexpected> const&); 36 }; 37 static_assert(!std::constructible_from<std::unexpected<CstrFromUnexpected>, std::unexpected<CstrFromUnexpected>>); 38 39 // is_same_v<remove_cvref_t<Err>, in_place_t> 40 struct CstrFromInplace { 41 CstrFromInplace(std::in_place_t); 42 }; 43 static_assert(!std::constructible_from<std::unexpected<CstrFromInplace>, std::in_place_t>); 44 45 // !is_constructible_v<E, Err> 46 struct Foo {}; 47 static_assert(!std::constructible_from<std::unexpected<Foo>, int>); 48 49 // test explicit 50 static_assert(std::convertible_to<int, int>); 51 static_assert(!std::convertible_to<int, std::unexpected<int>>); 52 53 struct Error { 54 int i; 55 constexpr Error(int ii) : i(ii) {} 56 constexpr Error(const Error& other) : i(other.i) {} 57 constexpr Error(Error&& other) : i(other.i) { other.i = 0; } 58 Error(std::initializer_list<Error>) { assert(false); } 59 }; 60 61 constexpr bool test() { 62 // lvalue 63 { 64 Error e(5); 65 std::unexpected<Error> unex(e); 66 assert(unex.error().i == 5); 67 assert(e.i == 5); 68 } 69 70 // rvalue 71 { 72 Error e(5); 73 std::unexpected<Error> unex(std::move(e)); 74 assert(unex.error().i == 5); 75 assert(e.i == 0); 76 } 77 78 // Direct-non-list-initializes: does not trigger initializer_list overload 79 { 80 Error e(5); 81 [[maybe_unused]] std::unexpected<Error> unex(e); 82 } 83 84 // Test default template argument. 85 // Without it, the template parameter cannot be deduced from an initializer list 86 { 87 struct Bar { 88 int i; 89 int j; 90 constexpr Bar(int ii, int jj) : i(ii), j(jj) {} 91 }; 92 std::unexpected<Bar> ue({5, 6}); 93 assert(ue.error().i == 5); 94 assert(ue.error().j == 6); 95 } 96 97 return true; 98 } 99 100 void testException() { 101 #ifndef TEST_HAS_NO_EXCEPTIONS 102 struct Except {}; 103 104 struct Throwing { 105 Throwing() = default; 106 Throwing(const Throwing&) { throw Except{}; } 107 }; 108 109 Throwing t; 110 try { 111 std::unexpected<Throwing> u(t); 112 assert(false); 113 } catch (Except) { 114 } 115 #endif // TEST_HAS_NO_EXCEPTIONS 116 } 117 118 int main(int, char**) { 119 test(); 120 static_assert(test()); 121 testException(); 122 return 0; 123 } 124