//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 // // optional& operator=(optional&& rhs) // noexcept(is_nothrow_move_assignable::value && // is_nothrow_move_constructible::value); // constexpr in C++20 #include #include #include #include #include "test_macros.h" #include "archetypes.h" using std::optional; struct X { static bool throw_now; static int alive; X() { ++alive; } X(X&&) { if (throw_now) TEST_THROW(6); ++alive; } X& operator=(X&&) { if (throw_now) TEST_THROW(42); return *this; } ~X() { assert(alive > 0); --alive; } }; struct Y {}; bool X::throw_now = false; int X::alive = 0; template constexpr bool assign_empty(optional&& lhs) { optional rhs; lhs = std::move(rhs); return !lhs.has_value() && !rhs.has_value(); } template constexpr bool assign_value(optional&& lhs) { optional rhs(101); lhs = std::move(rhs); return lhs.has_value() && rhs.has_value() && *lhs == Tp{101}; } int main(int, char**) { { static_assert(std::is_nothrow_move_assignable>::value, ""); optional opt; constexpr optional opt2; opt = std::move(opt2); static_assert(static_cast(opt2) == false, ""); assert(static_cast(opt) == static_cast(opt2)); } { optional opt; constexpr optional opt2(2); opt = std::move(opt2); static_assert(static_cast(opt2) == true, ""); static_assert(*opt2 == 2, ""); assert(static_cast(opt) == static_cast(opt2)); assert(*opt == *opt2); } { optional opt(3); constexpr optional opt2; opt = std::move(opt2); static_assert(static_cast(opt2) == false, ""); assert(static_cast(opt) == static_cast(opt2)); } { using T = TestTypes::TestType; T::reset(); optional opt(3); optional opt2; assert(T::alive == 1); opt = std::move(opt2); assert(T::alive == 0); assert(static_cast(opt2) == false); assert(static_cast(opt) == static_cast(opt2)); } { optional opt(3); constexpr optional opt2(2); opt = std::move(opt2); static_assert(static_cast(opt2) == true, ""); static_assert(*opt2 == 2, ""); assert(static_cast(opt) == static_cast(opt2)); assert(*opt == *opt2); } { using O = optional; #if TEST_STD_VER > 17 LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); #endif assert(assign_empty(O{42})); assert(assign_value(O{42})); } { using O = optional; #if TEST_STD_VER > 17 LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); #endif assert(assign_empty(O{42})); assert(assign_value(O{42})); } #ifndef TEST_HAS_NO_EXCEPTIONS { static_assert(!std::is_nothrow_move_assignable>::value, ""); X::alive = 0; X::throw_now = false; optional opt; optional opt2(X{}); assert(X::alive == 1); assert(static_cast(opt2) == true); try { X::throw_now = true; opt = std::move(opt2); assert(false); } catch (int i) { assert(i == 6); assert(static_cast(opt) == false); } assert(X::alive == 1); } assert(X::alive == 0); { static_assert(!std::is_nothrow_move_assignable>::value, ""); X::throw_now = false; optional opt(X{}); optional opt2(X{}); assert(X::alive == 2); assert(static_cast(opt2) == true); try { X::throw_now = true; opt = std::move(opt2); assert(false); } catch (int i) { assert(i == 42); assert(static_cast(opt) == true); } assert(X::alive == 2); } assert(X::alive == 0); #endif // TEST_HAS_NO_EXCEPTIONS { static_assert(std::is_nothrow_move_assignable>::value, ""); } { struct ThrowsMove { ThrowsMove() noexcept {} ThrowsMove(ThrowsMove const&) noexcept {} ThrowsMove(ThrowsMove &&) noexcept(false) {} ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; } ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; } }; static_assert(!std::is_nothrow_move_assignable>::value, ""); struct ThrowsMoveAssign { ThrowsMoveAssign() noexcept {} ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {} ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {} ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; } ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; } }; static_assert(!std::is_nothrow_move_assignable>::value, ""); struct NoThrowMove { NoThrowMove() noexcept(false) {} NoThrowMove(NoThrowMove const&) noexcept(false) {} NoThrowMove(NoThrowMove &&) noexcept {} NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; } NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; } }; static_assert(std::is_nothrow_move_assignable>::value, ""); } return 0; }