Skip to content

Commit 2384d39

Browse files
committed
[libc++][ABI BREAK] Make std::pair trivially copyable if its members are
1 parent 66e1d2c commit 2384d39

File tree

4 files changed

+146
-24
lines changed

4 files changed

+146
-24
lines changed

libcxx/include/__config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@
166166
// requires code not to make these assumptions.
167167
# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY
168168
# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW
169+
// Make a std::pair of trivially copyable types trivially copyable
170+
# define _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
169171
# elif _LIBCPP_ABI_VERSION == 1
170172
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
171173
// Enable compiling copies of now inline methods into the dylib to support

libcxx/include/__type_traits/datasizeof.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ struct _FirstPaddingByte<_Tp, true> {
5454
// the use as an extension.
5555
_LIBCPP_DIAGNOSTIC_PUSH
5656
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
57+
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
5758
template <class _Tp>
5859
inline const size_t __datasizeof_v = offsetof(_FirstPaddingByte<_Tp>, __first_padding_byte_);
5960
_LIBCPP_DIAGNOSTIC_POP

libcxx/include/__utility/pair.h

Lines changed: 54 additions & 24 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>
@@ -74,6 +75,31 @@ struct _LIBCPP_TEMPLATE_VIS pair
7475
_LIBCPP_HIDE_FROM_ABI pair(pair const&) = default;
7576
_LIBCPP_HIDE_FROM_ABI pair(pair&&) = default;
7677

78+
// Make pair trivially copyable if we have a way to do it
79+
static const bool __enable_defaulted_assignment_operators =
80+
!is_reference<first_type>::value && !is_reference<second_type>::value;
81+
#if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR)
82+
static const bool __has_defaulted_members = __enable_defaulted_assignment_operators;
83+
84+
_LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(const pair&)
85+
requires __enable_defaulted_assignment_operators
86+
= default;
87+
88+
_LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(pair&&)
89+
requires __enable_defaulted_assignment_operators
90+
= default;
91+
#elif __has_attribute(__enable_if__) && defined(_LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR)
92+
static const bool __has_defaulted_members = __enable_defaulted_assignment_operators;
93+
94+
_LIBCPP_HIDE_FROM_ABI pair& operator=(const pair&)
95+
__attribute__((__enable_if__(__enable_defaulted_assignment_operators, ""))) = default;
96+
97+
_LIBCPP_HIDE_FROM_ABI pair& operator=(pair&&)
98+
__attribute__((__enable_if__(__enable_defaulted_assignment_operators, ""))) = default;
99+
#else
100+
static const bool __has_defaulted_members = false;
101+
#endif // __has_attribute(__enable_if__) && defined(_LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR)
102+
77103
#ifdef _LIBCPP_CXX03_LANG
78104
_LIBCPP_HIDE_FROM_ABI pair() : first(), second() {}
79105

@@ -129,9 +155,9 @@ struct _LIBCPP_TEMPLATE_VIS pair
129155
typename conditional< _MaybeEnable, _CheckArgs, __check_tuple_constructor_fail>::type;
130156

131157
template <bool _Dummy = true, __enable_if_t<_CheckArgsDep<_Dummy>::__enable_default(), int> = 0>
132-
explicit(!_CheckArgsDep<_Dummy>::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair()
133-
_NOEXCEPT_(
134-
is_nothrow_default_constructible<first_type>::value&& is_nothrow_default_constructible<second_type>::value)
158+
explicit(!_CheckArgsDep<_Dummy>::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI
159+
_LIBCPP_CONSTEXPR pair() _NOEXCEPT_(
160+
is_nothrow_default_constructible<first_type>::value&& is_nothrow_default_constructible<second_type>::value)
135161
: first(), second() {}
136162

137163
template <bool _Dummy = true,
@@ -150,10 +176,10 @@ struct _LIBCPP_TEMPLATE_VIS pair
150176
class _U2,
151177
# endif
152178
__enable_if_t<_CheckArgs::template __is_pair_constructible<_U1, _U2>(), int> = 0 >
153-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>())
154-
pair(_U1&& __u1, _U2&& __u2)
155-
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1>::value &&
156-
is_nothrow_constructible<second_type, _U2>::value))
179+
_LIBCPP_HIDE_FROM_ABI
180+
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) pair(_U1&& __u1, _U2&& __u2)
181+
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1>::value &&
182+
is_nothrow_constructible<second_type, _U2>::value))
157183
: first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {
158184
}
159185

