From b06140e896cc1dac9ecd8226a9600956460bcd63 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/__utility/pair.h | 40 ++++++++++++++++--- .../trivially_copyable.compile.pass.cpp | 32 +++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index e05250ba05717f..5b3dec6e4d7e25 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -141,6 +141,31 @@ struct _LIBCPP_TEMPLATE_VIS pair _NOEXCEPT_(is_nothrow_copy_constructible::value&& is_nothrow_copy_constructible::value) : first(__t1), second(__t2) {} + // 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 + 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__) + 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__) + template < # if _LIBCPP_STD_VER >= 23 // http://wg21.link/P1951 class _U1 = _T1, @@ -221,18 +246,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); 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..2f4a77c3112200 --- /dev/null +++ b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: c++20 || clang + +#include +#include + +struct trivially_copyable { + int arr[4]; +}; + +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_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);