-
Notifications
You must be signed in to change notification settings - Fork 14.2k
[libc++] Mark more types as trivially relocatable #89724
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++] Mark more types as trivially relocatable #89724
Conversation
042f90a
to
ded371a
Compare
df5f43d
to
fa21630
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks! This is a really nice improvement. We should also look at more places where we can relocate elements, e.g. in vector there are certainly places where we don't currently take advantage of it.
@llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777) ChangesPatch is 20.73 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/89724.diff 16 Files Affected:
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index c9027de9238cd..f7026c437e883 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -64,6 +64,9 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
friend _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT;
public:
+ // exception_ptr is basically a COW string.
+ using __trivially_relocatable = exception_ptr;
+
_LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {}
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index d7adaac7567b2..0f994e297a877 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -31,6 +31,7 @@
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_constructible.h>
#include <__type_traits/is_trivially_destructible.h>
+#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/is_void.h>
#include <__type_traits/lazy.h>
#include <__type_traits/negation.h>
@@ -463,6 +464,11 @@ class expected : private __expected_base<_Tp, _Err> {
using error_type = _Err;
using unexpected_type = unexpected<_Err>;
+ using __trivially_relocatable =
+ __conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value && __libcpp_is_trivially_relocatable<_Err>::value,
+ expected,
+ void>;
+
template <class _Up>
using rebind = expected<_Up, error_type>;
diff --git a/libcxx/include/__locale b/libcxx/include/__locale
index 36ac099d650e4..fcae7c5efbe60 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -49,6 +49,9 @@ _LIBCPP_HIDE_FROM_ABI const _Facet& use_facet(const locale&);
class _LIBCPP_EXPORTED_FROM_ABI locale {
public:
+ // locale is essentially a shared_ptr that doesn't support weak_ptrs and never got a move constructor.
+ using __trivially_relocatable = locale;
+
// types:
class _LIBCPP_EXPORTED_FROM_ABI facet;
class _LIBCPP_EXPORTED_FROM_ABI id;
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 992b1ba43f100..fe87e0d04d8bb 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -419,6 +419,10 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr {
typedef _Tp element_type;
#endif
+ // A shared_ptr contains only two raw pointers which point to the heap and move constructing already doesn't require
+ // any bookkeeping, so it's always trivially relocatable.
+ using __trivially_relocatable = shared_ptr;
+
private:
element_type* __ptr_;
__shared_weak_count* __cntrl_;
@@ -1301,6 +1305,10 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS weak_ptr {
typedef _Tp element_type;
#endif
+ // A weak_ptr contains only two raw pointers which point to the heap and move constructing already doesn't require
+ // any bookkeeping, so it's always trivially relocatable.
+ using __trivially_relocatable = weak_ptr;
+
private:
element_type* __ptr_;
__shared_weak_count* __cntrl_;
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index c68349e0979c9..28b17235b56d7 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -24,12 +24,14 @@
#include <__memory/pointer_traits.h>
#include <__memory/swap_allocator.h>
#include <__type_traits/add_lvalue_reference.h>
+#include <__type_traits/conditional.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_nothrow_assignable.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_destructible.h>
+#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/remove_reference.h>
#include <__utility/forward.h>
#include <__utility/move.h>
@@ -64,6 +66,15 @@ public:
using iterator = pointer;
using const_iterator = const_pointer;
+ // A __split_buffer containers the following members which may be trivially relocatable:
+ // - pointer: may be trivially relocatable, so it's checked
+ // - allocator_type: may be trivially relocatable, so it's checked
+ // __split_buffer doesn't have any self-references, so it's trivially relocatable if its members are.
+ using __trivially_relocatable = __conditional_t<
+ __libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
+ __split_buffer,
+ void>;
+
pointer __first_;
pointer __begin_;
pointer __end_;
diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index e05250ba05717..c0b4215dbb5f0 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -34,6 +34,7 @@
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
+#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/nat.h>
#include <__type_traits/remove_cvref.h>
#include <__type_traits/unwrap_ref.h>
@@ -71,6 +72,11 @@ struct _LIBCPP_TEMPLATE_VIS pair
_T1 first;
_T2 second;
+ using __trivially_relocatable =
+ __conditional_t<__libcpp_is_trivially_relocatable<_T1>::value && __libcpp_is_trivially_relocatable<_T2>::value,
+ pair,
+ void>;
+
_LIBCPP_HIDE_FROM_ABI pair(pair const&) = default;
_LIBCPP_HIDE_FROM_ABI pair(pair&&) = default;
diff --git a/libcxx/include/array b/libcxx/include/array
index 6ea094deec32d..e030c6f32e9b2 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -130,6 +130,7 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
+#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/remove_cv.h>
#include <__utility/empty.h>
#include <__utility/integer_sequence.h>
@@ -166,6 +167,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS array {
+ using __trivially_relocatable = __conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, array, void>;
+
// types:
using __self = array;
using value_type = _Tp;
diff --git a/libcxx/include/deque b/libcxx/include/deque
index 3c33e04e9f05f..6adfb96efa1a4 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -478,6 +478,16 @@ public:
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ // A deque contains the following members which may be trivially relocatable:
+ // - __map: is a `__split_buffer`, see `__split_buffer` for more information on when it is trivially relocatable
+ // - size_type: is always trivially relocatable, since it is required to be an integral type
+ // - allocator_type: may not be trivially relocatable, so it's checked
+ // None of these are referencing the `deque` itself, so if all of them are trivially relocatable, `deque` is too.
+ using __trivially_relocatable = __conditional_t<
+ __libcpp_is_trivially_relocatable<__map>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
+ deque,
+ void>;
+
static_assert(is_same<allocator_type, __rebind_alloc<__alloc_traits, value_type> >::value,
"[allocator.requirements] states that rebinding an allocator to the same type should result in the "
"original allocator");
diff --git a/libcxx/include/optional b/libcxx/include/optional
index a16e48502e250..90cbb9113a4f1 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -210,6 +210,7 @@ namespace std {
#include <__type_traits/is_trivially_assignable.h>
#include <__type_traits/is_trivially_constructible.h>
#include <__type_traits/is_trivially_destructible.h>
+#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/negation.h>
#include <__type_traits/remove_const.h>
#include <__type_traits/remove_cvref.h>
@@ -581,6 +582,8 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
public:
using value_type = _Tp;
+ using __trivially_relocatable = conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>;
+
private:
// Disable the reference extension using this static assert.
static_assert(!is_same_v<__remove_cvref_t<value_type>, in_place_t>,
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index ace5f2328a457..93c6f479a98b8 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -241,6 +241,7 @@ template <class... Types>
#include <__type_traits/is_reference.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
+#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/lazy.h>
#include <__type_traits/maybe_const.h>
#include <__type_traits/nat.h>
@@ -538,6 +539,8 @@ class _LIBCPP_TEMPLATE_VIS tuple {
get(const tuple<_Up...>&&) _NOEXCEPT;
public:
+ using __trivially_relocatable = __conditional_t<_And<__libcpp_is_trivially_relocatable<_Tp>...>::value, tuple, void>;
+
// [tuple.cnstr]
// tuple() constructors (including allocator_arg_t variants)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 34150bd452842..d10d81f784358 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -239,6 +239,7 @@ namespace std {
#include <__type_traits/is_trivially_assignable.h>
#include <__type_traits/is_trivially_constructible.h>
#include <__type_traits/is_trivially_destructible.h>
+#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/is_void.h>
#include <__type_traits/remove_const.h>
#include <__type_traits/remove_cvref.h>
@@ -1165,6 +1166,9 @@ class _LIBCPP_TEMPLATE_VIS _LIBCPP_DECLSPEC_EMPTY_BASES variant
using __first_type = variant_alternative_t<0, variant>;
public:
+ using __trivially_relocatable =
+ conditional_t<(__libcpp_is_trivially_relocatable<_Types>::value && ...), variant, void>;
+
template <bool _Dummy = true,
enable_if_t<__dependent_type<is_default_constructible<__first_type>, _Dummy>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr variant() noexcept(is_nothrow_default_constructible_v<__first_type>)
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 976bde9b9048c..44bef5780266b 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -407,6 +407,15 @@ public:
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ // A vector containers the following members which may be trivially relocatable:
+ // - pointer: may be trivially relocatable, so it's checked
+ // - allocator_type: may be trivially relocatable, so it's checked
+ // vector doesn't contain any self-references, so it's trivially relocatable if its members are.
+ using __trivially_relocatable = __conditional_t<
+ __libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value,
+ vector,
+ void>;
+
static_assert((is_same<typename allocator_type::value_type, value_type>::value),
"Allocator::value_type must be same type as value_type");
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index cf0af3b8bb392..2f942412f306a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -905,6 +905,7 @@ thread type_traits
thread version
tuple compare
tuple cstddef
+tuple cstdint
tuple exception
tuple iosfwd
tuple new
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 62d931c0eebad..f43a67b72c10a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -161,6 +161,7 @@ exception typeinfo
exception version
execution version
expected cstddef
+expected cstdint
expected initializer_list
expected new
expected version
@@ -494,6 +495,7 @@ regex typeinfo
regex vector
regex version
scoped_allocator cstddef
+scoped_allocator cstdint
scoped_allocator limits
scoped_allocator new
scoped_allocator tuple
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 62d931c0eebad..36870273e3348 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -161,6 +161,7 @@ exception typeinfo
exception version
execution version
expected cstddef
+expected cstdint
expected initializer_list
expected new
expected version
@@ -494,6 +495,7 @@ regex typeinfo
regex vector
regex version
scoped_allocator cstddef
+scoped_allocator cstdint
scoped_allocator limits
scoped_allocator new
scoped_allocator tuple
@@ -650,6 +652,7 @@ thread typeinfo
thread version
tuple compare
tuple cstddef
+tuple cstdint
tuple version
type_traits cstddef
type_traits cstdint
@@ -684,6 +687,7 @@ unordered_set tuple
unordered_set version
utility compare
utility cstddef
+utility cstdint
utility initializer_list
utility limits
utility version
diff --git a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp
index 4d1a8ad9e229a..71f24913b0972 100644
--- a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp
+++ b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp
@@ -7,8 +7,17 @@
//===----------------------------------------------------------------------===//
#include <__type_traits/is_trivially_relocatable.h>
+#include <array>
+#include <deque>
+#include <exception>
+#include <expected>
+#include <locale>
#include <memory>
+#include <optional>
#include <string>
+#include <tuple>
+#include <variant>
+#include <vector>
#include "constexpr_char_traits.h"
#include "test_allocator.h"
@@ -44,9 +53,27 @@ static_assert(std::__libcpp_is_trivially_relocatable<MoveOnlyTriviallyCopyable>:
#else
static_assert(!std::__libcpp_is_trivially_relocatable<MoveOnlyTriviallyCopyable>::value, "");
#endif
+
+// library-internal types
+// ----------------------
+
+// __split_buffer
+static_assert(std::__libcpp_is_trivially_relocatable<std::__split_buffer<int> >::value, "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::__split_buffer<NotTriviallyCopyable> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::__split_buffer<int, test_allocator<int> > >::value, "");
+
// standard library types
// ----------------------
+// array
+static_assert(std::__libcpp_is_trivially_relocatable<std::array<int, 0> >::value, "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::array<NotTriviallyCopyable, 0> >::value, "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::array<std::unique_ptr<int>, 0> >::value, "");
+
+static_assert(std::__libcpp_is_trivially_relocatable<std::array<int, 1> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::array<NotTriviallyCopyable, 1> >::value, "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::array<std::unique_ptr<int>, 1> >::value, "");
+
// basic_string
#if defined(_LIBCPP_HAS_NO_ASAN) || !defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
struct MyChar {
@@ -80,6 +107,67 @@ static_assert(
std::basic_string<MyChar, NotTriviallyRelocatableCharTraits<MyChar>, test_allocator<MyChar> > >::value,
"");
#endif
+
+// deque
+static_assert(std::__libcpp_is_trivially_relocatable<std::deque<int> >::value, "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::deque<NotTriviallyCopyable> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::deque<int, test_allocator<int> > >::value, "");
+
+// exception_ptr
+static_assert(std::__libcpp_is_trivially_relocatable<std::exception_ptr>::value, "");
+
+// expected
+#if TEST_STD_VER >= 23
+static_assert(std::__libcpp_is_trivially_relocatable<std::expected<int, int> >::value);
+static_assert(std::__libcpp_is_trivially_relocatable<std::expected<std::unique_ptr<int>, int>>::value);
+static_assert(std::__libcpp_is_trivially_relocatable<std::expected<int, std::unique_ptr<int>>>::value);
+static_assert(std::__libcpp_is_trivially_relocatable<std::expected<std::unique_ptr<int>, std::unique_ptr<int>>>::value);
+
+static_assert(!std::__libcpp_is_trivially_relocatable<std::expected<int, NotTriviallyCopyable>>::value);
+static_assert(!std::__libcpp_is_trivially_relocatable<std::expected<NotTriviallyCopyable, int>>::value);
+static_assert(
+ !std::__libcpp_is_trivially_relocatable<std::expected<NotTriviallyCopyable, NotTriviallyCopyable>>::value);
+#endif
+
+// locale
+static_assert(std::__libcpp_is_trivially_relocatable<std::locale>::value, "");
+
+// optional
+#if TEST_STD_VER >= 17
+static_assert(std::__libcpp_is_trivially_relocatable<std::optional<int>>::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::optional<NotTriviallyCopyable>>::value, "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::optional<std::unique_ptr<int>>>::value, "");
+#endif // TEST_STD_VER >= 17
+
+// pair
+static_assert(std::__libcpp_is_trivially_relocatable<std::pair<int, int> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<NotTriviallyCopyable, int> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<int, NotTriviallyCopyable> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::pair<NotTriviallyCopyable, NotTriviallyCopyable> >::value,
+ "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::pair<std::unique_ptr<int>, std::unique_ptr<int> > >::value,
+ "");
+
+// shared_ptr
+static_assert(std::__libcpp_is_trivially_relocatable<std::shared_ptr<NotTriviallyCopyable> >::value, "");
+
+// tuple
+#if TEST_STD_VER >= 11
+static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<> >::value, "");
+
+static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<int> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable> >::value, "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<std::unique_ptr<int> > >::value, "");
+
+static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<int, int> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable, int> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<int, NotTriviallyCopyable> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::tuple<NotTriviallyCopyable, NotTriviallyCopyable> >::value,
+ "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::tuple<std::unique_ptr<int>, std::unique_ptr<int> > >::value,
+ "");
+#endif // TEST_STD_VER >= 11
+
// unique_ptr
struct NotTriviallyRelocatableDeleter {
NotTriviallyRelocatableDeleter(const NotTriviallyRelocatableDeleter&);
@@ -113,4 +201,27 @@ static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int, NotTr
static_assert(!std::__libcpp_is_trivially_relocatable<std::unique_ptr<int[], NotTriviallyRelocatablePointer> >::value,
"");
+// variant
+#if TEST_STD_VER >= 17
+static_assert(std::__libcpp_is_trivially_relocatable<std::variant<int> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<NotTriviallyCopyable> >::value, "");
+static_assert(std::__libcpp_is_trivially_relocatable<std::variant<std::unique_ptr<int> > >::value, "");
+
+static_assert(std::__libcpp_is_trivially_relocatable<std::variant<int, int> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<NotTriviallyCopyable, int> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::variant<int, NotTriviallyCopyable> >::value, "");
+static_assert(!std::__libcpp_is_trivially_relocatable<std::v...
[truncated]
|
fa21630
to
7182a98
Compare
7182a98
to
1f48a11
Compare
No description provided.