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 // template<class G> 12e356f681SHui Xie // constexpr expected& operator=(unexpected<G>&& e); 13e356f681SHui Xie // 14e356f681SHui Xie // Let GF be G 15e356f681SHui Xie // Constraints: 16e356f681SHui Xie // - is_constructible_v<E, GF> is true; and 17e356f681SHui Xie // - is_assignable_v<E&, GF> is true; and 18e356f681SHui Xie // - is_nothrow_constructible_v<E, GF> || is_nothrow_move_constructible_v<T> || 19e356f681SHui Xie // is_nothrow_move_constructible_v<E> is true. 20e356f681SHui Xie // 21e356f681SHui Xie // Effects: 22e356f681SHui Xie // - If has_value() is true, equivalent to: 23e356f681SHui Xie // reinit-expected(unex, val, std::forward<GF>(e.error())); 24e356f681SHui Xie // has_val = false; 25e356f681SHui Xie // - Otherwise, equivalent to: unex = std::forward<GF>(e.error()); 26e356f681SHui Xie // Returns: *this. 27e356f681SHui Xie 28e356f681SHui Xie #include <cassert> 29e356f681SHui Xie #include <concepts> 30e356f681SHui Xie #include <expected> 31e356f681SHui Xie #include <type_traits> 32e356f681SHui Xie #include <utility> 33e356f681SHui Xie 34e356f681SHui Xie #include "../../types.h" 35e356f681SHui Xie #include "test_macros.h" 36e356f681SHui Xie 37e356f681SHui Xie struct NotMoveConstructible { 38e356f681SHui Xie NotMoveConstructible(NotMoveConstructible&&) = delete; 39e356f681SHui Xie NotMoveConstructible& operator=(NotMoveConstructible&&) = default; 40e356f681SHui Xie }; 41e356f681SHui Xie 42e356f681SHui Xie struct NotMoveAssignable { 43e356f681SHui Xie NotMoveAssignable(NotMoveAssignable&&) = default; 44e356f681SHui Xie NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; 45e356f681SHui Xie }; 46e356f681SHui Xie 47e356f681SHui Xie struct MoveMayThrow { 48e356f681SHui Xie MoveMayThrow(MoveMayThrow const&) = default; 49e356f681SHui Xie MoveMayThrow& operator=(const MoveMayThrow&) = default; 50e356f681SHui Xie MoveMayThrow(MoveMayThrow&&) noexcept(false) {} 51e356f681SHui Xie MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) { return *this; } 52e356f681SHui Xie }; 53e356f681SHui Xie 54e356f681SHui Xie // Test constraints 55e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<int, int>&, std::unexpected<int>&&>); 56e356f681SHui Xie 57e356f681SHui Xie // !is_constructible_v<E, GF> 58e356f681SHui Xie static_assert( 59e356f681SHui Xie !std::is_assignable_v<std::expected<int, NotMoveConstructible>&, std::unexpected<NotMoveConstructible>&&>); 60e356f681SHui Xie 61e356f681SHui Xie // !is_assignable_v<E&, GF> 62e356f681SHui Xie static_assert(!std::is_assignable_v<std::expected<int, NotMoveAssignable>&, std::unexpected<NotMoveAssignable>&&>); 63e356f681SHui Xie 64e356f681SHui Xie template <bool moveNoexcept, bool convertNoexcept> 65e356f681SHui Xie struct MaybeNoexcept { 66e356f681SHui Xie explicit MaybeNoexcept(int) noexcept(convertNoexcept); 67e356f681SHui Xie MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept); 68e356f681SHui Xie MaybeNoexcept& operator=(MaybeNoexcept&&) = default; 69e356f681SHui Xie MaybeNoexcept& operator=(int); 70e356f681SHui Xie }; 71e356f681SHui Xie 72e356f681SHui Xie // !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> && 73e356f681SHui Xie // is_nothrow_move_constructible_v<E> 74e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<true, false>>&, 75e356f681SHui Xie std::unexpected<int>&&>); 76e356f681SHui Xie 77e356f681SHui Xie // is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> && 78e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 79e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<false, true>>&, 80e356f681SHui Xie std::unexpected<int>&&>); 81e356f681SHui Xie 82e356f681SHui Xie // !is_nothrow_constructible_v<E, GF> && is_nothrow_move_constructible_v<T> && 83e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 84e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<true, true>, MaybeNoexcept<false, false>>&, 85e356f681SHui Xie std::unexpected<int>&&>); 86e356f681SHui Xie 87e356f681SHui Xie // !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<T> && 88e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 89e356f681SHui Xie static_assert(!std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<false, false>>&, 90e356f681SHui Xie std::unexpected<int>&&>); 91e356f681SHui Xie 92e356f681SHui Xie constexpr bool test() { 93e356f681SHui Xie // - If has_value() is true, equivalent to: 94e356f681SHui Xie // reinit-expected(unex, val, std::forward<GF>(e.error())); 95e356f681SHui Xie // is_nothrow_constructible_v<E, GF> 96e356f681SHui Xie // 97e356f681SHui Xie // In this case, it should call the branch 98e356f681SHui Xie // destroy_at(addressof(oldval)); 99e356f681SHui Xie // construct_at(addressof(newval), std::forward<Args>(args)...); 100e356f681SHui Xie { 101e356f681SHui Xie BothNoexcept::state oldState{}; 102e356f681SHui Xie std::expected<BothNoexcept, BothNoexcept> e(std::in_place, oldState, 5); 103e356f681SHui Xie std::unexpected<int> un(10); 104e356f681SHui Xie decltype(auto) x = (e = std::move(un)); 105e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, BothNoexcept>&>); 106e356f681SHui Xie assert(&x == &e); 107e356f681SHui Xie 108e356f681SHui Xie assert(!oldState.moveCtorCalled); 109e356f681SHui Xie assert(oldState.dtorCalled); 110e356f681SHui Xie assert(e.error().movedFromInt); 111e356f681SHui Xie } 112e356f681SHui Xie 113e356f681SHui Xie // - If has_value() is true, equivalent to: 114e356f681SHui Xie // reinit-expected(unex, val, std::forward<GF>(e.error())); 115e356f681SHui Xie // !is_nothrow_constructible_v<E, GF> && is_nothrow_move_constructible_v<E> 116e356f681SHui Xie // 117e356f681SHui Xie // In this case, it should call the branch 118e356f681SHui Xie // T tmp(std::forward<Args>(args)...); 119e356f681SHui Xie // destroy_at(addressof(oldval)); 120e356f681SHui Xie // construct_at(addressof(newval), std::move(tmp)); 121e356f681SHui Xie { 122e356f681SHui Xie BothNoexcept::state oldState{}; 123e356f681SHui Xie std::expected<BothNoexcept, MoveNoexceptConvThrow> e(std::in_place, oldState, 5); 124e356f681SHui Xie std::unexpected<int> un(10); 125e356f681SHui Xie decltype(auto) x = (e = std::move(un)); 126e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, MoveNoexceptConvThrow>&>); 127e356f681SHui Xie assert(&x == &e); 128e356f681SHui Xie 129e356f681SHui Xie assert(!oldState.moveCtorCalled); 130e356f681SHui Xie assert(oldState.dtorCalled); 131e356f681SHui Xie assert(!e.error().movedFromInt); 132e356f681SHui Xie assert(e.error().movedFromTmp); 133e356f681SHui Xie } 134e356f681SHui Xie 135e356f681SHui Xie // - If has_value() is true, equivalent to: 136e356f681SHui Xie // reinit-expected(unex, val, std::forward<GF>(e.error())); 137e356f681SHui Xie // !is_nothrow_constructible_v<E, GF> && !is_nothrow_move_constructible_v<E> 138e356f681SHui Xie // is_nothrow_move_constructible_v<T> 139e356f681SHui Xie // 140e356f681SHui Xie // In this case, it should call the branch 141e356f681SHui Xie // U tmp(std::move(oldval)); 142e356f681SHui Xie // destroy_at(addressof(oldval)); 143e356f681SHui Xie // try { 144e356f681SHui Xie // construct_at(addressof(newval), std::forward<Args>(args)...); 145e356f681SHui Xie // } catch (...) { 146e356f681SHui Xie // construct_at(addressof(oldval), std::move(tmp)); 147e356f681SHui Xie // throw; 148e356f681SHui Xie // } 149e356f681SHui Xie { 150e356f681SHui Xie BothNoexcept::state oldState{}; 151e356f681SHui Xie std::expected<BothNoexcept, BothMayThrow> e(std::in_place, oldState, 5); 152e356f681SHui Xie std::unexpected<int> un(10); 153e356f681SHui Xie decltype(auto) x = (e = std::move(un)); 154e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<BothNoexcept, BothMayThrow>&>); 155e356f681SHui Xie assert(&x == &e); 156e356f681SHui Xie 157e356f681SHui Xie assert(oldState.moveCtorCalled); 158e356f681SHui Xie assert(oldState.dtorCalled); 159e356f681SHui Xie assert(e.error().movedFromInt); 160e356f681SHui Xie } 161e356f681SHui Xie 162e356f681SHui Xie // Otherwise, equivalent to: unex = std::forward<GF>(e.error()); 163e356f681SHui Xie { 164e356f681SHui Xie Traced::state oldState{}; 165e356f681SHui Xie Traced::state newState{}; 166e356f681SHui Xie std::expected<int, Traced> e1(std::unexpect, oldState, 5); 167e356f681SHui Xie std::unexpected<Traced> e(std::in_place, newState, 10); 168e356f681SHui Xie decltype(auto) x = (e1 = std::move(e)); 169e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<int, Traced >&>); 170e356f681SHui Xie assert(&x == &e1); 171e356f681SHui Xie 172e356f681SHui Xie assert(!e1.has_value()); 173e356f681SHui Xie assert(e1.error().data_ == 10); 174e356f681SHui Xie assert(oldState.moveAssignCalled); 175e356f681SHui Xie } 176e356f681SHui Xie return true; 177e356f681SHui Xie } 178e356f681SHui Xie 179e356f681SHui Xie void testException() { 180e356f681SHui Xie #ifndef TEST_HAS_NO_EXCEPTIONS 181e356f681SHui Xie std::expected<int, ThrowOnConvert> e1(std::in_place, 5); 182e356f681SHui Xie std::unexpected<int> un(10); 183e356f681SHui Xie try { 184e356f681SHui Xie e1 = std::move(un); 185e356f681SHui Xie assert(false); 186e356f681SHui Xie } catch (Except) { 187e356f681SHui Xie assert(e1.has_value()); 188e356f681SHui Xie assert(*e1 == 5); 189e356f681SHui Xie } 190e356f681SHui Xie #endif // TEST_HAS_NO_EXCEPTIONS 191e356f681SHui Xie } 192e356f681SHui Xie 193e356f681SHui Xie int main(int, char**) { 194e356f681SHui Xie test(); 195e356f681SHui Xie static_assert(test()); 196e356f681SHui Xie testException(); 197e356f681SHui Xie return 0; 198e356f681SHui Xie } 199