diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h index bf16c8f720d26..128369fc1b0a1 100644 --- a/libcxx/include/__expected/expected.h +++ b/libcxx/include/__expected/expected.h @@ -38,8 +38,10 @@ #include <__type_traits/is_reference.h> #include <__type_traits/is_same.h> #include <__type_traits/is_swappable.h> +#include <__type_traits/is_trivially_copy_assignable.h> #include <__type_traits/is_trivially_copy_constructible.h> #include <__type_traits/is_trivially_destructible.h> +#include <__type_traits/is_trivially_move_assignable.h> #include <__type_traits/is_trivially_move_constructible.h> #include <__type_traits/is_void.h> #include <__type_traits/lazy.h> @@ -282,10 +284,27 @@ class expected { } } + static constexpr bool __is_trivially_move_assignable = + is_trivially_move_constructible_v<_Tp> && + is_trivially_move_assignable_v<_Tp> && + is_trivially_move_constructible_v<_Err> && + is_trivially_move_assignable_v<_Err>; + + static constexpr bool __is_trivially_copy_assignable = + __is_trivially_move_assignable && + is_trivially_copy_constructible_v<_Tp> && + is_trivially_copy_assignable_v<_Tp> && + is_trivially_copy_constructible_v<_Err> && + is_trivially_copy_assignable_v<_Err>; + public: // [expected.object.assign], assignment _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) + requires __is_trivially_copy_assignable + = default; + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) noexcept(is_nothrow_copy_assignable_v<_Tp> && is_nothrow_copy_constructible_v<_Tp> && @@ -295,6 +314,7 @@ class expected { is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err> && + !__is_trivially_copy_assignable && (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>)) { @@ -312,6 +332,10 @@ class expected { return *this; } + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs) + requires __is_trivially_move_assignable + = default; + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Tp> && is_nothrow_move_constructible_v<_Tp> && @@ -321,6 +345,7 @@ class expected { is_move_assignable_v<_Tp> && is_move_constructible_v<_Err> && is_move_assignable_v<_Err> && + !__is_trivially_move_assignable && (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>)) { diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp index 03fe888b0a5e7..12ca07a3c1f9a 100644 --- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp @@ -47,6 +47,22 @@ struct NotCopyAssignable { NotCopyAssignable& operator=(const NotCopyAssignable&) = delete; }; +struct NotTriviallyCopyConstructible { + NotTriviallyCopyConstructible(const NotTriviallyCopyConstructible&); + NotTriviallyCopyConstructible(NotTriviallyCopyConstructible&&) = default; + + NotTriviallyCopyConstructible& operator=(const NotTriviallyCopyConstructible&) = default; + NotTriviallyCopyConstructible& operator=(NotTriviallyCopyConstructible&&) = default; +}; + +struct NotTriviallyCopyAssignable { + NotTriviallyCopyAssignable(const NotTriviallyCopyAssignable&) = default; + NotTriviallyCopyAssignable(NotTriviallyCopyAssignable&&) = default; + + NotTriviallyCopyAssignable& operator=(const NotTriviallyCopyAssignable&); + NotTriviallyCopyAssignable& operator=(NotTriviallyCopyAssignable&&) = default; +}; + struct MoveMayThrow { MoveMayThrow(MoveMayThrow const&) = default; MoveMayThrow& operator=(const MoveMayThrow&) = default; @@ -55,7 +71,7 @@ struct MoveMayThrow { }; // Test constraints -static_assert(std::is_copy_assignable_v>); +static_assert(std::is_trivially_copy_assignable_v>); // !is_copy_assignable_v static_assert(!std::is_copy_assignable_v>); @@ -78,6 +94,25 @@ static_assert(std::is_copy_assignable_v>); // !is_nothrow_move_constructible_v && !is_nothrow_move_constructible_v static_assert(!std::is_copy_assignable_v>); +// !is_trivially_copy_constructible +static_assert(std::is_copy_assignable_v>); +static_assert(!std::is_trivially_copy_assignable_v>); +static_assert(!std::is_trivially_copy_assignable_v>); +static_assert( + !std::is_trivially_copy_assignable_v>); + +// !is_trivially_copy_assignable +static_assert(std::is_copy_assignable_v>); +static_assert(!std::is_trivially_copy_assignable_v>); +static_assert(!std::is_trivially_copy_assignable_v>); +static_assert( + !std::is_trivially_copy_assignable_v>); + +static_assert( + !std::is_trivially_copy_assignable_v>); +static_assert( + !std::is_trivially_copy_assignable_v>); + constexpr bool test() { // If this->has_value() && rhs.has_value() is true, equivalent to val = *rhs. { diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp index 8c419afd10729..b08023b9c95ef 100644 --- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp +++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp @@ -50,13 +50,29 @@ struct NotMoveAssignable { NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; }; +struct NotTriviallyMoveConstructible { + NotTriviallyMoveConstructible(const NotTriviallyMoveConstructible&) = default; + NotTriviallyMoveConstructible(NotTriviallyMoveConstructible&&); + + NotTriviallyMoveConstructible& operator=(const NotTriviallyMoveConstructible&) = default; + NotTriviallyMoveConstructible& operator=(NotTriviallyMoveConstructible&&) = default; +}; + +struct NotTriviallyMoveAssignable { + NotTriviallyMoveAssignable(const NotTriviallyMoveAssignable&) = default; + NotTriviallyMoveAssignable(NotTriviallyMoveAssignable&&) = default; + + NotTriviallyMoveAssignable& operator=(const NotTriviallyMoveAssignable&) = default; + NotTriviallyMoveAssignable& operator=(NotTriviallyMoveAssignable&&); +}; + struct MoveCtorMayThrow { MoveCtorMayThrow(MoveCtorMayThrow&&) noexcept(false) {} MoveCtorMayThrow& operator=(MoveCtorMayThrow&&) noexcept = default; }; // Test constraints -static_assert(std::is_move_assignable_v>); +static_assert(std::is_trivially_move_assignable_v>); // !is_move_assignable_v static_assert(!std::is_move_assignable_v>); @@ -99,6 +115,21 @@ static_assert(!std::is_nothrow_move_assignable_v static_assert(!std::is_nothrow_move_assignable_v>); +// !is_trivially_move_constructible +static_assert(std::is_move_assignable_v>); +static_assert(!std::is_trivially_move_assignable_v>); +static_assert(!std::is_trivially_move_assignable_v>); + +// !is_trivially_move_assignable +static_assert(std::is_move_assignable_v>); +static_assert(!std::is_trivially_move_assignable_v>); +static_assert(!std::is_trivially_move_assignable_v>); + +static_assert( + !std::is_trivially_move_assignable_v>); +static_assert( + !std::is_trivially_move_assignable_v>); + constexpr bool test() { // If this->has_value() && rhs.has_value() is true, equivalent to val = std::move(*rhs). {