@@ -168,17 +194,18 @@ struct _LIBCPP_TEMPLATE_VIS pair
168194
template <class _U1,
169195
class _U2,
170196
__enable_if_t<_CheckArgs::template __is_pair_constructible<_U1 const&, _U2 const&>(), int> = 0>
171-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(
172-
!_CheckArgs::template __is_implicit<_U1 const&, _U2 const&>()) pair(pair<_U1, _U2> const& __p)
173-
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1 const&>::value &&
174-
is_nothrow_constructible<second_type, _U2 const&>::value))
197+
_LIBCPP_HIDE_FROM_ABI
198+
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1 const&, _U2 const&>())
199+
pair(pair<_U1, _U2> const& __p)
200+
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1 const&>::value &&
201+
is_nothrow_constructible<second_type, _U2 const&>::value))
175202
: first(__p.first), second(__p.second) {}
176203

177204
template <class _U1, class _U2, __enable_if_t<_CheckArgs::template __is_pair_constructible<_U1, _U2>(), int> = 0>
178-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>())
179-
pair(pair<_U1, _U2>&& __p)
180-
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1&&>::value &&
181-
is_nothrow_constructible<second_type, _U2&&>::value))
205+
_LIBCPP_HIDE_FROM_ABI
206+
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) pair(pair<_U1, _U2>&& __p)
207+
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1&&>::value &&
208+
is_nothrow_constructible<second_type, _U2&&>::value))
182209
: first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {}
183210

184211
# if _LIBCPP_STD_VER >= 23
@@ -221,18 +248,21 @@ struct _LIBCPP_TEMPLATE_VIS pair
221248
typename __make_tuple_indices<sizeof...(_Args2) >::type()) {}
222249

