Skip to content

Commit b06140e

Browse files
committed
[libc++][ABI BREAK] Make std::pair trivially copyable if its members are
1 parent c8e5ad4 commit b06140e

File tree

2 files changed

+66
-6
lines changed

2 files changed

+66
-6
lines changed

libcxx/include/__utility/pair.h

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,31 @@ struct _LIBCPP_TEMPLATE_VIS pair
141141
_NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value&& is_nothrow_copy_constructible<second_type>::value)
142142
: first(__t1), second(__t2) {}
143143

144+
// Make pair trivially copyable if we have a way to do it
145+
static const bool __enable_defaulted_assignment_operators =
146+
!is_reference<first_type>::value && !is_reference<second_type>::value;
147+
# if _LIBCPP_STD_VER >= 20
148+
static const bool __has_defaulted_members = __enable_defaulted_assignment_operators;
149+
150+
_LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(const pair&)
151+
requires __enable_defaulted_assignment_operators
152+
= default;
153+
154+
_LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(pair&&)
155+
requires __enable_defaulted_assignment_operators
156+
= default;
157+
# elif __has_attribute(__enable_if__)
158+
static const bool __has_defaulted_members = __enable_defaulted_assignment_operators;
159+
160+
_LIBCPP_HIDE_FROM_ABI pair& operator=(const pair&)
161+
__attribute__((__enable_if__(__enable_defaulted_assignment_operators, ""))) = default;
162+
163+
_LIBCPP_HIDE_FROM_ABI pair& operator=(pair&&)
164+
__attribute__((__enable_if__(__enable_defaulted_assignment_operators, ""))) = default;
165+
# else
166+
static const bool __has_defaulted_members = false;
167+
# endif // __has_attribute(__enable_if__)
168+
144169
template <
145170
# if _LIBCPP_STD_VER >= 23 // http://wg21.link/P1951
146171
class _U1 = _T1,
@@ -221,18 +246,21 @@ struct _LIBCPP_TEMPLATE_VIS pair
221246
typename __make_tuple_indices<sizeof...(_Args2) >::type()) {}
222247

223248
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
224-
operator=(__conditional_t< is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
225-
pair,
226-
__nat> const& __p)
249+
operator=(__conditional_t<
250+
!__has_defaulted_members && is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
251+
pair,
252+
__nat> const& __p)
227253
_NOEXCEPT_(is_nothrow_copy_assignable<first_type>::value&& is_nothrow_copy_assignable<second_type>::value) {
228254
first = __p.first;
229255
second = __p.second;
230256
return *this;
231257
}
232258

233-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(
234-
__conditional_t< is_move_assignable<first_type>::value && is_move_assignable<second_type>::value, pair, __nat>&&
235-
__p)
259+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
260+
operator=(__conditional_t<
261+
!__has_defaulted_members && is_move_assignable<first_type>::value && is_move_assignable<second_type>::value,
262+
pair,
263+
__nat>&& __p)
236264
_NOEXCEPT_(is_nothrow_move_assignable<first_type>::value&& is_nothrow_move_assignable<second_type>::value) {
237265
first = std::forward<first_type>(__p.first);
238266
second = std::forward<second_type>(__p.second);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: c++20 || clang
10+
11+
#include <type_traits>
12+
#include <utility>
13+
14+
struct trivially_copyable {
15+
int arr[4];
16+
};
17+
18+
static_assert(std::is_trivially_copyable<std::pair<int, int>>::value, "");
19+
static_assert(std::is_trivially_copyable<std::pair<int, char>>::value, "");
20+
static_assert(std::is_trivially_copyable<std::pair<char, int>>::value, "");
21+
static_assert(std::is_trivially_copyable<std::pair<std::pair<char, char>, int>>::value, "");
22+
static_assert(std::is_trivially_copyable<std::pair<trivially_copyable, int>>::value, "");
23+
24+
static_assert(!std::is_trivially_copyable<std::pair<int&, int>>::value, "");
25+
static_assert(!std::is_trivially_copyable<std::pair<int, int&>>::value, "");
26+
static_assert(!std::is_trivially_copyable<std::pair<int&, int&>>::value, "");
27+
28+
static_assert(std::is_trivially_copy_constructible<std::pair<int, int>>::value);
29+
static_assert(std::is_trivially_move_constructible<std::pair<int, int>>::value);
30+
static_assert(std::is_trivially_copy_assignable<std::pair<int, int>>::value);
31+
static_assert(std::is_trivially_move_assignable<std::pair<int, int>>::value);
32+
static_assert(std::is_trivially_destructible<std::pair<int, int>>::value);

0 commit comments

Comments
 (0)