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