Skip to content

Commit 6347173

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

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed

libcxx/include/__type_traits/datasizeof.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct __libcpp_datasizeof {
5555
// the use as an extension.
5656
_LIBCPP_DIAGNOSTIC_PUSH
5757
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
58+
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
5859
static const size_t value = offsetof(_FirstPaddingByte<>, __first_padding_byte_);
5960
_LIBCPP_DIAGNOSTIC_POP
6061
#endif // __has_extension(datasizeof)

libcxx/include/__utility/pair.h

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <__type_traits/is_implicitly_default_constructible.h>
3333
#include <__type_traits/is_nothrow_assignable.h>
3434
#include <__type_traits/is_nothrow_constructible.h>
35+
#include <__type_traits/is_reference.h>
3536
#include <__type_traits/is_same.h>
3637
#include <__type_traits/is_swappable.h>
3738
#include <__type_traits/nat.h>
@@ -141,6 +142,31 @@ struct _LIBCPP_TEMPLATE_VIS pair
141142
_NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value&& is_nothrow_copy_constructible<second_type>::value)
142143
: first(__t1), second(__t2) {}
143144

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

223249
_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)
250+
operator=(__conditional_t<
251+
!__has_defaulted_members && is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
252+
pair,
253+
__nat> const& __p)
227254
_NOEXCEPT_(is_nothrow_copy_assignable<first_type>::value&& is_nothrow_copy_assignable<second_type>::value) {
228255
first = __p.first;
229256
second = __p.second;
230257
return *this;
231258
}
232259

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)
260+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
261+
operator=(__conditional_t<
262+
!__has_defaulted_members && is_move_assignable<first_type>::value && is_move_assignable<second_type>::value,
263+
pair,
264+
__nat>&& __p)
236265
_NOEXCEPT_(is_nothrow_move_assignable<first_type>::value&& is_nothrow_move_assignable<second_type>::value) {
237266
first = std::forward<first_type>(__p.first);
238267
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+
// UNSUPPORTED: c++03 || !clang && (c++11 || c++14 || c++17)
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)