[libc++] Make std::pair trivially copyable if its members are (#89652)
This makes `std::pair` trivially copyable if its members are and we have a way to do so. We need either C++20 with requires clauses or support for `__attribute__((enable_if))`. Only Clang has support for this attribute, so it's effectively clang or C++20. Co-authored-by: Christopher Di Bella <cjdb@google.com>
This commit is contained in:
parent
d1578848e9
commit
f9dd885cb6
@ -98,6 +98,10 @@
|
||||
// and WCHAR_MAX. This ABI setting determines whether we should instead track whether the fill
|
||||
// value has been initialized using a separate boolean, which changes the ABI.
|
||||
# define _LIBCPP_ABI_IOS_ALLOW_ARBITRARY_FILL_VALUE
|
||||
// Make a std::pair of trivially copyable types trivially copyable.
|
||||
// While this technically doesn't change the layout of pair itself, other types may decide to programatically change
|
||||
// their representation based on whether something is 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
|
||||
|
@ -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 <class _Tp>
|
||||
inline const size_t __datasizeof_v = offsetof(_FirstPaddingByte<_Tp>, __first_padding_byte_);
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
|
@ -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/is_trivially_relocatable.h>
|
||||
@ -80,6 +81,38 @@ struct _LIBCPP_TEMPLATE_VIS pair
|
||||
_LIBCPP_HIDE_FROM_ABI pair(pair const&) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI pair(pair&&) = default;
|
||||
|
||||
// When we are requested for pair to be trivially copyable by the ABI macro, we use defaulted members
|
||||
// if it is both legal to do it (i.e. no references) and we have a way to actually implement it, which requires
|
||||
// the __enable_if__ attribute before C++20.
|
||||
#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
|
||||
// FIXME: This should really just be a static constexpr variable. It's in a struct to avoid gdb printing the value
|
||||
// when printing a pair
|
||||
struct __has_defaulted_members {
|
||||
static const bool value = !is_reference<first_type>::value && !is_reference<second_type>::value;
|
||||
};
|
||||
# if _LIBCPP_STD_VER >= 20
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(const pair&)
|
||||
requires __has_defaulted_members::value
|
||||
= default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(pair&&)
|
||||
requires __has_defaulted_members::value
|
||||
= default;
|
||||
# elif __has_attribute(__enable_if__)
|
||||
_LIBCPP_HIDE_FROM_ABI pair& operator=(const pair&)
|
||||
__attribute__((__enable_if__(__has_defaulted_members::value, ""))) = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI pair& operator=(pair&&)
|
||||
__attribute__((__enable_if__(__has_defaulted_members::value, ""))) = default;
|
||||
# else
|
||||
# error "_LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR isn't supported with this compiler"
|
||||
# endif
|
||||
#else
|
||||
struct __has_defaulted_members {
|
||||
static const bool value = false;
|
||||
};
|
||||
#endif // defined(_LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR) && __has_attribute(__enable_if__)
|
||||
|
||||
#ifdef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI pair() : first(), second() {}
|
||||
|
||||
@ -225,7 +258,8 @@ struct _LIBCPP_TEMPLATE_VIS pair
|
||||
typename __make_tuple_indices<sizeof...(_Args2) >::type()) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
|
||||
operator=(__conditional_t<is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
|
||||
operator=(__conditional_t<!__has_defaulted_members::value && is_copy_assignable<first_type>::value &&
|
||||
is_copy_assignable<second_type>::value,
|
||||
pair,
|
||||
__nat> const& __p) noexcept(is_nothrow_copy_assignable<first_type>::value &&
|
||||
is_nothrow_copy_assignable<second_type>::value) {
|
||||
@ -234,10 +268,12 @@ struct _LIBCPP_TEMPLATE_VIS pair
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(
|
||||
__conditional_t<is_move_assignable<first_type>::value && is_move_assignable<second_type>::value, pair, __nat>&&
|
||||
__p) noexcept(is_nothrow_move_assignable<first_type>::value &&
|
||||
is_nothrow_move_assignable<second_type>::value) {
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
|
||||
operator=(__conditional_t<!__has_defaulted_members::value && is_move_assignable<first_type>::value &&
|
||||
is_move_assignable<second_type>::value,
|
||||
pair,
|
||||
__nat>&& __p) noexcept(is_nothrow_move_assignable<first_type>::value &&
|
||||
is_nothrow_move_assignable<second_type>::value) {
|
||||
first = std::forward<first_type>(__p.first);
|
||||
second = std::forward<second_type>(__p.second);
|
||||
return *this;
|
||||
|
@ -162,8 +162,13 @@ void test_trivial()
|
||||
static_assert(!std::is_trivially_copy_constructible<P>::value, "");
|
||||
static_assert(!std::is_trivially_move_constructible<P>::value, "");
|
||||
#endif // TEST_STD_VER >= 11
|
||||
#ifndef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
|
||||
static_assert(!std::is_trivially_copy_assignable<P>::value, "");
|
||||
static_assert(!std::is_trivially_move_assignable<P>::value, "");
|
||||
#else
|
||||
static_assert(std::is_trivially_copy_assignable<P>::value, "");
|
||||
static_assert(std::is_trivially_move_assignable<P>::value, "");
|
||||
#endif
|
||||
static_assert(std::is_trivially_destructible<P>::value, "");
|
||||
}
|
||||
}
|
||||
|
@ -47,11 +47,20 @@ static_assert(!std::is_trivially_copyable<std::pair<int&, int> >::value, "");
|
||||
static_assert(!std::is_trivially_copyable<std::pair<int, int&> >::value, "");
|
||||
static_assert(!std::is_trivially_copyable<std::pair<int&, int&> >::value, "");
|
||||
|
||||
#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
|
||||
static_assert(std::is_trivially_copyable<std::pair<int, int> >::value, "");
|
||||
static_assert(std::is_trivially_copyable<std::pair<int, char> >::value, "");
|
||||
static_assert(std::is_trivially_copyable<std::pair<char, int> >::value, "");
|
||||
static_assert(std::is_trivially_copyable<std::pair<std::pair<char, char>, int> >::value, "");
|
||||
static_assert(std::is_trivially_copyable<std::pair<trivially_copyable, int> >::value, "");
|
||||
#else
|
||||
static_assert(!std::is_trivially_copyable<std::pair<int, int> >::value, "");
|
||||
static_assert(!std::is_trivially_copyable<std::pair<int, char> >::value, "");
|
||||
static_assert(!std::is_trivially_copyable<std::pair<char, int> >::value, "");
|
||||
static_assert(!std::is_trivially_copyable<std::pair<std::pair<char, char>, int> >::value, "");
|
||||
static_assert(!std::is_trivially_copyable<std::pair<trivially_copyable, int> >::value, "");
|
||||
#endif // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
|
||||
|
||||
#if TEST_STD_VER == 03 // Known ABI difference
|
||||
static_assert(!std::is_trivially_copyable<std::pair<trivially_copyable_no_copy_assignment, int> >::value, "");
|
||||
static_assert(!std::is_trivially_copyable<std::pair<trivially_copyable_no_move_assignment, int> >::value, "");
|
||||
@ -59,10 +68,21 @@ static_assert(!std::is_trivially_copyable<std::pair<trivially_copyable_no_move_a
|
||||
static_assert(std::is_trivially_copyable<std::pair<trivially_copyable_no_copy_assignment, int> >::value, "");
|
||||
static_assert(std::is_trivially_copyable<std::pair<trivially_copyable_no_move_assignment, int> >::value, "");
|
||||
#endif
|
||||
|
||||
#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
|
||||
static_assert(std::is_trivially_copyable<std::pair<trivially_copyable_no_construction, int> >::value, "");
|
||||
#else
|
||||
static_assert(!std::is_trivially_copyable<std::pair<trivially_copyable_no_construction, int> >::value, "");
|
||||
#endif
|
||||
|
||||
static_assert(std::is_trivially_copy_constructible<std::pair<int, int> >::value, "");
|
||||
static_assert(std::is_trivially_move_constructible<std::pair<int, int> >::value, "");
|
||||
static_assert(std::is_trivially_destructible<std::pair<int, int> >::value, "");
|
||||
|
||||
#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
|
||||
static_assert(std::is_trivially_copy_assignable<std::pair<int, int> >::value, "");
|
||||
static_assert(std::is_trivially_move_assignable<std::pair<int, int> >::value, "");
|
||||
#else
|
||||
static_assert(!std::is_trivially_copy_assignable<std::pair<int, int> >::value, "");
|
||||
static_assert(!std::is_trivially_move_assignable<std::pair<int, int> >::value, "");
|
||||
static_assert(std::is_trivially_destructible<std::pair<int, int> >::value, "");
|
||||
#endif // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
|
||||
|
Loading…
x
Reference in New Issue
Block a user