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 // Older Clangs do not support the C++20 feature to constrain destructors 11 // XFAIL: clang-14, apple-clang-14 12 13 // constexpr expected& operator=(const expected& rhs); 14 // 15 // Effects: 16 // - If this->has_value() && rhs.has_value() is true, no effects. 17 // - Otherwise, if this->has_value() is true, equivalent to: construct_at(addressof(unex), rhs.unex); has_val = false; 18 // - Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true. 19 // - Otherwise, equivalent to unex = rhs.error(). 20 // 21 // Returns: *this. 22 // 23 // Remarks: This operator is defined as deleted unless is_copy_assignable_v<E> is true and is_copy_constructible_v<E> is true. 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 // Test constraints 45 static_assert(std::is_copy_assignable_v<std::expected<void, int>>); 46 47 // !is_copy_assignable_v<E> 48 static_assert(!std::is_copy_assignable_v<std::expected<void, NotCopyAssignable>>); 49 50 // !is_copy_constructible_v<E> 51 static_assert(!std::is_copy_assignable_v<std::expected<void, NotCopyConstructible>>); 52 53 constexpr bool test() { 54 // If this->has_value() && rhs.has_value() is true, no effects. 55 { 56 std::expected<void, int> e1; 57 std::expected<void, int> e2; 58 decltype(auto) x = (e1 = e2); 59 static_assert(std::same_as<decltype(x), std::expected<void, int>&>); 60 assert(&x == &e1); 61 assert(e1.has_value()); 62 } 63 64 // Otherwise, if this->has_value() is true, equivalent to: construct_at(addressof(unex), rhs.unex); has_val = false; 65 { 66 Traced::state state{}; 67 std::expected<void, Traced> e1; 68 std::expected<void, Traced> e2(std::unexpect, state, 5); 69 decltype(auto) x = (e1 = e2); 70 static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>); 71 assert(&x == &e1); 72 assert(!e1.has_value()); 73 assert(e1.error().data_ == 5); 74 75 assert(state.copyCtorCalled); 76 } 77 78 // Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true. 79 { 80 Traced::state state{}; 81 std::expected<void, Traced> e1(std::unexpect, state, 5); 82 std::expected<void, Traced> e2; 83 decltype(auto) x = (e1 = e2); 84 static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>); 85 assert(&x == &e1); 86 assert(e1.has_value()); 87 88 assert(state.dtorCalled); 89 } 90 91 // Otherwise, equivalent to unex = rhs.error(). 92 { 93 Traced::state state{}; 94 std::expected<void, Traced> e1(std::unexpect, state, 5); 95 std::expected<void, Traced> e2(std::unexpect, state, 10); 96 decltype(auto) x = (e1 = e2); 97 static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>); 98 assert(&x == &e1); 99 assert(!e1.has_value()); 100 assert(e1.error().data_ == 10); 101 102 assert(state.copyAssignCalled); 103 } 104 105 return true; 106 } 107 108 void testException() { 109 #ifndef TEST_HAS_NO_EXCEPTIONS 110 std::expected<void, ThrowOnCopyConstruct> e1(std::in_place); 111 std::expected<void, ThrowOnCopyConstruct> e2(std::unexpect); 112 try { 113 e1 = e2; 114 assert(false); 115 } catch (Except) { 116 assert(e1.has_value()); 117 } 118 #endif // TEST_HAS_NO_EXCEPTIONS 119 } 120 121 int main(int, char**) { 122 test(); 123 static_assert(test()); 124 testException(); 125 return 0; 126 } 127