1e356f681SHui Xie //===----------------------------------------------------------------------===// 2*6a54dfbfSLouis Dionne // 3e356f681SHui Xie // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e356f681SHui Xie // See https://llvm.org/LICENSE.txt for license information. 5e356f681SHui Xie // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e356f681SHui Xie // 7e356f681SHui Xie //===----------------------------------------------------------------------===// 8e356f681SHui Xie 9e356f681SHui Xie // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 10e356f681SHui Xie 11e356f681SHui Xie // constexpr expected& operator=(expected&& rhs) noexcept(see below); 12e356f681SHui Xie // 13e356f681SHui Xie // Effects: 14e356f681SHui Xie // - If this->has_value() && rhs.has_value() is true, no effects. 15e356f681SHui Xie // - Otherwise, if this->has_value() is true, equivalent to: 16e356f681SHui Xie // construct_at(addressof(unex), std::move(rhs.unex)); 17e356f681SHui Xie // has_val = false; 18e356f681SHui Xie // - Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true. 19e356f681SHui Xie // - Otherwise, equivalent to unex = std::move(rhs.error()). 20e356f681SHui Xie // 21e356f681SHui Xie // Returns: *this. 22e356f681SHui Xie // 23e356f681SHui Xie // Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v<E> && is_nothrow_move_assignable_v<E>. 24e356f681SHui Xie // 25e356f681SHui Xie // This operator is defined as deleted unless is_move_constructible_v<E> is true and is_move_assignable_v<E> is true. 26e356f681SHui Xie 27e356f681SHui Xie #include <cassert> 28e356f681SHui Xie #include <concepts> 29e356f681SHui Xie #include <expected> 30e356f681SHui Xie #include <type_traits> 31e356f681SHui Xie #include <utility> 32e356f681SHui Xie 33e356f681SHui Xie #include "../../types.h" 34e356f681SHui Xie #include "test_macros.h" 35e356f681SHui Xie 36e356f681SHui Xie struct NotMoveConstructible { 37e356f681SHui Xie NotMoveConstructible(NotMoveConstructible&&) = delete; 38e356f681SHui Xie NotMoveConstructible& operator=(NotMoveConstructible&&) = default; 39e356f681SHui Xie }; 40e356f681SHui Xie 41e356f681SHui Xie struct NotMoveAssignable { 42e356f681SHui Xie NotMoveAssignable(NotMoveAssignable&&) = default; 43e356f681SHui Xie NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; 44e356f681SHui Xie }; 45e356f681SHui Xie 46e356f681SHui Xie // Test constraints 47e356f681SHui Xie static_assert(std::is_move_assignable_v<std::expected<void, int>>); 48e356f681SHui Xie 49e356f681SHui Xie // !is_move_assignable_v<E> 50e356f681SHui Xie static_assert(!std::is_move_assignable_v<std::expected<void, NotMoveAssignable>>); 51e356f681SHui Xie 52e356f681SHui Xie // !is_move_constructible_v<E> 53e356f681SHui Xie static_assert(!std::is_move_assignable_v<std::expected<void, NotMoveConstructible>>); 54e356f681SHui Xie 55e356f681SHui Xie // Test noexcept 56e356f681SHui Xie struct MoveCtorMayThrow { 57e356f681SHui Xie MoveCtorMayThrow(MoveCtorMayThrow&&) noexcept(false) {} 58e356f681SHui Xie MoveCtorMayThrow& operator=(MoveCtorMayThrow&&) noexcept = default; 59e356f681SHui Xie }; 60e356f681SHui Xie 61e356f681SHui Xie struct MoveAssignMayThrow { 62e356f681SHui Xie MoveAssignMayThrow(MoveAssignMayThrow&&) noexcept = default; 63e356f681SHui Xie MoveAssignMayThrow& operator=(MoveAssignMayThrow&&) noexcept(false) { return *this; } 64e356f681SHui Xie }; 65e356f681SHui Xie 66e356f681SHui Xie // Test noexcept 67e356f681SHui Xie static_assert(std::is_nothrow_move_assignable_v<std::expected<void, int>>); 68e356f681SHui Xie 69e356f681SHui Xie // !is_nothrow_move_assignable_v<E> 70e356f681SHui Xie static_assert(!std::is_nothrow_move_assignable_v<std::expected<void, MoveAssignMayThrow>>); 71e356f681SHui Xie 72e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 73e356f681SHui Xie static_assert(!std::is_nothrow_move_assignable_v<std::expected<void, MoveCtorMayThrow>>); 74e356f681SHui Xie 75e356f681SHui Xie constexpr bool test() { 76e356f681SHui Xie // If this->has_value() && rhs.has_value() is true, no effects. 77e356f681SHui Xie { 78e356f681SHui Xie std::expected<void, int> e1; 79e356f681SHui Xie std::expected<void, int> e2; 80e356f681SHui Xie decltype(auto) x = (e1 = std::move(e2)); 81e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<void, int>&>); 82e356f681SHui Xie assert(&x == &e1); 83e356f681SHui Xie assert(e1.has_value()); 84e356f681SHui Xie } 85e356f681SHui Xie 86e356f681SHui Xie // Otherwise, if this->has_value() is true, equivalent to: 87e356f681SHui Xie // construct_at(addressof(unex), std::move(rhs.unex)); 88e356f681SHui Xie // has_val = false; 89e356f681SHui Xie { 90e356f681SHui Xie Traced::state state{}; 91e356f681SHui Xie std::expected<void, Traced> e1; 92e356f681SHui Xie std::expected<void, Traced> e2(std::unexpect, state, 5); 93e356f681SHui Xie decltype(auto) x = (e1 = std::move(e2)); 94e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>); 95e356f681SHui Xie assert(&x == &e1); 96e356f681SHui Xie assert(!e1.has_value()); 97e356f681SHui Xie assert(e1.error().data_ == 5); 98e356f681SHui Xie 99e356f681SHui Xie assert(state.moveCtorCalled); 100e356f681SHui Xie } 101e356f681SHui Xie 102e356f681SHui Xie // Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true. 103e356f681SHui Xie { 104e356f681SHui Xie Traced::state state{}; 105e356f681SHui Xie std::expected<void, Traced> e1(std::unexpect, state, 5); 106e356f681SHui Xie std::expected<void, Traced> e2; 107e356f681SHui Xie decltype(auto) x = (e1 = std::move(e2)); 108e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>); 109e356f681SHui Xie assert(&x == &e1); 110e356f681SHui Xie assert(e1.has_value()); 111e356f681SHui Xie 112e356f681SHui Xie assert(state.dtorCalled); 113e356f681SHui Xie } 114e356f681SHui Xie 115e356f681SHui Xie // Otherwise, equivalent to unex = rhs.error(). 116e356f681SHui Xie { 117e356f681SHui Xie Traced::state state{}; 118e356f681SHui Xie std::expected<void, Traced> e1(std::unexpect, state, 5); 119e356f681SHui Xie std::expected<void, Traced> e2(std::unexpect, state, 10); 120e356f681SHui Xie decltype(auto) x = (e1 = std::move(e2)); 121e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<void, Traced>&>); 122e356f681SHui Xie assert(&x == &e1); 123e356f681SHui Xie assert(!e1.has_value()); 124e356f681SHui Xie assert(e1.error().data_ == 10); 125e356f681SHui Xie 126e356f681SHui Xie assert(state.moveAssignCalled); 127e356f681SHui Xie } 128e356f681SHui Xie 1294f469053SJan Kokemüller // CheckForInvalidWrites 1304f469053SJan Kokemüller { 1314f469053SJan Kokemüller { 1324f469053SJan Kokemüller CheckForInvalidWrites<true, true> e1; 1334f469053SJan Kokemüller CheckForInvalidWrites<true, true> e2(std::unexpect); 1344f469053SJan Kokemüller 1354f469053SJan Kokemüller e1 = std::move(e2); 1364f469053SJan Kokemüller 1374f469053SJan Kokemüller assert(e1.check()); 1384f469053SJan Kokemüller assert(e2.check()); 1394f469053SJan Kokemüller } 1404f469053SJan Kokemüller { 1414f469053SJan Kokemüller CheckForInvalidWrites<false, true> e1; 1424f469053SJan Kokemüller CheckForInvalidWrites<false, true> e2(std::unexpect); 1434f469053SJan Kokemüller 1444f469053SJan Kokemüller e1 = std::move(e2); 1454f469053SJan Kokemüller 1464f469053SJan Kokemüller assert(e1.check()); 1474f469053SJan Kokemüller assert(e2.check()); 1484f469053SJan Kokemüller } 1494f469053SJan Kokemüller } 1504f469053SJan Kokemüller 151e356f681SHui Xie return true; 152e356f681SHui Xie } 153e356f681SHui Xie 154e356f681SHui Xie void testException() { 155e356f681SHui Xie #ifndef TEST_HAS_NO_EXCEPTIONS 156e356f681SHui Xie std::expected<void, ThrowOnMoveConstruct> e1(std::in_place); 157e356f681SHui Xie std::expected<void, ThrowOnMoveConstruct> e2(std::unexpect); 158e356f681SHui Xie try { 159e356f681SHui Xie e1 = std::move(e2); 160e356f681SHui Xie assert(false); 161e356f681SHui Xie } catch (Except) { 162e356f681SHui Xie assert(e1.has_value()); 163e356f681SHui Xie } 164e356f681SHui Xie #endif // TEST_HAS_NO_EXCEPTIONS 165e356f681SHui Xie } 166e356f681SHui Xie 167e356f681SHui Xie int main(int, char**) { 168e356f681SHui Xie test(); 169e356f681SHui Xie static_assert(test()); 170e356f681SHui Xie testException(); 171e356f681SHui Xie return 0; 172e356f681SHui Xie } 173