diff --git a/libcxx/include/__config b/libcxx/include/__config index 11e13e0c24986..a8720cd76ca03 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -180,6 +180,9 @@ // requires code not to make these assumptions. # define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY # define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW +// Allows std::pair's copy assignment and move assignment operators to be trivial +// when both its element types' respective assignment operators are trivial. +# define _LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE # elif _LIBCPP_ABI_VERSION == 1 # if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF)) // Enable compiling copies of now inline methods into the dylib to support diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index b488a9829c384..fb38f29e9078c 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -11,6 +11,7 @@ #include <__compare/common_comparison_category.h> #include <__compare/synth_three_way.h> +#include <__concepts/assignable.h> #include <__concepts/different_from.h> #include <__config> #include <__fwd/array.h> @@ -26,6 +27,7 @@ #include <__type_traits/common_type.h> #include <__type_traits/conditional.h> #include <__type_traits/decay.h> +#include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_assignable.h> #include <__type_traits/is_constructible.h> @@ -40,8 +42,11 @@ #include <__type_traits/is_nothrow_copy_constructible.h> #include <__type_traits/is_nothrow_default_constructible.h> #include <__type_traits/is_nothrow_move_assignable.h> +#include <__type_traits/is_object.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_move_assignable.h> #include <__type_traits/nat.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/unwrap_ref.h> @@ -67,6 +72,14 @@ struct __non_trivially_copyable_base { __non_trivially_copyable_base(__non_trivially_copyable_base const&) _NOEXCEPT {} }; +#if _LIBCPP_STD_VER >= 20 +template +concept __trivially_copy_assignable_object = is_trivially_copy_assignable_v<_Tp> && is_object_v<_Tp>; + +template +concept __trivially_move_assignable_object = is_trivially_move_assignable_v<_Tp> && is_object_v<_Tp>; +#endif + #if _LIBCPP_STD_VER >= 23 template struct __is_specialization_of_subrange : false_type {}; @@ -236,6 +249,28 @@ struct _LIBCPP_TEMPLATE_VIS pair typename __make_tuple_indices::type(), typename __make_tuple_indices::type()) {} +# if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE) + _LIBCPP_HIDE_FROM_ABI pair& operator=(pair const& __p) = default; + _LIBCPP_HIDE_FROM_ABI pair& operator=(pair&& __p) = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(pair const& __p) + _NOEXCEPT_(is_nothrow_copy_assignable::value&& is_nothrow_copy_assignable::value) + requires is_copy_assignable_v && is_copy_assignable_v && (!(__trivially_copy_assignable_object && __trivially_copy_assignable_object)) + { + first = __p.first; + second = __p.second; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(pair&& __p) + _NOEXCEPT_(is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value) + requires is_move_assignable_v && is_move_assignable_v && (!(__trivially_move_assignable_object && __trivially_move_assignable_object)) + { + first = std::forward(__p.first); + second = std::forward(__p.second); + return *this; + } +# else _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(__conditional_t< is_copy_assignable::value && is_copy_assignable::value, pair, @@ -254,6 +289,7 @@ struct _LIBCPP_TEMPLATE_VIS pair second = std::forward(__p.second); return *this; } +# endif template < class _U1, diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp index 253bd1b85d03e..f45903f2a263a 100644 --- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp @@ -88,6 +88,16 @@ TEST_CONSTEXPR_CXX20 bool test() { assert(&p.second == &inc_obj); } +#if TEST_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE) + static_assert(std::is_trivially_copy_assignable>::value, ""); +#else + static_assert(!std::is_trivially_copy_assignable>::value, ""); +#endif + + static_assert(!std::is_trivially_copy_assignable>::value, ""); + static_assert(!std::is_trivially_copy_assignable>::value, ""); + static_assert(!std::is_trivially_copy_assignable>::value, ""); + return true; } diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp index 2444131b02a0c..76982c41629ee 100644 --- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp @@ -62,7 +62,9 @@ int main(int, char**) assert(p.second == 'x'); } - return 0; + static_assert(!std::is_trivially_copy_assignable >::value, ""); + + return 0; } struct Incomplete {}; diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp index 8e5d9c39ae886..a4c178db25492 100644 --- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp @@ -130,6 +130,17 @@ TEST_CONSTEXPR_CXX20 bool test() { static_assert(!std::is_move_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); } + +#if TEST_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE) + static_assert(std::is_trivially_move_assignable>::value, ""); +#else + static_assert(!std::is_trivially_move_assignable>::value, ""); +#endif + + static_assert(!std::is_trivially_move_assignable>::value, ""); + static_assert(!std::is_trivially_move_assignable>::value, ""); + static_assert(!std::is_trivially_move_assignable>::value, ""); + return true; } diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp new file mode 100644 index 0000000000000..ecea98b4f9dc3 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++17 + +// + +// template struct pair + +// Checks that `std::pair` is actually trivially copyable. + +#include +#include + +#if defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE) +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); + +static_assert(!std::is_trivially_copyable_v>); +static_assert(!std::is_trivially_copyable_v>); +static_assert(!std::is_trivially_copyable_v>); + +enum E {}; +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); + +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); + +struct S {}; +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); +static_assert(std::is_trivially_copyable_v>); +#endif