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 // Older Clangs do not support the C++20 feature to constrain destructors 10 // XFAIL: clang-14, apple-clang-14 11 12 // template<class G> 13 // constexpr expected& operator=(const unexpected<G>& e); 14 // 15 // Let GF be const G& 16 // 17 // Constraints: is_constructible_v<E, GF> is true and is_assignable_v<E&, GF> is true. 18 // 19 // Effects: 20 // - If has_value() is true, equivalent to: 21 // construct_at(addressof(unex), std::forward<GF>(e.error())); 22 // has_val = false; 23 // - Otherwise, equivalent to: unex = std::forward<GF>(e.error()); 24 // 25 // Returns: *this. 26 27 #include <cassert> 28 #include <concepts> 29 #include <expected> 30 #include <type_traits> 31 #include <utility> 32 33 #include "../../types.h" 34 #include "test_macros.h" 35 36 struct NotCopyConstructible { 37 NotCopyConstructible(const NotCopyConstructible&) = delete; 38 NotCopyConstructible& operator=(const NotCopyConstructible&) = default; 39 }; 40 41 struct NotCopyAssignable { 42 NotCopyAssignable(const NotCopyAssignable&) = default; 43 NotCopyAssignable& operator=(const NotCopyAssignable&) = delete; 44 }; 45 46 struct MoveMayThrow { 47 MoveMayThrow(MoveMayThrow const&) = default; 48 MoveMayThrow& operator=(const MoveMayThrow&) = default; 49 MoveMayThrow(MoveMayThrow&&) noexcept(false) {} 50 MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; } 51 }; 52 53 // Test constraints 54 static_assert(std::is_assignable_v<std::expected<void, int>&, const std::unexpected<int>&>); 55 56 // !is_constructible_v<E, GF> 57 static_assert( 58 !std::is_assignable_v<std::expected<void, NotCopyConstructible>&, const std::unexpected<NotCopyConstructible>&>); 59 60 // !is_assignable_v<E&, GF> 61 static_assert( 62 !std::is_assignable_v<std::expected<void, NotCopyAssignable>&, const std::unexpected<NotCopyAssignable>&>); 63 64 constexpr bool test() { 65 // - If has_value() is true, equivalent to: 66 // construct_at(addressof(unex), std::forward<GF>(e.error())); 67 // has_val = false; 68 { 69 Traced::state state{}; 70 std::expected<void, Traced> e; 71 std::unexpected<Traced> un(std::in_place, state, 5); 72 decltype(auto) x = (e = un); 73 static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>); 74 assert(&x == &e); 75 assert(!e.has_value()); 76 assert(e.error().data_ == 5); 77 78 assert(state.copyCtorCalled); 79 } 80 81 // - Otherwise, equivalent to: unex = std::forward<GF>(e.error()); 82 { 83 Traced::state state1{}; 84 Traced::state state2{}; 85 std::expected<void, Traced> e(std::unexpect, state1, 5); 86 std::unexpected<Traced> un(std::in_place, state2, 10); 87 decltype(auto) x = (e = un); 88 static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>); 89 assert(&x == &e); 90 assert(!e.has_value()); 91 assert(e.error().data_ == 10); 92 93 assert(state1.copyAssignCalled); 94 } 95 96 return true; 97 } 98 99 void testException() { 100 #ifndef TEST_HAS_NO_EXCEPTIONS 101 std::expected<void, ThrowOnCopyConstruct> e1(std::in_place); 102 std::unexpected<ThrowOnCopyConstruct> un(std::in_place); 103 try { 104 e1 = un; 105 assert(false); 106 } catch (Except) { 107 assert(e1.has_value()); 108 } 109 #endif // TEST_HAS_NO_EXCEPTIONS 110 } 111 112 int main(int, char**) { 113 test(); 114 static_assert(test()); 115 testException(); 116 return 0; 117 } 118