Skip to content

Commit 042f90a

Browse files
committed
[libc++] Mark more types as trivially relocatable
1 parent c8e5ad4 commit 042f90a

File tree

13 files changed

+174
-6
lines changed

13 files changed

+174
-6
lines changed

libcxx/include/__exception/exception_ptr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
6464
friend _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT;
6565

6666
public:
67+
// exception_ptr is basically a COW string.
68+
using __trivially_relocatable = exception_ptr;
69+
6770
_LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {}
6871
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
6972

libcxx/include/__expected/expected.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <__type_traits/is_swappable.h>
3232
#include <__type_traits/is_trivially_constructible.h>
3333
#include <__type_traits/is_trivially_destructible.h>
34+
#include <__type_traits/is_trivially_relocatable.h>
3435
#include <__type_traits/is_void.h>
3536
#include <__type_traits/lazy.h>
3637
#include <__type_traits/negation.h>
@@ -463,6 +464,11 @@ class expected : private __expected_base<_Tp, _Err> {
463464
using error_type = _Err;
464465
using unexpected_type = unexpected<_Err>;
465466

467+
using __trivially_relocatable =
468+
__conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value && __libcpp_is_trivially_relocatable<_Err>::value,
469+
expected,
470+
void>;
471+
466472
template <class _Up>
467473
using rebind = expected<_Up, error_type>;
468474

libcxx/include/__locale

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ _LIBCPP_HIDE_FROM_ABI const _Facet& use_facet(const locale&);
4949

5050
class _LIBCPP_EXPORTED_FROM_ABI locale {
5151
public:
52+
// locale is essentially a shared_ptr that doesn't support weak_ptrs and never got a move constructor.
53+
using __trivially_relocatable = locale;
54+
5255
// types:
5356
class _LIBCPP_EXPORTED_FROM_ABI facet;
5457
class _LIBCPP_EXPORTED_FROM_ABI id;

libcxx/include/__memory/shared_ptr.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,10 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr {
419419
typedef _Tp element_type;
420420
#endif
421421

422+
// A shared_ptr contains only two raw pointers which point to the heap and move constructing already doesn't require
423+
// any bookkeeping, so it's always trivially relocatable.
424+
using __trivially_relocatable = shared_ptr;
425+
422426
private:
423427
element_type* __ptr_;
424428
__shared_weak_count* __cntrl_;
@@ -1301,6 +1305,10 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS weak_ptr {
13011305
typedef _Tp element_type;
13021306
#endif
13031307

1308+
// A weak_ptr contains only two raw pointers which point to the heap and move constructing already doesn't require
1309+
// any bookkeeping, so it's always trivially relocatable.
1310+
using __trivially_relocatable = weak_ptr;
1311+
13041312
private:
13051313
element_type* __ptr_;
13061314
__shared_weak_count* __cntrl_;

libcxx/include/__split_buffer

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ public:
6464
using iterator = pointer;
6565
using const_iterator = const_pointer;
6666

67+
// A __split_buffer containers the following members which may be trivially relocatable:
68+
// - pointer: may be trivially relocatable, so it's checked
69+
// - allocator_type: may be trivially relocatable, so it's checked
70+
// __split_buffer doesn't have any self-references, so it's trivially relocatable if its members are.
71+
using __trivially_relocatable = __conditional_t<
72+
__libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
73+
__split_buffer,
74+
void>;
75+
6776
pointer __first_;
6877
pointer __begin_;
6978
pointer __end_;

libcxx/include/__utility/pair.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <__type_traits/is_nothrow_constructible.h>
3535
#include <__type_traits/is_same.h>
3636
#include <__type_traits/is_swappable.h>
37+
#include <__type_traits/is_trivially_relocatable.h>
3738
#include <__type_traits/nat.h>
3839
#include <__type_traits/remove_cvref.h>
3940
#include <__type_traits/unwrap_ref.h>
@@ -71,6 +72,11 @@ struct _LIBCPP_TEMPLATE_VIS pair
7172
_T1 first;
7273
_T2 second;
7374

75+
using __trivially_relocatable =
76+
__conditional_t<__libcpp_is_trivially_relocatable<_T1>::value && __libcpp_is_trivially_relocatable<_T2>::value,
77+
pair,
78+
void>;
79+
7480
_LIBCPP_HIDE_FROM_ABI pair(pair const&) = default;
7581
_LIBCPP_HIDE_FROM_ABI pair(pair&&) = default;
7682

libcxx/include/array

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce
130130
#include <__type_traits/is_nothrow_constructible.h>
131131
#include <__type_traits/is_same.h>
132132
#include <__type_traits/is_swappable.h>
133+
#include <__type_traits/is_trivially_relocatable.h>
133134
#include <__type_traits/remove_cv.h>
134135
#include <__utility/empty.h>
135136
#include <__utility/integer_sequence.h>
@@ -166,6 +167,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
166167

167168
template <class _Tp, size_t _Size>
168169
struct _LIBCPP_TEMPLATE_VIS array {
170+
using __trivially_relocatable = __conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, array, void>;
171+
169172
// types:
170173
using __self = array;
171174
using value_type = _Tp;

libcxx/include/deque

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,16 @@ public:
478478
using reverse_iterator = std::reverse_iterator<iterator>;
479479
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
480480

481+
// A deque contains the following members which may be trivially relocatable:
482+
// - __map: is a `__split_buffer`, see `__split_buffer` for more information on when it is trivially relocatable
483+
// - size_type: is always trivially relocatable, since it is required to be an integral type
484+
// - allocator_type: may not be trivially relocatable, so it's checked
485+
// None of these are referencing the `deque` itself, so if all of them are trivially relocatable, `deque` is too.
486+
using __trivially_relocatable = __conditional_t<
487+
__libcpp_is_trivially_relocatable<__map>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
488+
deque,
489+
void>;
490+
481491
static_assert(is_same<allocator_type, __rebind_alloc<__alloc_traits, value_type> >::value,
482492
"[allocator.requirements] states that rebinding an allocator to the same type should result in the "
483493
"original allocator");

libcxx/include/optional

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,8 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
581581
public:
582582
using value_type = _Tp;
583583

584+
using __trivially_relocatable = conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>;
585+
584586
private:
585587
// Disable the reference extension using this static assert.
586588
static_assert(!is_same_v<__remove_cvref_t<value_type>, in_place_t>,

libcxx/include/tuple

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ template <class... Types>
241241
#include <__type_traits/is_reference.h>
242242
#include <__type_traits/is_same.h>
243243
#include <__type_traits/is_swappable.h>
244+
#include <__type_traits/is_trivially_relocatable.h>
244245
#include <__type_traits/lazy.h>
245246
#include <__type_traits/maybe_const.h>
246247
#include <__type_traits/nat.h>
@@ -538,6 +539,8 @@ class _LIBCPP_TEMPLATE_VIS tuple {
538539
get(const tuple<_Up...>&&) _NOEXCEPT;
539540

540541
public:
542+
using __trivially_relocatable = __conditional_t<_And<__libcpp_is_trivially_relocatable<_Tp>...>::value, tuple, void>;
543+
541544
// [tuple.cnstr]
542545

543546
// tuple() constructors (including allocator_arg_t variants)
@@ -1375,22 +1378,22 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t,
13751378
}
13761379
#else
13771380
template <class _Tp, class _Tuple, size_t... _Idx>
1378-
inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>,
1381+
inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>,
13791382
enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>> * = nullptr)
13801383
_LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
13811384
#endif // _LIBCPP_STD_VER >= 20
13821385

1383-
template <class _Tp, class _Tuple,
1386+
template <class _Tp, class _Tuple,
13841387
class _Seq = typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type, class = void>
13851388
inline constexpr bool __can_make_from_tuple = false;
13861389

13871390
template <class _Tp, class _Tuple, size_t... _Idx>
1388-
inline constexpr bool __can_make_from_tuple<_Tp, _Tuple, __tuple_indices<_Idx...>,
1391+
inline constexpr bool __can_make_from_tuple<_Tp, _Tuple, __tuple_indices<_Idx...>,
13891392
enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::declval<_Tuple>()))...>>> = true;
13901393

1391-
// Based on LWG3528(https://wg21.link/LWG3528) and http://eel.is/c++draft/description#structure.requirements-9,
1392-
// the standard allows to impose requirements, we constraint std::make_from_tuple to make std::make_from_tuple
1393-
// SFINAE friendly and also avoid worse diagnostic messages. We still keep the constraints of std::__make_from_tuple_impl
1394+
// Based on LWG3528(https://wg21.link/LWG3528) and http://eel.is/c++draft/description#structure.requirements-9,
1395+
// the standard allows to impose requirements, we constraint std::make_from_tuple to make std::make_from_tuple
1396+
// SFINAE friendly and also avoid worse diagnostic messages. We still keep the constraints of std::__make_from_tuple_impl
13941397
// so that std::__make_from_tuple_impl will have the same advantages when used alone.
13951398
#if _LIBCPP_STD_VER >= 20
13961399
template <class _Tp, class _Tuple>

libcxx/include/variant

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,9 @@ class _LIBCPP_TEMPLATE_VIS _LIBCPP_DECLSPEC_EMPTY_BASES variant
11511151
using __first_type = variant_alternative_t<0, variant>;
11521152

11531153
public:
1154+
using __trivially_relocatable =
1155+
conditional_t<(__libcpp_is_trivially_relocatable<_Types>::value && ...), variant, void>;
1156+
11541157
template <bool _Dummy = true,
11551158
enable_if_t<__dependent_type<is_default_constructible<__first_type>, _Dummy>::value, int> = 0>
11561159
_LIBCPP_HIDE_FROM_ABI constexpr variant() noexcept(is_nothrow_default_constructible_v<__first_type>)

libcxx/include/vector

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,15 @@ public:
407407
typedef std::reverse_iterator<iterator> reverse_iterator;
408408
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
409409

410+
// A vector containers the following members which may be trivially relocatable:
411+
// - pointer: may be trivially relocatable, so it's checked
412+
// - allocator_type: may be trivially relocatable, so it's checked
413+
// vector doesn't contain any self-references, so it's trivially relocatable if its members are.
414+
using __trivially_relocatable = __conditional_t<
415+
__libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
416+
vector,
417+
void>;
418+
410419
static_assert((is_same<typename allocator_type::value_type, value_type>::value),
411420
"Allocator::value_type must be same type as value_type");
412421

libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@
77
//===----------------------------------------------------------------------===//
88

99
#include <__type_traits/is_trivially_relocatable.h>
10+
#include <array>
11+
#include <deque>
12+
#include <exception>
13+
#include <expected>
14+
#include <locale>
1015
#include <memory>
16+
#include <optional>
1117
#include <string>
18+
#include <variant>
19+
#include <vector>
1220

1321
#include "constexpr_char_traits.h"
1422
#include "test_allocator.h"
@@ -44,9 +52,27 @@ static_assert(std::__libcpp_is_trivially_relocatable<MoveOnlyTriviallyCopyable>:
4452
#else
4553
static_assert(!std::__libcpp_is_trivially_relocatable<MoveOnlyTriviallyCopyable>::value, "");
4654
#endif
55+
56+
// library-internal types
57+
// ----------------------
58+
59+
// __split_buffer
60+
static_assert(std::__libcpp_is_trivially_relocatable<std::__split_buffer<int> >::value, "");
61+
static_assert(std::__libcpp_is_trivially_relocatable<std::__split_buffer<NotTriviallyCopyable> >::value, "");
62+
static_assert(!std::__libcpp_is_trivially_relocatable<std::__split_buffer<int, test_allocator<int> > >::value, "");
63+
4764
// standard library types
4865
// ----------------------
4966

67+
// array
68+
static_assert(std::__libcpp_is_trivially_relocatable<std::array<int, 0> >::value, "");
69+
static_assert(std::__libcpp_is_trivially_relocatable<std::array<NotTriviallyCopyable, 0> >::value, "");
70+
static_assert(std::__libcpp_is_trivially_relocatable<std::array<std::unique_ptr<int>, 0> >::value, "");
71+
72+
static_assert(std::__libcpp_is_trivially_relocatable<std::array<int, 1> >::value, "");
73+
static_assert(!std::__libcpp_is_trivially_relocatable<std::array<NotTriviallyCopyable, 1> >::value, "");
74+
static_assert(std::__libcpp_is_trivially_relocatable<std::array<std::unique_ptr<int>, 1> >::value, "");
75+
5076
// basic_string
5177
struct MyChar {
5278
char c;
@@ -79,6 +105,62 @@ static_assert(
79105
std::basic_string<MyChar, NotTriviallyRelocatableCharTraits<MyChar>, test_allocator<MyChar> > >::value,
80106
"");
81107

108+
// deque
109+
static_assert(std::__libcpp_is_trivially_relocatable<std::deque<int> >::value, "");
110+
static_assert(std::__libcpp_is_trivially_relocatable<std::deque<NotTriviallyCopyable> >::value, "");
111+
static_assert(!std::__libcpp_is_trivially_relocatable<std::deque<int, test_allocator<int> > >::value, "");
112+
113+
// exception_ptr
114+
static_assert(std::__libcpp_is_trivially_relocatable<std::exception_ptr>::value, "");
115+
116+
// expected
117+
#if TEST_STD_VER >= 23
118+
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<int, int> >::value);
119+
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<std::unique_ptr<int>, int>>::value);
120+
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<int, std::unique_ptr<int>>>::value);
121+
static_assert(std::__libcpp_is_trivially_relocatable<std::expected<std::unique_ptr<int>, std::unique_ptr<int>>>::value);
122+
123+
static_assert(!std::__libcpp_is_trivially_relocatable<std::expected<int, NotTriviallyCopyable>>::value);
124+
static_assert(!std::__libcpp_is_trivially_relocatable<std::expected<NotTriviallyCopyable, int>>::value);
125+
static_assert(
126+
!std::__libcpp_is_trivially_relocatable<std::expected<NotTriviallyCopyable, NotTriviallyCopyable>>::value);
127+
#endif
128+
129+
// locale
130+
static_assert(std::__libcpp_is_trivially_relocatable<std::locale>::value, "");
131+
132+
// optional
133+
static_assert(std::__libcpp_is_trivially_relocatable<std::optional<int> >::value, "");
134+
static_assert(!std::__libcpp_is_trivially_relocatable<std::optional<NotTriviallyCopyable> >::value, "");
135+
static_assert(std::__libcpp_is_trivially_relocatable<std::optional<std::unique_ptr<int> > >::value, "");
136+
137+
// pair
138+
static_assert(std::__libcpp_is_trivially_relocatable<std::pair<int, int> >::value, "");
139+
static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<NotTriviallyCopyable, int> >::value, "");
140+
static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<int, NotTriviallyCopyable> >::value, "");
141+
static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<NotTriviallyCopyable, NotTriviallyCopyable> >::value,
142+
"");
143+
static_assert(std::__libcpp_is_trivially_relocatable<std::pair<std::unique_ptr<int>, std::unique_ptr<int> > >::value,
144+
"");
145+
146+
// shared_ptr
147+
static_assert(std::__libcpp_is_trivially_relocatable<std::shared_ptr<NotTriviallyCopyable> >::value, "");
148+
149+
// tuple
150+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<> >::value, "");
151+
152+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<int> >::value, "");
153+
static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable> >::value, "");
154+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<std::unique_ptr<int> > >::value, "");
155+
156+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<int, int> >::value, "");
157+
static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable, int> >::value, "");
158+
static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<int, NotTriviallyCopyable> >::value, "");
159+
static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable, NotTriviallyCopyable> >::value,
160+
"");
161+
static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<std::unique_ptr<int>, std::unique_ptr<int> > >::value,
162+
"");
163+
82164
// unique_ptr
83165
struct NotTriviallyRelocatableDeleter {
84166
NotTriviallyRelocatableDeleter(const NotTriviallyRelocatableDeleter&);
@@ -112,4 +194,25 @@ static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int, NotTr
112194
static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[], NotTriviallyRelocatablePointer> >::value,
113195
"");
114196

