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