From 9a4773d6daeef793c0d90a3625b4f5e4fd810ae8 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Mon, 22 Apr 2024 20:58:34 +0200 Subject: [PATCH] [libc++][ABI BREAK] Make std::pair trivially copyable if its members are --- libcxx/include/__config | 2 + libcxx/include/__type_traits/datasizeof.h | 1 + libcxx/include/__utility/pair.h | 78 +++++++++++------ .../trivially_copyable.compile.pass.cpp | 85 +++++++++++++++++++ 4 files changed, 142 insertions(+), 24 deletions(-) create mode 100644 libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp diff --git a/libcxx/include/__config b/libcxx/include/__config index 97cdd020c55d1f..1db8a298175ea7 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -166,6 +166,8 @@ // 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 +// Make a std::pair of trivially copyable types trivially copyable +# define _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR # 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/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h index 54fde242ebcde1..ccb57a46f0fb52 100644 --- a/libcxx/include/__type_traits/datasizeof.h +++ b/libcxx/include/__type_traits/datasizeof.h @@ -54,6 +54,7 @@ struct _FirstPaddingByte<_Tp, true> { // the use as an extension. _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof") +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof") template inline const size_t __datasizeof_v = offsetof(_FirstPaddingByte<_Tp>, __first_padding_byte_); _LIBCPP_DIAGNOSTIC_POP diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index e05250ba05717f..ae08aaf75cc64f 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -32,6 +32,7 @@ #include <__type_traits/is_implicitly_default_constructible.h> #include <__type_traits/is_nothrow_assignable.h> #include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_reference.h> #include <__type_traits/is_same.h> #include <__type_traits/is_swappable.h> #include <__type_traits/nat.h> @@ -73,6 +74,31 @@ struct _LIBCPP_TEMPLATE_VIS pair _LIBCPP_HIDE_FROM_ABI pair(pair const&) = default; _LIBCPP_HIDE_FROM_ABI pair(pair&&) = default; +#define _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR + // Make pair trivially copyable if we have a way to do it + static const bool __enable_defaulted_assignment_operators = + !is_reference::value && !is_reference::value; +#if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR) + static const bool __has_defaulted_members = __enable_defaulted_assignment_operators; + + _LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(const pair&) + requires __enable_defaulted_assignment_operators + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(pair&&) + requires __enable_defaulted_assignment_operators + = default; +#elif __has_attribute(__enable_if__) && defined(_LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR) + static const bool __has_defaulted_members = __enable_defaulted_assignment_operators; + + _LIBCPP_HIDE_FROM_ABI pair& operator=(const pair&) + __attribute__((__enable_if__(__enable_defaulted_assignment_operators, ""))) = default; + + _LIBCPP_HIDE_FROM_ABI pair& operator=(pair&&) + __attribute__((__enable_if__(__enable_defaulted_assignment_operators, ""))) = default; +#else + static const bool __has_defaulted_members = false; +#endif // __has_attribute(__enable_if__) && defined(_LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR) #ifdef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI pair() : first(), second() {} @@ -129,9 +155,9 @@ struct _LIBCPP_TEMPLATE_VIS pair typename conditional< _MaybeEnable, _CheckArgs, __check_tuple_constructor_fail>::type; template ::__enable_default(), int> = 0> - explicit(!_CheckArgsDep<_Dummy>::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair() - _NOEXCEPT_( - is_nothrow_default_constructible::value&& is_nothrow_default_constructible::value) + explicit(!_CheckArgsDep<_Dummy>::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR pair() _NOEXCEPT_( + is_nothrow_default_constructible::value&& is_nothrow_default_constructible::value) : first(), second() {} template (), int> = 0 > - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) - pair(_U1&& __u1, _U2&& __u2) - _NOEXCEPT_((is_nothrow_constructible::value && - is_nothrow_constructible::value)) + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) pair(_U1&& __u1, _U2&& __u2) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) : first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) { } @@ -168,17 +194,18 @@ struct _LIBCPP_TEMPLATE_VIS pair template (), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit( - !_CheckArgs::template __is_implicit<_U1 const&, _U2 const&>()) pair(pair<_U1, _U2> const& __p) - _NOEXCEPT_((is_nothrow_constructible::value && - is_nothrow_constructible::value)) + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1 const&, _U2 const&>()) + pair(pair<_U1, _U2> const& __p) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) : first(__p.first), second(__p.second) {} template (), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) - pair(pair<_U1, _U2>&& __p) - _NOEXCEPT_((is_nothrow_constructible::value && - is_nothrow_constructible::value)) + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) pair(pair<_U1, _U2>&& __p) + _NOEXCEPT_((is_nothrow_constructible::value && + is_nothrow_constructible::value)) : first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {} # if _LIBCPP_STD_VER >= 23 @@ -221,18 +248,21 @@ struct _LIBCPP_TEMPLATE_VIS pair typename __make_tuple_indices::type()) {} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& - operator=(__conditional_t< is_copy_assignable::value && is_copy_assignable::value, - pair, - __nat> const& __p) + operator=(__conditional_t< + !__has_defaulted_members && is_copy_assignable::value && is_copy_assignable::value, + pair, + __nat> const& __p) _NOEXCEPT_(is_nothrow_copy_assignable::value&& is_nothrow_copy_assignable::value) { first = __p.first; second = __p.second; return *this; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=( - __conditional_t< is_move_assignable::value && is_move_assignable::value, pair, __nat>&& - __p) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& + operator=(__conditional_t< + !__has_defaulted_members && is_move_assignable::value && is_move_assignable::value, + pair, + __nat>&& __p) _NOEXCEPT_(is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value) { first = std::forward(__p.first); second = std::forward(__p.second); @@ -528,9 +558,9 @@ swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) noexcept(noexcept(__x #endif template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 - pair::type, typename __unwrap_ref_decay<_T2>::type> - make_pair(_T1&& __t1, _T2&& __t2) { +inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 pair::type, typename __unwrap_ref_decay<_T2>::type> +make_pair(_T1&& __t1, _T2&& __t2) { return pair::type, typename __unwrap_ref_decay<_T2>::type>( std::forward<_T1>(__t1), std::forward<_T2>(__t2)); } diff --git a/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp new file mode 100644 index 00000000000000..fd9f3746d95e48 --- /dev/null +++ b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc && (c++11 || c++14 || c++17) + +#include +#include + +struct trivially_copyable { + int arr[4]; +}; + +struct trivially_copyable_no_assignment { + int arr[4]; + trivially_copyable_no_assignment& operator=(const trivially_copyable_no_assignment&) = delete; +}; +static_assert(std::is_trivially_copyable::value, ""); + +static_assert(std::is_trivially_copy_constructible >::value, ""); +static_assert(std::is_trivially_move_constructible >::value, ""); +static_assert(!std::is_trivially_copy_assignable >::value, ""); +static_assert(!std::is_trivially_move_assignable >::value, ""); +static_assert(std::is_trivially_destructible >::value, ""); + +struct trivially_copyable_no_construction { + int arr[4]; + trivially_copyable_no_construction() = default; + trivially_copyable_no_construction(const trivially_copyable_no_construction&) = delete; + trivially_copyable_no_construction& operator=(const trivially_copyable_no_construction&) = default; +}; +static_assert(std::is_trivially_copyable::value, ""); + +#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR +static_assert(!std::is_trivially_copy_constructible >::value, ""); +static_assert(!std::is_trivially_move_constructible >::value, ""); +static_assert(std::is_trivially_copy_assignable >::value, ""); +static_assert(std::is_trivially_move_assignable >::value, ""); +static_assert(std::is_trivially_destructible >::value, ""); +#else // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR +static_assert(!std::is_trivially_copy_constructible >::value, ""); +static_assert(!std::is_trivially_move_constructible >::value, ""); +static_assert(!std::is_trivially_copy_assignable >::value, ""); +static_assert(!std::is_trivially_move_assignable >::value, ""); +static_assert(std::is_trivially_destructible >::value, ""); +#endif // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR + +static_assert(!std::is_trivially_copyable >::value, ""); +static_assert(!std::is_trivially_copyable >::value, ""); +static_assert(!std::is_trivially_copyable >::value, ""); + +#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR +static_assert(std::is_trivially_copyable >::value, ""); +static_assert(std::is_trivially_copyable >::value, ""); +static_assert(std::is_trivially_copyable >::value, ""); +static_assert(std::is_trivially_copyable, int> >::value, ""); +static_assert(std::is_trivially_copyable >::value, ""); +static_assert(std::is_trivially_copyable >::value, ""); +static_assert(std::is_trivially_copyable >::value, ""); + +static_assert(std::is_trivially_copy_constructible >::value, ""); +static_assert(std::is_trivially_move_constructible >::value, ""); +static_assert(std::is_trivially_copy_assignable >::value, ""); +static_assert(std::is_trivially_move_assignable >::value, ""); +static_assert(std::is_trivially_destructible >::value, ""); + +#else // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR +static_assert(!std::is_trivially_copyable >::value, ""); +static_assert(!std::is_trivially_copyable >::value, ""); +static_assert(!std::is_trivially_copyable >::value, ""); +static_assert(!std::is_trivially_copyable, int> >::value, ""); +static_assert(!std::is_trivially_copyable >::value, ""); +static_assert(!std::is_trivially_copyable >::value, ""); +static_assert(!std::is_trivially_copyable >::value, ""); + +static_assert(std::is_trivially_copy_constructible >::value, ""); +static_assert(std::is_trivially_move_constructible >::value, ""); +static_assert(!std::is_trivially_copy_assignable >::value, ""); +static_assert(!std::is_trivially_move_assignable >::value, ""); +static_assert(std::is_trivially_destructible >::value, ""); +#endif // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR