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