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 U = T> 12e356f681SHui Xie // constexpr expected& operator=(U&& v); 13e356f681SHui Xie // 14e356f681SHui Xie // Constraints: 15e356f681SHui Xie // - is_same_v<expected, remove_cvref_t<U>> is false; and 16e356f681SHui Xie // - remove_cvref_t<U> is not a specialization of unexpected; and 17e356f681SHui Xie // - is_constructible_v<T, U> is true; and 18e356f681SHui Xie // - is_assignable_v<T&, U> is true; and 19e356f681SHui Xie // - is_nothrow_constructible_v<T, U> || is_nothrow_move_constructible_v<T> || 20e356f681SHui Xie // is_nothrow_move_constructible_v<E> is true. 21e356f681SHui Xie // 22e356f681SHui Xie // Effects: 23e356f681SHui Xie // - If has_value() is true, equivalent to: val = std::forward<U>(v); 24e356f681SHui Xie // - Otherwise, equivalent to: 25e356f681SHui Xie // reinit-expected(val, unex, std::forward<U>(v)); 26e356f681SHui Xie // has_val = true; 27e356f681SHui Xie // - Returns: *this. 28e356f681SHui Xie 29e356f681SHui Xie #include <cassert> 30e356f681SHui Xie #include <concepts> 31e356f681SHui Xie #include <expected> 32e356f681SHui Xie #include <type_traits> 33e356f681SHui Xie #include <utility> 34e356f681SHui Xie 35e356f681SHui Xie #include "../../types.h" 36e356f681SHui Xie #include "test_macros.h" 37e356f681SHui Xie 38e356f681SHui Xie struct NotCopyConstructible { 39e356f681SHui Xie NotCopyConstructible(const NotCopyConstructible&) = delete; 40e356f681SHui Xie NotCopyConstructible& operator=(const NotCopyConstructible&) = default; 41e356f681SHui Xie }; 42e356f681SHui Xie 43e356f681SHui Xie struct NotCopyAssignable { 44e356f681SHui Xie NotCopyAssignable(const NotCopyAssignable&) = default; 45e356f681SHui Xie NotCopyAssignable& operator=(const NotCopyAssignable&) = delete; 46e356f681SHui Xie }; 47e356f681SHui Xie 48e356f681SHui Xie // Test constraints 49e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<int, int>&, int>); 50e356f681SHui Xie 51e356f681SHui Xie // is_same_v<expected, remove_cvref_t<U>> 52e356f681SHui Xie // it is true because it covered by the copy assignment 53e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<int, int>&, std::expected<int, int>>); 54e356f681SHui Xie 55e356f681SHui Xie // remove_cvref_t<U> is a specialization of unexpected 56f5832babSStephan T. Lavavej // it is true because it covered the unexpected overload 57e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<int, int>&, std::unexpected<int>>); 58e356f681SHui Xie 59e356f681SHui Xie // !is_constructible_v<T, U> 60e356f681SHui Xie struct NoCtorFromInt { 61e356f681SHui Xie NoCtorFromInt(int) = delete; 62e356f681SHui Xie NoCtorFromInt& operator=(int); 63e356f681SHui Xie }; 64e356f681SHui Xie static_assert(!std::is_assignable_v<std::expected<NoCtorFromInt, int>&, int>); 65e356f681SHui Xie 66e356f681SHui Xie // !is_assignable_v<T&, U> 67e356f681SHui Xie struct NoAssignFromInt { 68e356f681SHui Xie explicit NoAssignFromInt(int); 69e356f681SHui Xie NoAssignFromInt& operator=(int) = delete; 70e356f681SHui Xie }; 71e356f681SHui Xie static_assert(!std::is_assignable_v<std::expected<NoAssignFromInt, int>&, int>); 72e356f681SHui Xie 73e356f681SHui Xie template <bool moveNoexcept, bool convertNoexcept> 74e356f681SHui Xie struct MaybeNoexcept { 75e356f681SHui Xie explicit MaybeNoexcept(int) noexcept(convertNoexcept); 76e356f681SHui Xie MaybeNoexcept(MaybeNoexcept&&) noexcept(moveNoexcept); 77e356f681SHui Xie MaybeNoexcept& operator=(MaybeNoexcept&&) = default; 78e356f681SHui Xie MaybeNoexcept& operator=(int); 79e356f681SHui Xie }; 80e356f681SHui Xie 81e356f681SHui Xie // !is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> && 82e356f681SHui Xie // is_nothrow_move_constructible_v<E> 83e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, int>&, int>); 84e356f681SHui Xie 85e356f681SHui Xie // is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> && 86e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 87e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<false, true>, MaybeNoexcept<false, false>>&, int>); 88e356f681SHui Xie 89e356f681SHui Xie // !is_nothrow_constructible_v<T, U> && is_nothrow_move_constructible_v<T> && 90e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 91e356f681SHui Xie static_assert(std::is_assignable_v<std::expected<MaybeNoexcept<true, false>, MaybeNoexcept<false, false>>&, int>); 92e356f681SHui Xie 93e356f681SHui Xie // !is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> && 94e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 95e356f681SHui Xie static_assert(!std::is_assignable_v<std::expected<MaybeNoexcept<false, false>, MaybeNoexcept<false, false>>&, int>); 96e356f681SHui Xie 97e356f681SHui Xie constexpr bool test() { 98e356f681SHui Xie // If has_value() is true, equivalent to: val = std::forward<U>(v); 99e356f681SHui Xie // Copy 100e356f681SHui Xie { 101e356f681SHui Xie Traced::state oldState{}; 102e356f681SHui Xie Traced::state newState{}; 103e356f681SHui Xie std::expected<Traced, int> e1(std::in_place, oldState, 5); 104e356f681SHui Xie Traced u(newState, 10); 105e356f681SHui Xie decltype(auto) x = (e1 = u); 106e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<Traced, int>&>); 107e356f681SHui Xie assert(&x == &e1); 108e356f681SHui Xie 109e356f681SHui Xie assert(e1.has_value()); 110e356f681SHui Xie assert(e1.value().data_ == 10); 111e356f681SHui Xie assert(oldState.copyAssignCalled); 112e356f681SHui Xie } 113e356f681SHui Xie 114e356f681SHui Xie // If has_value() is true, equivalent to: val = std::forward<U>(v); 115e356f681SHui Xie // Move 116e356f681SHui Xie { 117e356f681SHui Xie Traced::state oldState{}; 118e356f681SHui Xie Traced::state newState{}; 119e356f681SHui Xie std::expected<Traced, int> e1(std::in_place, oldState, 5); 120e356f681SHui Xie Traced u(newState, 10); 121e356f681SHui Xie decltype(auto) x = (e1 = std::move(u)); 122e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<Traced, int>&>); 123e356f681SHui Xie assert(&x == &e1); 124e356f681SHui Xie 125e356f681SHui Xie assert(e1.has_value()); 126e356f681SHui Xie assert(e1.value().data_ == 10); 127e356f681SHui Xie assert(oldState.moveAssignCalled); 128e356f681SHui Xie } 129e356f681SHui Xie 130e356f681SHui Xie // Otherwise, equivalent to: 131e356f681SHui Xie // reinit-expected(val, unex, std::forward<U>(v)); 132e356f681SHui Xie // is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> && 133e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 134e356f681SHui Xie // copy 135e356f681SHui Xie // 136e356f681SHui Xie // In this case, it should call the branch 137e356f681SHui Xie // destroy_at(addressof(oldval)); 138e356f681SHui Xie // construct_at(addressof(newval), std::forward<Args>(args)...); 139e356f681SHui Xie { 140e356f681SHui Xie BothMayThrow::state oldState{}; 141e356f681SHui Xie std::expected<MoveThrowConvNoexcept, BothMayThrow> e1(std::unexpect, oldState, 5); 142e356f681SHui Xie const int i = 10; 143e356f681SHui Xie decltype(auto) x = (e1 = i); 144e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<MoveThrowConvNoexcept, BothMayThrow>&>); 145e356f681SHui Xie assert(&x == &e1); 146e356f681SHui Xie 147e356f681SHui Xie assert(e1.has_value()); 148e356f681SHui Xie assert(e1.value().data_ == 10); 149e356f681SHui Xie 150e356f681SHui Xie assert(!oldState.copyCtorCalled); 151e356f681SHui Xie assert(!oldState.moveCtorCalled); 152e356f681SHui Xie assert(oldState.dtorCalled); 153e356f681SHui Xie assert(e1.value().copiedFromInt); 154e356f681SHui Xie } 155e356f681SHui Xie 156e356f681SHui Xie // Otherwise, equivalent to: 157e356f681SHui Xie // reinit-expected(val, unex, std::forward<U>(v)); 158e356f681SHui Xie // is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> && 159e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 160e356f681SHui Xie // move 161e356f681SHui Xie // 162e356f681SHui Xie // In this case, it should call the branch 163e356f681SHui Xie // destroy_at(addressof(oldval)); 164e356f681SHui Xie // construct_at(addressof(newval), std::forward<Args>(args)...); 165e356f681SHui Xie { 166e356f681SHui Xie BothMayThrow::state oldState{}; 167e356f681SHui Xie std::expected<MoveThrowConvNoexcept, BothMayThrow> e1(std::unexpect, oldState, 5); 168e356f681SHui Xie decltype(auto) x = (e1 = 10); 169e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<MoveThrowConvNoexcept, BothMayThrow>&>); 170e356f681SHui Xie assert(&x == &e1); 171e356f681SHui Xie 172e356f681SHui Xie assert(e1.has_value()); 173e356f681SHui Xie assert(e1.value().data_ == 10); 174e356f681SHui Xie 175e356f681SHui Xie assert(!oldState.copyCtorCalled); 176e356f681SHui Xie assert(!oldState.moveCtorCalled); 177e356f681SHui Xie assert(oldState.dtorCalled); 178e356f681SHui Xie assert(e1.value().movedFromInt); 179e356f681SHui Xie } 180e356f681SHui Xie 181e356f681SHui Xie // Otherwise, equivalent to: 182e356f681SHui Xie // reinit-expected(val, unex, std::forward<U>(v)); 183e356f681SHui Xie // !is_nothrow_constructible_v<T, U> && is_nothrow_move_constructible_v<T> && 184e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 185e356f681SHui Xie // copy 186e356f681SHui Xie // 187e356f681SHui Xie // In this case, it should call the branch 188e356f681SHui Xie // T tmp(std::forward<Args>(args)...); 189e356f681SHui Xie // destroy_at(addressof(oldval)); 190e356f681SHui Xie // construct_at(addressof(newval), std::move(tmp)); 191e356f681SHui Xie { 192e356f681SHui Xie BothMayThrow::state oldState{}; 193e356f681SHui Xie std::expected<MoveNoexceptConvThrow, BothMayThrow> e1(std::unexpect, oldState, 5); 194e356f681SHui Xie const int i = 10; 195e356f681SHui Xie decltype(auto) x = (e1 = i); 196e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<MoveNoexceptConvThrow, BothMayThrow>&>); 197e356f681SHui Xie assert(&x == &e1); 198e356f681SHui Xie 199e356f681SHui Xie assert(e1.has_value()); 200e356f681SHui Xie assert(e1.value().data_ == 10); 201e356f681SHui Xie 202e356f681SHui Xie assert(!oldState.copyCtorCalled); 203e356f681SHui Xie assert(!oldState.moveCtorCalled); 204e356f681SHui Xie assert(oldState.dtorCalled); 205e356f681SHui Xie assert(!e1.value().copiedFromInt); 206e356f681SHui Xie assert(e1.value().movedFromTmp); 207e356f681SHui Xie } 208e356f681SHui Xie 209e356f681SHui Xie // Otherwise, equivalent to: 210e356f681SHui Xie // reinit-expected(val, unex, std::forward<U>(v)); 211e356f681SHui Xie // !is_nothrow_constructible_v<T, U> && is_nothrow_move_constructible_v<T> && 212e356f681SHui Xie // !is_nothrow_move_constructible_v<E> 213e356f681SHui Xie // move 214e356f681SHui Xie // 215e356f681SHui Xie // In this case, it should call the branch 216e356f681SHui Xie // T tmp(std::forward<Args>(args)...); 217e356f681SHui Xie // destroy_at(addressof(oldval)); 218e356f681SHui Xie // construct_at(addressof(newval), std::move(tmp)); 219e356f681SHui Xie { 220e356f681SHui Xie BothMayThrow::state oldState{}; 221e356f681SHui Xie std::expected<MoveNoexceptConvThrow, BothMayThrow> e1(std::unexpect, oldState, 5); 222e356f681SHui Xie decltype(auto) x = (e1 = 10); 223e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<MoveNoexceptConvThrow, BothMayThrow>&>); 224e356f681SHui Xie assert(&x == &e1); 225e356f681SHui Xie 226e356f681SHui Xie assert(e1.has_value()); 227e356f681SHui Xie assert(e1.value().data_ == 10); 228e356f681SHui Xie 229e356f681SHui Xie assert(!oldState.copyCtorCalled); 230e356f681SHui Xie assert(!oldState.moveCtorCalled); 231e356f681SHui Xie assert(oldState.dtorCalled); 232e356f681SHui Xie assert(!e1.value().copiedFromInt); 233e356f681SHui Xie assert(e1.value().movedFromTmp); 234e356f681SHui Xie } 235e356f681SHui Xie 236e356f681SHui Xie // Otherwise, equivalent to: 237e356f681SHui Xie // reinit-expected(val, unex, std::forward<U>(v)); 238e356f681SHui Xie // !is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> && 239e356f681SHui Xie // is_nothrow_move_constructible_v<E> 240e356f681SHui Xie // copy 241e356f681SHui Xie // 242e356f681SHui Xie // In this case, it should call the branch 243e356f681SHui Xie // U tmp(std::move(oldval)); 244e356f681SHui Xie // destroy_at(addressof(oldval)); 245e356f681SHui Xie // try { 246e356f681SHui Xie // construct_at(addressof(newval), std::forward<Args>(args)...); 247e356f681SHui Xie // } catch (...) { 248e356f681SHui Xie // construct_at(addressof(oldval), std::move(tmp)); 249e356f681SHui Xie // throw; 250e356f681SHui Xie // } 251e356f681SHui Xie { 252e356f681SHui Xie TracedNoexcept::state oldState{}; 253e356f681SHui Xie std::expected<BothMayThrow, TracedNoexcept> e1(std::unexpect, oldState, 5); 254e356f681SHui Xie const int i = 10; 255e356f681SHui Xie decltype(auto) x = (e1 = i); 256e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<BothMayThrow, TracedNoexcept>&>); 257e356f681SHui Xie assert(&x == &e1); 258e356f681SHui Xie 259e356f681SHui Xie assert(e1.has_value()); 260e356f681SHui Xie assert(e1.value().data_ == 10); 261e356f681SHui Xie 262e356f681SHui Xie assert(!oldState.copyCtorCalled); 263e356f681SHui Xie assert(oldState.moveCtorCalled); 264e356f681SHui Xie assert(oldState.dtorCalled); 265e356f681SHui Xie assert(e1.value().copiedFromInt); 266e356f681SHui Xie } 267e356f681SHui Xie 268e356f681SHui Xie // Otherwise, equivalent to: 269e356f681SHui Xie // reinit-expected(val, unex, std::forward<U>(v)); 270e356f681SHui Xie // !is_nothrow_constructible_v<T, U> && !is_nothrow_move_constructible_v<T> && 271e356f681SHui Xie // is_nothrow_move_constructible_v<E> 272e356f681SHui Xie // move 273e356f681SHui Xie // 274e356f681SHui Xie // In this case, it should call the branch 275e356f681SHui Xie // U tmp(std::move(oldval)); 276e356f681SHui Xie // destroy_at(addressof(oldval)); 277e356f681SHui Xie // try { 278e356f681SHui Xie // construct_at(addressof(newval), std::forward<Args>(args)...); 279e356f681SHui Xie // } catch (...) { 280e356f681SHui Xie // construct_at(addressof(oldval), std::move(tmp)); 281e356f681SHui Xie // throw; 282e356f681SHui Xie // } 283e356f681SHui Xie { 284e356f681SHui Xie TracedNoexcept::state oldState{}; 285e356f681SHui Xie std::expected<BothMayThrow, TracedNoexcept> e1(std::unexpect, oldState, 5); 286e356f681SHui Xie decltype(auto) x = (e1 = 10); 287e356f681SHui Xie static_assert(std::same_as<decltype(x), std::expected<BothMayThrow, TracedNoexcept>&>); 288e356f681SHui Xie assert(&x == &e1); 289e356f681SHui Xie 290e356f681SHui Xie assert(e1.has_value()); 291e356f681SHui Xie assert(e1.value().data_ == 10); 292e356f681SHui Xie 293e356f681SHui Xie assert(!oldState.copyCtorCalled); 294e356f681SHui Xie assert(oldState.moveCtorCalled); 295e356f681SHui Xie assert(oldState.dtorCalled); 296e356f681SHui Xie assert(e1.value().movedFromInt); 297e356f681SHui Xie } 298e356f681SHui Xie 299e356f681SHui Xie // Test default template argument. 300e356f681SHui Xie // Without it, the template parameter cannot be deduced from an initializer list 301e356f681SHui Xie { 302e356f681SHui Xie struct Bar { 303e356f681SHui Xie int i; 304e356f681SHui Xie int j; 305e356f681SHui Xie constexpr Bar(int ii, int jj) : i(ii), j(jj) {} 306e356f681SHui Xie }; 307e356f681SHui Xie 308e356f681SHui Xie std::expected<Bar, int> e({5, 6}); 309e356f681SHui Xie e = {7, 8}; 310e356f681SHui Xie assert(e.value().i == 7); 311e356f681SHui Xie assert(e.value().j == 8); 312e356f681SHui Xie } 313e356f681SHui Xie 3144f469053SJan Kokemüller // CheckForInvalidWrites 3154f469053SJan Kokemüller { 3164f469053SJan Kokemüller { 3174f469053SJan Kokemüller CheckForInvalidWrites<true> e1(std::unexpect); 3184f469053SJan Kokemüller e1 = 42; 3194f469053SJan Kokemüller assert(e1.check()); 3204f469053SJan Kokemüller } 3214f469053SJan Kokemüller { 3224f469053SJan Kokemüller CheckForInvalidWrites<false> e1(std::unexpect); 3234f469053SJan Kokemüller e1 = true; 3244f469053SJan Kokemüller assert(e1.check()); 3254f469053SJan Kokemüller } 3264f469053SJan Kokemüller } 3274f469053SJan Kokemüller 328e356f681SHui Xie return true; 329e356f681SHui Xie } 330e356f681SHui Xie 331e356f681SHui Xie void testException() { 332e356f681SHui Xie #ifndef TEST_HAS_NO_EXCEPTIONS 333e356f681SHui Xie std::expected<ThrowOnConvert, int> e1(std::unexpect, 5); 334e356f681SHui Xie try { 335e356f681SHui Xie e1 = 10; 336e356f681SHui Xie assert(false); 337e356f681SHui Xie } catch (Except) { 338e356f681SHui Xie assert(!e1.has_value()); 339e356f681SHui Xie assert(e1.error() == 5); 340e356f681SHui Xie } 341e356f681SHui Xie 342e356f681SHui Xie #endif // TEST_HAS_NO_EXCEPTIONS 343e356f681SHui Xie } 344e356f681SHui Xie 345e356f681SHui Xie int main(int, char**) { 346e356f681SHui Xie test(); 347e356f681SHui Xie static_assert(test()); 348e356f681SHui Xie testException(); 349e356f681SHui Xie return 0; 350e356f681SHui Xie } 351