197+
// variant
198+
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<int> >::value, "");
199+
static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<NotTriviallyCopyable> >::value, "");
200+
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<std::unique_ptr<int> > >::value, "");
201+
202+
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<int, int> >::value, "");
203+
static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<NotTriviallyCopyable, int> >::value, "");
204+
static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<int, NotTriviallyCopyable> >::value, "");
205+
static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<NotTriviallyCopyable, NotTriviallyCopyable> >::value,
206+
"");
207+
static_assert(std::__libcpp_is_trivially_relocatable<std::variant<std::unique_ptr<int>, std::unique_ptr<int> > >::value,
208+
"");
209+
210+
// vector
211+
static_assert(std::__libcpp_is_trivially_relocatable<std::vector<int> >::value, "");
212+
static_assert(std::__libcpp_is_trivially_relocatable<std::vector<NotTriviallyCopyable> >::value, "");
213+
static_assert(!std::__libcpp_is_trivially_relocatable<std::vector<int, test_allocator<int> > >::value, "");
214+
215+
// weak_ptr
216+
static_assert(std::__libcpp_is_trivially_relocatable<std::weak_ptr<NotTriviallyCopyable> >::value, "");
217+
115218
// TODO: Mark all the trivially relocatable STL types as such

0 commit comments

Comments
 (0)