223250
_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)
251+
operator=(__conditional_t<
252+
!__has_defaulted_members && is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
253+
pair,
254+
__nat> const& __p)
227255
_NOEXCEPT_(is_nothrow_copy_assignable<first_type>::value&& is_nothrow_copy_assignable<second_type>::value) {
228256
first = __p.first;
229257
second = __p.second;
230258
return *this;
231259
}
232260

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)
261+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
262+
operator=(__conditional_t<
263+
!__has_defaulted_members && is_move_assignable<first_type>::value && is_move_assignable<second_type>::value,
264+
pair,
265+
__nat>&& __p)
236266
_NOEXCEPT_(is_nothrow_move_assignable<first_type>::value&& is_nothrow_move_assignable<second_type>::value) {
237267
first = std::forward<first_type>(__p.first);
238268
second = std::forward<second_type>(__p.second);
@@ -528,9 +558,9 @@ swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) noexcept(noexcept(__x
528558
#endif
529559

530560
template <class _T1, class _T2>
531-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
532-
pair<typename __unwrap_ref_decay<_T1>::type, typename __unwrap_ref_decay<_T2>::type>
533-
make_pair(_T1&& __t1, _T2&& __t2) {
561+
inline _LIBCPP_HIDE_FROM_ABI
562+
_LIBCPP_CONSTEXPR_SINCE_CXX14 pair<typename __unwrap_ref_decay<_T1>::type, typename __unwrap_ref_decay<_T2>::type>
563+
make_pair(_T1&& __t1, _T2&& __t2) {
534564
return pair<typename __unwrap_ref_decay<_T1>::type, typename __unwrap_ref_decay<_T2>::type>(
535565
std::forward<_T1>(__t1), std::forward<_T2>(__t2));
536566
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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: gcc && (c++11 || c++14 || c++17)
10+
11+
#include <type_traits>
12+
#include <utility>
13+
14+
#include "test_macros.h"
15+
16+
struct trivially_copyable {
17+
int arr[4];
18+
};
19+
20+
struct trivially_copyable_no_assignment {
21+
int arr[4];
22+
trivially_copyable_no_assignment& operator=(const trivially_copyable_no_assignment&) = delete;
23+
};
24+
static_assert(std::is_trivially_copyable<trivially_copyable_no_assignment>::value, "");
25+
26+
static_assert(std::is_trivially_copy_constructible<std::pair<trivially_copyable_no_assignment, int> >::value, "");
27+
static_assert(std::is_trivially_move_constructible<std::pair<trivially_copyable_no_assignment, int> >::value, "");
28+
#if TEST_STD_VER >= 11 // This is https://llvm.org/PR90605
29+
static_assert(!std::is_trivially_copy_assignable<std::pair<trivially_copyable_no_assignment, int> >::value, "");
30+
static_assert(!std::is_trivially_move_assignable<std::pair<trivially_copyable_no_assignment, int> >::value, "");
31+
#endif // TEST_STD_VER >= 11
32+
static_assert(std::is_trivially_destructible<std::pair<trivially_copyable_no_assignment, int> >::value, "");
33+
34+
struct trivially_copyable_no_construction {
35+
int arr[4];
36+
trivially_copyable_no_construction() = default;
37+
trivially_copyable_no_construction(const trivially_copyable_no_construction&) = delete;
38+
trivially_copyable_no_construction& operator=(const trivially_copyable_no_construction&) = default;
39+
};
40+
static_assert(std::is_trivially_copyable<trivially_copyable_no_construction>::value, "");
41+
42+
#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
43+
static_assert(!std::is_trivially_copy_constructible<std::pair<trivially_copyable_no_construction, int> >::value, "");
44+
static_assert(!std::is_trivially_move_constructible<std::pair<trivially_copyable_no_construction, int> >::value, "");
45+
static_assert(std::is_trivially_copy_assignable<std::pair<trivially_copyable_no_construction, int> >::value, "");
46+
static_assert(std::is_trivially_move_assignable<std::pair<trivially_copyable_no_construction, int> >::value, "");
47+
static_assert(std::is_trivially_destructible<std::pair<trivially_copyable_no_construction, int> >::value, "");
48+
#else // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
49+
static_assert(!std::is_trivially_copy_constructible<std::pair<trivially_copyable_no_construction, int> >::value, "");
50+
static_assert(!std::is_trivially_move_constructible<std::pair<trivially_copyable_no_construction, int> >::value, "");
51+
static_assert(!std::is_trivially_copy_assignable<std::pair<trivially_copyable_no_construction, int> >::value, "");
52+
static_assert(!std::is_trivially_move_assignable<std::pair<trivially_copyable_no_construction, int> >::value, "");
53+
static_assert(std::is_trivially_destructible<std::pair<trivially_copyable_no_construction, int> >::value, "");
54+
#endif // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
55+
56+
static_assert(!std::is_trivially_copyable<std::pair<int&, int> >::value, "");
57+
static_assert(!std::is_trivially_copyable<std::pair<int, int&> >::value, "");
58+
static_assert(!std::is_trivially_copyable<std::pair<int&, int&> >::value, "");
59+
60+
#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
61+
static_assert(std::is_trivially_copyable<std::pair<int, int> >::value, "");
62+
static_assert(std::is_trivially_copyable<std::pair<int, char> >::value, "");
63+
static_assert(std::is_trivially_copyable<std::pair<char, int> >::value, "");
64+
static_assert(std::is_trivially_copyable<std::pair<std::pair<char, char>, int> >::value, "");
65+
static_assert(std::is_trivially_copyable<std::pair<trivially_copyable, int> >::value, "");
66+
static_assert(std::is_trivially_copyable<std::pair<trivially_copyable_no_assignment, int> >::value, "");
67+
static_assert(std::is_trivially_copyable<std::pair<trivially_copyable_no_construction, int> >::value, "");
68+
69+
static_assert(std::is_trivially_copy_constructible<std::pair<int, int> >::value, "");
70+
static_assert(std::is_trivially_move_constructible<std::pair<int, int> >::value, "");
71+
static_assert(std::is_trivially_copy_assignable<std::pair<int, int> >::value, "");
72+
static_assert(std::is_trivially_move_assignable<std::pair<int, int> >::value, "");
73+
static_assert(std::is_trivially_destructible<std::pair<int, int> >::value, "");
74+
75+
#else // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR
76+
static_assert(!std::is_trivially_copyable<std::pair<int, int> >::value, "");
77+
static_assert(!std::is_trivially_copyable<std::pair<int, char> >::value, "");
78+
static_assert(!std::is_trivially_copyable<std::pair<char, int> >::value, "");
79+
static_assert(!std::is_trivially_copyable<std::pair<std::pair<char, char>, int> >::value, "");
80+
static_assert(!std::is_trivially_copyable<std::pair<trivially_copyable, int> >::value, "");
81+
static_assert(!std::is_trivially_copyable<std::pair<trivially_copyable_no_assignment, int> >::value, "");
82+
static_assert(!std::is_trivially_copyable<std::pair<trivially_copyable_no_construction, int> >::value, "");
83+
84+
static_assert(std::is_trivially_copy_constructible<std::pair<int, int> >::value, "");
85+
static_assert(std::is_trivially_move_constructible<std::pair<int, int> >::value, "");
86+
static_assert(!std::is_trivially_copy_assignable<std::pair<int, int> >::value, "");
87+
static_assert(!std::is_trivially_move_assignable<std::pair<int, int> >::value, "");
88+
static_assert(std::is_trivially_destructible<std::pair<int, int> >::value, "");
89+
#endif // _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR

0 commit comments

Comments
 (0)