[libcxx-commits] [libcxx] [libc++] Replace `__compressed_pair` with `[[no_unique_address]]` (PR #76756)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Sep 12 07:02:18 PDT 2024
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/76756
>From 509ab33faa52526cd2e86367368b960ab2d8490d Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 1 Jan 2024 18:47:45 +0100
Subject: [PATCH] [libc++] Replace `__compressed_pair` with
`[[no_unique_address]]`
---
libcxx/docs/ReleaseNotes/20.rst | 15 +-
libcxx/include/__config | 20 +-
libcxx/include/__configuration/abi.h | 31 +++
libcxx/include/__functional/function.h | 27 +--
libcxx/include/__hash_table | 155 ++++++++------
libcxx/include/__memory/compressed_pair.h | 202 ++++++------------
libcxx/include/__memory/shared_ptr.h | 44 ++--
libcxx/include/__memory/unique_ptr.h | 124 ++++++-----
libcxx/include/__split_buffer | 27 ++-
libcxx/include/__tree | 53 ++---
libcxx/include/__type_traits/datasizeof.h | 3 +
libcxx/include/deque | 45 ++--
libcxx/include/forward_list | 21 +-
libcxx/include/future | 22 +-
libcxx/include/list | 21 +-
libcxx/include/string | 147 +++++++------
libcxx/include/vector | 89 ++++----
.../unord.map/abi.compile.pass.cpp | 7 +-
.../unord.set/abi.compile.pass.cpp | 7 +-
.../sequences/deque/abi.compile.pass.cpp | 2 +
.../vector.bool/abi.compile.pass.cpp | 2 +
.../missing_hash_specialization.verify.cpp | 9 +-
.../compressed_pair/compressed_pair.pass.cpp | 52 -----
.../type_traits/datasizeof.compile.pass.cpp | 4 +
.../libcxx.control_block_layout.pass.cpp | 121 ++++++++---
.../func.wrap.func.con/copy_move.pass.cpp | 4 -
libcxx/utils/gdb/libcxx/printers.py | 62 ++----
libcxx/utils/libcxx/test/features.py | 1 +
28 files changed, 638 insertions(+), 679 deletions(-)
delete mode 100644 libcxx/test/libcxx/memory/compressed_pair/compressed_pair.pass.cpp
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index 93d6027291ad95..f366ecf22d4b41 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -42,7 +42,6 @@ Implemented Papers
- P2609R3: Relaxing Ranges Just A Smidge (`Github <https://github.com/llvm/llvm-project/issues/105253>`__)
- P2985R0: A type trait for detecting virtual base classes (`Github <https://github.com/llvm/llvm-project/issues/105432>`__)
-
Improvements and New Features
-----------------------------
@@ -51,6 +50,9 @@ Improvements and New Features
- The ``_LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION`` macro has been added to make ``std::uncaught_exception`` available in C++20 and later modes.
+- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``, resulting in reduced
+ compile times and smaller debug information as well as better code generation if optimizations are disabled.
+ The Chromium project measured a 5% reduction in object file and debug information size.
Deprecations and Removals
-------------------------
@@ -91,8 +93,15 @@ LLVM 21
ABI Affecting Changes
---------------------
-- TODO
-
+- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``. The ABI impact is:
+ - When using the Itanium ABI (most non-MSVC platforms), empty types are now placed at the beginning of the enclosing
+ object instead of where the beginning of the ``__compressed_pair`` subobject was. This is only observable by
+ checking the address of the empty allocator, equality comparator or hasher.
+ - Additionally, using an overaligned empty type as an allocator, comparator or hasher in the associative containers
+ (and only those containers) may result in the container's object object size and data layout changing beyond only
+ the address of the empty member.
+ - When using the MSVC ABI, this change results in some classes having a completely different memory layout, so this is
+ a genuine ABI break. However, the library does not currently guarantee ABI stability on MSVC platforms.
Build System Changes
--------------------
diff --git a/libcxx/include/__config b/libcxx/include/__config
index bccf90d1dbacd2..db74240dc960ee 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -31,6 +31,7 @@
# define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y
# define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y)
+# define _LIBCPP_CONCAT3(X, Y, Z) _LIBCPP_CONCAT(X, _LIBCPP_CONCAT(Y, Z))
# if __STDC_HOSTED__ == 0
# define _LIBCPP_FREESTANDING
@@ -191,25 +192,6 @@ _LIBCPP_HARDENING_MODE_DEBUG
# error "libc++ only supports C++03 with Clang-based compilers. Please enable C++11"
# endif
-// FIXME: ABI detection should be done via compiler builtin macros. This
-// is just a placeholder until Clang implements such macros. For now assume
-// that Windows compilers pretending to be MSVC++ target the Microsoft ABI,
-// and allow the user to explicitly specify the ABI to handle cases where this
-// heuristic falls short.
-# if defined(_LIBCPP_ABI_FORCE_ITANIUM) && defined(_LIBCPP_ABI_FORCE_MICROSOFT)
-# error "Only one of _LIBCPP_ABI_FORCE_ITANIUM and _LIBCPP_ABI_FORCE_MICROSOFT can be defined"
-# elif defined(_LIBCPP_ABI_FORCE_ITANIUM)
-# define _LIBCPP_ABI_ITANIUM
-# elif defined(_LIBCPP_ABI_FORCE_MICROSOFT)
-# define _LIBCPP_ABI_MICROSOFT
-# else
-# if defined(_WIN32) && defined(_MSC_VER)
-# define _LIBCPP_ABI_MICROSOFT
-# else
-# define _LIBCPP_ABI_ITANIUM
-# endif
-# endif
-
# if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_NO_VCRUNTIME)
# define _LIBCPP_ABI_VCRUNTIME
# endif
diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 8efbb42d1d8470..707e10b5ceb53f 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -18,6 +18,25 @@
# pragma GCC system_header
#endif
+// FIXME: ABI detection should be done via compiler builtin macros. This
+// is just a placeholder until Clang implements such macros. For now assume
+// that Windows compilers pretending to be MSVC++ target the Microsoft ABI,
+// and allow the user to explicitly specify the ABI to handle cases where this
+// heuristic falls short.
+#if defined(_LIBCPP_ABI_FORCE_ITANIUM) && defined(_LIBCPP_ABI_FORCE_MICROSOFT)
+# error "Only one of _LIBCPP_ABI_FORCE_ITANIUM and _LIBCPP_ABI_FORCE_MICROSOFT can be defined"
+#elif defined(_LIBCPP_ABI_FORCE_ITANIUM)
+# define _LIBCPP_ABI_ITANIUM
+#elif defined(_LIBCPP_ABI_FORCE_MICROSOFT)
+# define _LIBCPP_ABI_MICROSOFT
+#else
+# if defined(_WIN32) && defined(_MSC_VER)
+# define _LIBCPP_ABI_MICROSOFT
+# else
+# define _LIBCPP_ABI_ITANIUM
+# endif
+#endif
+
#if _LIBCPP_ABI_VERSION >= 2
// Change short string representation so that string data starts at offset 0,
// improving its alignment in some cases.
@@ -98,6 +117,13 @@
// and WCHAR_MAX. This ABI setting determines whether we should instead track whether the fill
// value has been initialized using a separate boolean, which changes the ABI.
# define _LIBCPP_ABI_IOS_ALLOW_ARBITRARY_FILL_VALUE
+// Historically, libc++ used a type called `__compressed_pair` to reduce storage needs in cases of empty types (e.g. an
+// empty allocator in std::vector). We switched to using `[[no_unique_address]]`. However, for ABI compatibility reasons
+// we had to add artificial padding in a few places.
+//
+// This setting disables the addition of such artificial padding, leading to a more optimal
+// representation for several types.
+# define _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
#elif _LIBCPP_ABI_VERSION == 1
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
// Enable compiling copies of now inline methods into the dylib to support
@@ -150,6 +176,11 @@
// ABI impact: changes the iterator type of `vector` (except `vector<bool>`).
// #define _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
+// [[msvc::no_unique_address]] seems to mostly affect empty classes, so the padding scheme for Itanium doesn't work.
+#if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING)
+# define _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
+#endif
+
#if defined(_LIBCPP_COMPILER_CLANG_BASED)
# if defined(__APPLE__)
# if defined(__i386__) || defined(__x86_64__)
diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index c7b98035e34bfa..b073af4f64ab57 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -143,45 +143,46 @@ class __default_alloc_func;
template <class _Fp, class _Ap, class _Rp, class... _ArgTypes>
class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> {
- __compressed_pair<_Fp, _Ap> __f_;
+ _LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Ap, __alloc_);
public:
typedef _LIBCPP_NODEBUG _Fp _Target;
typedef _LIBCPP_NODEBUG _Ap _Alloc;
- _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_.first(); }
+ _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __func_; }
// WIN32 APIs may define __allocator, so use __get_allocator instead.
- _LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __f_.second(); }
+ _LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __alloc_; }
- _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f)
- : __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple()) {}
+ _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f) : __func_(std::move(__f)), __alloc_() {}
- _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a)
- : __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(__a)) {}
+ _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {}
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, _Alloc&& __a)
- : __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(std::move(__a))) {}
+ : __func_(__f), __alloc_(std::move(__a)) {}
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f, _Alloc&& __a)
- : __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple(std::move(__a))) {}
+ : __func_(std::move(__f)), __alloc_(std::move(__a)) {}
_LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) {
typedef __invoke_void_return_wrapper<_Rp> _Invoker;
- return _Invoker::__call(__f_.first(), std::forward<_ArgTypes>(__arg)...);
+ return _Invoker::__call(__func_, std::forward<_ArgTypes>(__arg)...);
}
_LIBCPP_HIDE_FROM_ABI __alloc_func* __clone() const {
typedef allocator_traits<_Alloc> __alloc_traits;
typedef __rebind_alloc<__alloc_traits, __alloc_func> _AA;
- _AA __a(__f_.second());
+ _AA __a(__alloc_);
typedef __allocator_destructor<_AA> _Dp;
unique_ptr<__alloc_func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
- ::new ((void*)__hold.get()) __alloc_func(__f_.first(), _Alloc(__a));
+ ::new ((void*)__hold.get()) __alloc_func(__func_, _Alloc(__a));
return __hold.release();
}
- _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~__compressed_pair<_Target, _Alloc>(); }
+ _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT {
+ __func_.~_Fp();
+ __alloc_.~_Alloc();
+ }
_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__alloc_func* __f) {
typedef allocator_traits<_Alloc> __alloc_traits;
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index d5fbc92a3dfc4e..94554a8f15345c 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -554,29 +554,29 @@ class __bucket_list_deallocator {
typedef allocator_traits<allocator_type> __alloc_traits;
typedef typename __alloc_traits::size_type size_type;
- __compressed_pair<size_type, allocator_type> __data_;
+ _LIBCPP_COMPRESSED_PAIR(size_type, __size_, allocator_type, __alloc_);
public:
typedef typename __alloc_traits::pointer pointer;
_LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __data_(0, __default_init_tag()) {}
+ : __size_(0) {}
_LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(const allocator_type& __a, size_type __size)
_NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
- : __data_(__size, __a) {}
+ : __size_(__size), __alloc_(__a) {}
_LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(__bucket_list_deallocator&& __x)
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
- : __data_(std::move(__x.__data_)) {
+ : __size_(std::move(__x.__size_)), __alloc_(std::move(__x.__alloc_)) {
__x.size() = 0;
}
- _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __data_.first(); }
- _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __data_.first(); }
+ _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
+ _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; }
- _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __data_.second(); }
- _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __data_.second(); }
+ _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __alloc_; }
+ _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __alloc_; }
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { __alloc_traits::deallocate(__alloc(), __p, size()); }
};
@@ -716,27 +716,27 @@ private:
// --- Member data begin ---
__bucket_list __bucket_list_;
- __compressed_pair<__first_node, __node_allocator> __p1_;
- __compressed_pair<size_type, hasher> __p2_;
- __compressed_pair<float, key_equal> __p3_;
+ _LIBCPP_COMPRESSED_PAIR(__first_node, __first_node_, __node_allocator, __node_alloc_);
+ _LIBCPP_COMPRESSED_PAIR(size_type, __size_, hasher, __hasher_);
+ _LIBCPP_COMPRESSED_PAIR(float, __max_load_factor_, key_equal, __key_eq_);
// --- Member data end ---
- _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __p2_.first(); }
+ _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
public:
- _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __p2_.first(); }
+ _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; }
- _LIBCPP_HIDE_FROM_ABI hasher& hash_function() _NOEXCEPT { return __p2_.second(); }
- _LIBCPP_HIDE_FROM_ABI const hasher& hash_function() const _NOEXCEPT { return __p2_.second(); }
+ _LIBCPP_HIDE_FROM_ABI hasher& hash_function() _NOEXCEPT { return __hasher_; }
+ _LIBCPP_HIDE_FROM_ABI const hasher& hash_function() const _NOEXCEPT { return __hasher_; }
- _LIBCPP_HIDE_FROM_ABI float& max_load_factor() _NOEXCEPT { return __p3_.first(); }
- _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __p3_.first(); }
+ _LIBCPP_HIDE_FROM_ABI float& max_load_factor() _NOEXCEPT { return __max_load_factor_; }
+ _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __max_load_factor_; }
- _LIBCPP_HIDE_FROM_ABI key_equal& key_eq() _NOEXCEPT { return __p3_.second(); }
- _LIBCPP_HIDE_FROM_ABI const key_equal& key_eq() const _NOEXCEPT { return __p3_.second(); }
+ _LIBCPP_HIDE_FROM_ABI key_equal& key_eq() _NOEXCEPT { return __key_eq_; }
+ _LIBCPP_HIDE_FROM_ABI const key_equal& key_eq() const _NOEXCEPT { return __key_eq_; }
- _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __p1_.second(); }
- _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __p1_.second(); }
+ _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __node_alloc_; }
+ _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __node_alloc_; }
public:
typedef __hash_iterator<__node_pointer> iterator;
@@ -1022,26 +1022,34 @@ inline __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table() _NOEXCEPT_(
is_nothrow_default_constructible<__bucket_list>::value&& is_nothrow_default_constructible<__first_node>::value&&
is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_default_constructible<hasher>::value&&
is_nothrow_default_constructible<key_equal>::value)
- : __p2_(0, __default_init_tag()), __p3_(1.0f, __default_init_tag()) {}
+ : __size_(0), __max_load_factor_(1.0f) {}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
inline __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const hasher& __hf, const key_equal& __eql)
- : __bucket_list_(nullptr, __bucket_list_deleter()), __p1_(), __p2_(0, __hf), __p3_(1.0f, __eql) {}
+ : __bucket_list_(nullptr, __bucket_list_deleter()),
+ __first_node_(),
+ __node_alloc_(),
+ __size_(0),
+ __hasher_(__hf),
+ __max_load_factor_(1.0f),
+ __key_eq_(__eql) {}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(
const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
: __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
- __p1_(__default_init_tag(), __node_allocator(__a)),
- __p2_(0, __hf),
- __p3_(1.0f, __eql) {}
+ __node_alloc_(__node_allocator(__a)),
+ __size_(0),
+ __hasher_(__hf),
+ __max_load_factor_(1.0f),
+ __key_eq_(__eql) {}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const allocator_type& __a)
: __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
- __p1_(__default_init_tag(), __node_allocator(__a)),
- __p2_(0, __default_init_tag()),
- __p3_(1.0f, __default_init_tag()) {}
+ __node_alloc_(__node_allocator(__a)),
+ __size_(0),
+ __max_load_factor_(1.0f) {}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u)
@@ -1049,17 +1057,20 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u)
__bucket_list_deleter(allocator_traits<__pointer_allocator>::select_on_container_copy_construction(
__u.__bucket_list_.get_deleter().__alloc()),
0)),
- __p1_(__default_init_tag(),
- allocator_traits<__node_allocator>::select_on_container_copy_construction(__u.__node_alloc())),
- __p2_(0, __u.hash_function()),
- __p3_(__u.__p3_) {}
+ __node_alloc_(allocator_traits<__node_allocator>::select_on_container_copy_construction(__u.__node_alloc())),
+ __size_(0),
+ __hasher_(__u.hash_function()),
+ __max_load_factor_(__u.__max_load_factor_),
+ __key_eq_(__u.__key_eq_) {}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u, const allocator_type& __a)
: __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
- __p1_(__default_init_tag(), __node_allocator(__a)),
- __p2_(0, __u.hash_function()),
- __p3_(__u.__p3_) {}
+ __node_alloc_(__node_allocator(__a)),
+ __size_(0),
+ __hasher_(__u.hash_function()),
+ __max_load_factor_(__u.__max_load_factor_),
+ __key_eq_(__u.__key_eq_) {}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u) _NOEXCEPT_(
@@ -1067,12 +1078,15 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u) _NOEX
is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<hasher>::value&&
is_nothrow_move_constructible<key_equal>::value)
: __bucket_list_(std::move(__u.__bucket_list_)),
- __p1_(std::move(__u.__p1_)),
- __p2_(std::move(__u.__p2_)),
- __p3_(std::move(__u.__p3_)) {
+ __first_node_(std::move(__u.__first_node_)),
+ __node_alloc_(std::move(__u.__node_alloc_)),
+ __size_(std::move(__u.__size_)),
+ __hasher_(std::move(__u.__hasher_)),
+ __max_load_factor_(__u.__max_load_factor_),
+ __key_eq_(std::move(__u.__key_eq_)) {
if (size() > 0) {
- __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr();
- __u.__p1_.first().__next_ = nullptr;
+ __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
+ __u.__first_node_.__next_ = nullptr;
__u.size() = 0;
}
}
@@ -1080,17 +1094,19 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u) _NOEX
template <class _Tp, class _Hash, class _Equal, class _Alloc>
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u, const allocator_type& __a)
: __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
- __p1_(__default_init_tag(), __node_allocator(__a)),
- __p2_(0, std::move(__u.hash_function())),
- __p3_(std::move(__u.__p3_)) {
+ __node_alloc_(__node_allocator(__a)),
+ __size_(0),
+ __hasher_(std::move(__u.__hasher_)),
+ __max_load_factor_(__u.__max_load_factor_),
+ __key_eq_(std::move(__u.__key_eq_)) {
if (__a == allocator_type(__u.__node_alloc())) {
__bucket_list_.reset(__u.__bucket_list_.release());
__bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size();
__u.__bucket_list_.get_deleter().size() = 0;
if (__u.size() > 0) {
- __p1_.first().__next_ = __u.__p1_.first().__next_;
- __u.__p1_.first().__next_ = nullptr;
- __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr();
+ __first_node_.__next_ = __u.__first_node_.__next_;
+ __u.__first_node_.__next_ = nullptr;
+ __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
size() = __u.size();
__u.size() = 0;
}
@@ -1104,7 +1120,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table() {
static_assert(is_copy_constructible<hasher>::value, "Hasher must be copy-constructible.");
#endif
- __deallocate_node(__p1_.first().__next_);
+ __deallocate_node(__first_node_.__next_);
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1150,8 +1166,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__detach() _NOEXCEPT {
for (size_type __i = 0; __i < __bc; ++__i)
__bucket_list_[__i] = nullptr;
size() = 0;
- __next_pointer __cache = __p1_.first().__next_;
- __p1_.first().__next_ = nullptr;
+ __next_pointer __cache = __first_node_.__next_;
+ __first_node_.__next_ = nullptr;
return __cache;
}
@@ -1168,10 +1184,10 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
hash_function() = std::move(__u.hash_function());
max_load_factor() = __u.max_load_factor();
key_eq() = std::move(__u.key_eq());
- __p1_.first().__next_ = __u.__p1_.first().__next_;
+ __first_node_.__next_ = __u.__first_node_.__next_;
if (size() > 0) {
- __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr();
- __u.__p1_.first().__next_ = nullptr;
+ __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
+ __u.__first_node_.__next_ = nullptr;
__u.size() = 0;
}
}
@@ -1288,7 +1304,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
template <class _Tp, class _Hash, class _Equal, class _Alloc>
inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() _NOEXCEPT {
- return iterator(__p1_.first().__next_);
+ return iterator(__first_node_.__next_);
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1300,7 +1316,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() _NOEXCEPT {
template <class _Tp, class _Hash, class _Equal, class _Alloc>
inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() const _NOEXCEPT {
- return const_iterator(__p1_.first().__next_);
+ return const_iterator(__first_node_.__next_);
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1312,8 +1328,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT {
template <class _Tp, class _Hash, class _Equal, class _Alloc>
void __hash_table<_Tp, _Hash, _Equal, _Alloc>::clear() _NOEXCEPT {
if (size() > 0) {
- __deallocate_node(__p1_.first().__next_);
- __p1_.first().__next_ = nullptr;
+ __deallocate_node(__first_node_.__next_);
+ __first_node_.__next_ = nullptr;
size_type __bc = bucket_count();
for (size_type __i = 0; __i < __bc; ++__i)
__bucket_list_[__i] = nullptr;
@@ -1365,7 +1381,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique_perform(__node_po
// insert_after __bucket_list_[__chash], or __first_node if bucket is null
__next_pointer __pn = __bucket_list_[__chash];
if (__pn == nullptr) {
- __pn = __p1_.first().__ptr();
+ __pn = __first_node_.__ptr();
__nd->__next_ = __pn->__next_;
__pn->__next_ = __nd->__ptr();
// fix up __bucket_list_
@@ -1445,7 +1461,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi_perform(
size_type __bc = bucket_count();
size_t __chash = std::__constrain_hash(__cp->__hash_, __bc);
if (__pn == nullptr) {
- __pn = __p1_.first().__ptr();
+ __pn = __first_node_.__ptr();
__cp->__next_ = __pn->__next_;
__pn->__next_ = __cp->__ptr();
// fix up __bucket_list_
@@ -1530,7 +1546,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const&
// insert_after __bucket_list_[__chash], or __first_node if bucket is null
__next_pointer __pn = __bucket_list_[__chash];
if (__pn == nullptr) {
- __pn = __p1_.first().__ptr();
+ __pn = __first_node_.__ptr();
__h->__next_ = __pn->__next_;
__pn->__next_ = __h.get()->__ptr();
// fix up __bucket_list_
@@ -1708,7 +1724,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc) {
if (__nbc > 0) {
for (size_type __i = 0; __i < __nbc; ++__i)
__bucket_list_[__i] = nullptr;
- __next_pointer __pp = __p1_.first().__ptr();
+ __next_pointer __pp = __first_node_.__ptr();
__next_pointer __cp = __pp->__next_;
if (__cp != nullptr) {
size_type __chash = std::__constrain_hash(__cp->__hash(), __nbc);
@@ -1885,7 +1901,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p) _NOEXCEPT {
// Fix up __bucket_list_
// if __pn is not in same bucket (before begin is not in same bucket) &&
// if __cn->__next_ is not in same bucket (nullptr is not in same bucket)
- if (__pn == __p1_.first().__ptr() || std::__constrain_hash(__pn->__hash(), __bc) != __chash) {
+ if (__pn == __first_node_.__ptr() || std::__constrain_hash(__pn->__hash(), __bc) != __chash) {
if (__cn->__next_ == nullptr || std::__constrain_hash(__cn->__next_->__hash(), __bc) != __chash)
__bucket_list_[__chash] = nullptr;
}
@@ -2004,14 +2020,17 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
std::swap(__bucket_list_.get_deleter().size(), __u.__bucket_list_.get_deleter().size());
std::__swap_allocator(__bucket_list_.get_deleter().__alloc(), __u.__bucket_list_.get_deleter().__alloc());
std::__swap_allocator(__node_alloc(), __u.__node_alloc());
- std::swap(__p1_.first().__next_, __u.__p1_.first().__next_);
- __p2_.swap(__u.__p2_);
- __p3_.swap(__u.__p3_);
+ std::swap(__first_node_.__next_, __u.__first_node_.__next_);
+ using std::swap;
+ swap(__size_, __u.__size_);
+ swap(__hasher_, __u.__hasher_);
+ swap(__max_load_factor_, __u.__max_load_factor_);
+ swap(__key_eq_, __u.__key_eq_);
if (size() > 0)
- __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr();
+ __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
if (__u.size() > 0)
- __u.__bucket_list_[std::__constrain_hash(__u.__p1_.first().__next_->__hash(), __u.bucket_count())] =
- __u.__p1_.first().__ptr();
+ __u.__bucket_list_[std::__constrain_hash(__u.__first_node_.__next_->__hash(), __u.bucket_count())] =
+ __u.__first_node_.__ptr();
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
diff --git a/libcxx/include/__memory/compressed_pair.h b/libcxx/include/__memory/compressed_pair.h
index 40e5cfc35fb040..13d35cd4ab6f45 100644
--- a/libcxx/include/__memory/compressed_pair.h
+++ b/libcxx/include/__memory/compressed_pair.h
@@ -11,161 +11,79 @@
#define _LIBCPP___MEMORY_COMPRESSED_PAIR_H
#include <__config>
-#include <__fwd/tuple.h>
-#include <__tuple/tuple_indices.h>
-#include <__type_traits/decay.h>
-#include <__type_traits/dependent_type.h>
-#include <__type_traits/enable_if.h>
-#include <__type_traits/is_constructible.h>
+#include <__type_traits/datasizeof.h>
#include <__type_traits/is_empty.h>
#include <__type_traits/is_final.h>
-#include <__type_traits/is_same.h>
-#include <__type_traits/is_swappable.h>
-#include <__utility/forward.h>
-#include <__utility/move.h>
-#include <__utility/piecewise_construct.h>
-#include <cstddef>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
-_LIBCPP_PUSH_MACROS
-#include <__undef_macros>
-
_LIBCPP_BEGIN_NAMESPACE_STD
-// Tag used to default initialize one or both of the pair's elements.
-struct __default_init_tag {};
-struct __value_init_tag {};
-
-template <class _Tp, int _Idx, bool _CanBeEmptyBase = is_empty<_Tp>::value && !__libcpp_is_final<_Tp>::value>
-struct __compressed_pair_elem {
- using _ParamT = _Tp;
- using reference = _Tp&;
- using const_reference = const _Tp&;
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__default_init_tag) {}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__value_init_tag) : __value_() {}
-
- template <class _Up, __enable_if_t<!is_same<__compressed_pair_elem, __decay_t<_Up> >::value, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(_Up&& __u)
- : __value_(std::forward<_Up>(__u)) {}
-
-#ifndef _LIBCPP_CXX03_LANG
- template <class... _Args, size_t... _Indices>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit __compressed_pair_elem(
- piecewise_construct_t, tuple<_Args...> __args, __tuple_indices<_Indices...>)
- : __value_(std::forward<_Args>(std::get<_Indices>(__args))...) {}
-#endif
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference __get() _NOEXCEPT { return __value_; }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __get() const _NOEXCEPT { return __value_; }
-
-private:
- _Tp __value_;
-};
-
-template <class _Tp, int _Idx>
-struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
- using _ParamT = _Tp;
- using reference = _Tp&;
- using const_reference = const _Tp&;
- using __value_type = _Tp;
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem() = default;
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__default_init_tag) {}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__value_init_tag) : __value_type() {}
-
- template <class _Up, __enable_if_t<!is_same<__compressed_pair_elem, __decay_t<_Up> >::value, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(_Up&& __u)
- : __value_type(std::forward<_Up>(__u)) {}
-
-#ifndef _LIBCPP_CXX03_LANG
- template <class... _Args, size_t... _Indices>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17
- __compressed_pair_elem(piecewise_construct_t, tuple<_Args...> __args, __tuple_indices<_Indices...>)
- : __value_type(std::forward<_Args>(std::get<_Indices>(__args))...) {}
-#endif
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference __get() _NOEXCEPT { return *this; }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __get() const _NOEXCEPT { return *this; }
-};
+// ================================================================================================================== //
+// The utilites here are for staying ABI compatible with the legacy `__compressed_pair`. They should not be used //
+// for new data structures. Use `_LIBCPP_NO_UNIQUE_ADDRESS` for new data structures instead (but make sure you //
+// understand how it works). //
+// ================================================================================================================== //
-template <class _T1, class _T2>
-class __compressed_pair : private __compressed_pair_elem<_T1, 0>, private __compressed_pair_elem<_T2, 1> {
-public:
- // NOTE: This static assert should never fire because __compressed_pair
- // is *almost never* used in a scenario where it's possible for T1 == T2.
- // (The exception is std::function where it is possible that the function
- // object and the allocator have the same type).
- static_assert(
- (!is_same<_T1, _T2>::value),
- "__compressed_pair cannot be instantiated when T1 and T2 are the same type; "
- "The current implementation is NOT ABI-compatible with the previous implementation for this configuration");
-
- using _Base1 _LIBCPP_NODEBUG = __compressed_pair_elem<_T1, 0>;
- using _Base2 _LIBCPP_NODEBUG = __compressed_pair_elem<_T2, 1>;
-
- template <bool _Dummy = true,
- __enable_if_t< __dependent_type<is_default_constructible<_T1>, _Dummy>::value &&
- __dependent_type<is_default_constructible<_T2>, _Dummy>::value,
- int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair()
- : _Base1(__value_init_tag()), _Base2(__value_init_tag()) {}
-
- template <class _U1, class _U2>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair(_U1&& __t1, _U2&& __t2)
- : _Base1(std::forward<_U1>(__t1)), _Base2(std::forward<_U2>(__t2)) {}
-
-#ifndef _LIBCPP_CXX03_LANG
- template <class... _Args1, class... _Args2>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit __compressed_pair(
- piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args)
- : _Base1(__pc, std::move(__first_args), typename __make_tuple_indices<sizeof...(_Args1)>::type()),
- _Base2(__pc, std::move(__second_args), typename __make_tuple_indices<sizeof...(_Args2)>::type()) {}
-#endif
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename _Base1::reference first() _NOEXCEPT {
- return static_cast<_Base1&>(*this).__get();
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename _Base1::const_reference first() const _NOEXCEPT {
- return static_cast<_Base1 const&>(*this).__get();
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename _Base2::reference second() _NOEXCEPT {
- return static_cast<_Base2&>(*this).__get();
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename _Base2::const_reference second() const _NOEXCEPT {
- return static_cast<_Base2 const&>(*this).__get();
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static _Base1* __get_first_base(__compressed_pair* __pair) _NOEXCEPT {
- return static_cast<_Base1*>(__pair);
- }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static _Base2* __get_second_base(__compressed_pair* __pair) _NOEXCEPT {
- return static_cast<_Base2*>(__pair);
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void swap(__compressed_pair& __x)
- _NOEXCEPT_(__is_nothrow_swappable_v<_T1>&& __is_nothrow_swappable_v<_T2>) {
- using std::swap;
- swap(first(), __x.first());
- swap(second(), __x.second());
- }
+// The first member is aligned to the alignment of the second member to force padding in front of the compressed pair
+// in case there are members before it.
+//
+// For example:
+// (assuming x86-64 linux)
+// class SomeClass {
+// uint32_t member1;
+// _LIBCPP_COMPRESSED_PAIR(uint32_t, member2, uint64_t, member3);
+// }
+//
+// The layout with __compressed_pair is:
+// member1 - offset: 0, size: 4
+// padding - offset: 4, size: 4
+// member2 - offset: 8, size: 4
+// padding - offset: 12, size: 4
+// member3 - offset: 16, size: 8
+//
+// If the [[gnu::aligned]] wasn't there, the layout would instead be:
+// member1 - offset: 0, size: 4
+// member2 - offset: 4, size: 4
+// member3 - offset: 8, size: 8
+
+#ifndef _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
+
+template <class _ToPad>
+class __compressed_pair_padding {
+ char __padding_[(is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value)
+ ? 0
+ : sizeof(_ToPad) - __datasizeof_v<_ToPad>];
};
-template <class _T1, class _T2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
-swap(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y)
- _NOEXCEPT_(__is_nothrow_swappable_v<_T1>&& __is_nothrow_swappable_v<_T2>) {
- __x.swap(__y);
-}
+# define _LIBCPP_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \
+ _LIBCPP_NO_UNIQUE_ADDRESS __attribute__((__aligned__(_LIBCPP_ALIGNOF(T2)))) T1 Initializer1; \
+ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding1_, __LINE__, _); \
+ _LIBCPP_NO_UNIQUE_ADDRESS T2 Initializer2; \
+ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T2> _LIBCPP_CONCAT3(__padding2_, __LINE__, _)
+
+# define _LIBCPP_COMPRESSED_TRIPLE(T1, Initializer1, T2, Initializer2, T3, Initializer3) \
+ _LIBCPP_NO_UNIQUE_ADDRESS \
+ __attribute__((__aligned__(_LIBCPP_ALIGNOF(T2)), __aligned__(_LIBCPP_ALIGNOF(T3)))) T1 Initializer1; \
+ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding1_, __LINE__, _); \
+ _LIBCPP_NO_UNIQUE_ADDRESS T2 Initializer2; \
+ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T2> _LIBCPP_CONCAT3(__padding2_, __LINE__, _); \
+ _LIBCPP_NO_UNIQUE_ADDRESS T3 Initializer3; \
+ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T3> _LIBCPP_CONCAT3(__padding3_, __LINE__, _)
+
+#else
+# define _LIBCPP_COMPRESSED_PAIR(T1, Name1, T2, Name2) \
+ _LIBCPP_NO_UNIQUE_ADDRESS T1 Name1; \
+ _LIBCPP_NO_UNIQUE_ADDRESS T2 Name2
+
+# define _LIBCPP_COMPRESSED_TRIPLE(T1, Name1, T2, Name2, T3, Name3) \
+ _LIBCPP_NO_UNIQUE_ADDRESS T1 Name1; \
+ _LIBCPP_NO_UNIQUE_ADDRESS T2 Name2; \
+ _LIBCPP_NO_UNIQUE_ADDRESS T3 Name3
+#endif // _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
_LIBCPP_END_NAMESPACE_STD
-_LIBCPP_POP_MACROS
-
#endif // _LIBCPP___MEMORY_COMPRESSED_PAIR_H
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index d487e4fbe3a953..af181a3327a475 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -198,11 +198,11 @@ class _LIBCPP_EXPORTED_FROM_ABI __shared_weak_count : private __shared_count {
template <class _Tp, class _Dp, class _Alloc>
class __shared_ptr_pointer : public __shared_weak_count {
- __compressed_pair<__compressed_pair<_Tp, _Dp>, _Alloc> __data_;
+ _LIBCPP_COMPRESSED_TRIPLE(_Tp, __ptr_, _Dp, __deleter_, _Alloc, __alloc_);
public:
_LIBCPP_HIDE_FROM_ABI __shared_ptr_pointer(_Tp __p, _Dp __d, _Alloc __a)
- : __data_(__compressed_pair<_Tp, _Dp>(__p, std::move(__d)), std::move(__a)) {}
+ : __ptr_(__p), __deleter_(std::move(__d)), __alloc_(std::move(__a)) {}
#ifndef _LIBCPP_HAS_NO_RTTI
_LIBCPP_HIDE_FROM_ABI_VIRTUAL const void* __get_deleter(const type_info&) const _NOEXCEPT override;
@@ -217,15 +217,15 @@ class __shared_ptr_pointer : public __shared_weak_count {
template <class _Tp, class _Dp, class _Alloc>
const void* __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__get_deleter(const type_info& __t) const _NOEXCEPT {
- return __t == typeid(_Dp) ? std::addressof(__data_.first().second()) : nullptr;
+ return __t == typeid(_Dp) ? std::addressof(__deleter_) : nullptr;
}
#endif // _LIBCPP_HAS_NO_RTTI
template <class _Tp, class _Dp, class _Alloc>
void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared() _NOEXCEPT {
- __data_.first().second()(__data_.first().first());
- __data_.first().second().~_Dp();
+ __deleter_(__ptr_);
+ __deleter_.~_Dp();
}
template <class _Tp, class _Dp, class _Alloc>
@@ -234,8 +234,8 @@ void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT {
typedef allocator_traits<_Al> _ATraits;
typedef pointer_traits<typename _ATraits::pointer> _PTraits;
- _Al __a(__data_.second());
- __data_.second().~_Alloc();
+ _Al __a(__alloc_);
+ __alloc_.~_Alloc();
__a.deallocate(_PTraits::pointer_to(*this), 1);
}
@@ -293,36 +293,28 @@ struct __shared_ptr_emplace : __shared_weak_count {
allocator_traits<_ControlBlockAlloc>::deallocate(__tmp, pointer_traits<_ControlBlockPointer>::pointer_to(*this), 1);
}
+ // TODO: It should be possible to refactor this to remove `_Storage` entirely.
// This class implements the control block for non-array shared pointers created
// through `std::allocate_shared` and `std::make_shared`.
- //
- // In previous versions of the library, we used a compressed pair to store
- // both the _Alloc and the _Tp. This implies using EBO, which is incompatible
- // with Allocator construction for _Tp. To allow implementing P0674 in C++20,
- // we now use a properly aligned char buffer while making sure that we maintain
- // the same layout that we had when we used a compressed pair.
- using _CompressedPair = __compressed_pair<_Alloc, _Tp>;
- struct _ALIGNAS_TYPE(_CompressedPair) _Storage {
- char __blob_[sizeof(_CompressedPair)];
+ struct _Storage {
+ struct _Data {
+ _LIBCPP_COMPRESSED_PAIR(_Alloc, __alloc_, _Tp, __elem_);
+ };
+
+ _ALIGNAS_TYPE(_Data) char __buffer_[sizeof(_Data)];
_LIBCPP_HIDE_FROM_ABI explicit _Storage(_Alloc&& __a) { ::new ((void*)__get_alloc()) _Alloc(std::move(__a)); }
_LIBCPP_HIDE_FROM_ABI ~_Storage() { __get_alloc()->~_Alloc(); }
+
_LIBCPP_HIDE_FROM_ABI _Alloc* __get_alloc() _NOEXCEPT {
- _CompressedPair* __as_pair = reinterpret_cast<_CompressedPair*>(__blob_);
- typename _CompressedPair::_Base1* __first = _CompressedPair::__get_first_base(__as_pair);
- _Alloc* __alloc = reinterpret_cast<_Alloc*>(__first);
- return __alloc;
+ return std::addressof(reinterpret_cast<_Data*>(__buffer_)->__alloc_);
}
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI _Tp* __get_elem() _NOEXCEPT {
- _CompressedPair* __as_pair = reinterpret_cast<_CompressedPair*>(__blob_);
- typename _CompressedPair::_Base2* __second = _CompressedPair::__get_second_base(__as_pair);
- _Tp* __elem = reinterpret_cast<_Tp*>(__second);
- return __elem;
+ return std::addressof(reinterpret_cast<_Data*>(__buffer_)->__elem_);
}
};
- static_assert(_LIBCPP_ALIGNOF(_Storage) == _LIBCPP_ALIGNOF(_CompressedPair), "");
- static_assert(sizeof(_Storage) == sizeof(_CompressedPair), "");
_Storage __storage_;
};
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 7f5e0ea243c956..1c73ff90ec2236 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -143,7 +143,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
void>;
private:
- __compressed_pair<pointer, deleter_type> __ptr_;
+ _LIBCPP_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_);
typedef _LIBCPP_NODEBUG __unique_ptr_deleter_sfinae<_Dp> _DeleterSFINAE;
@@ -177,23 +177,25 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
public:
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(__value_init_tag(), __value_init_tag()) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(), __deleter_() {}
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT
- : __ptr_(__value_init_tag(), __value_init_tag()) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT : __ptr_(), __deleter_() {}
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
- _LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(pointer __p) _NOEXCEPT : __ptr_(__p, __value_init_tag()) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(pointer __p) _NOEXCEPT
+ : __ptr_(__p),
+ __deleter_() {}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_LValRefType<_Dummy> > >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(pointer __p, _LValRefType<_Dummy> __d) _NOEXCEPT
- : __ptr_(__p, __d) {}
+ : __ptr_(__p),
+ __deleter_(__d) {}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy> > >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) _NOEXCEPT
- : __ptr_(__p, std::move(__d)) {
+ : __ptr_(__p),
+ __deleter_(std::move(__d)) {
static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
}
@@ -201,24 +203,26 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
_LIBCPP_HIDE_FROM_ABI unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT
- : __ptr_(__u.release(), std::forward<deleter_type>(__u.get_deleter())) {}
+ : __ptr_(__u.release()),
+ __deleter_(std::forward<deleter_type>(__u.get_deleter())) {}
template <class _Up,
class _Ep,
class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>,
class = _EnableIfDeleterConvertible<_Ep> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT
- : __ptr_(__u.release(), std::forward<_Ep>(__u.get_deleter())) {}
+ : __ptr_(__u.release()),
+ __deleter_(std::forward<_Ep>(__u.get_deleter())) {}
#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR)
template <class _Up,
__enable_if_t<is_convertible<_Up*, _Tp*>::value && is_same<_Dp, default_delete<_Tp> >::value, int> = 0>
- _LIBCPP_HIDE_FROM_ABI unique_ptr(auto_ptr<_Up>&& __p) _NOEXCEPT : __ptr_(__p.release(), __value_init_tag()) {}
+ _LIBCPP_HIDE_FROM_ABI unique_ptr(auto_ptr<_Up>&& __p) _NOEXCEPT : __ptr_(__p.release()), __deleter_() {}
#endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT {
reset(__u.release());
- __ptr_.second() = std::forward<deleter_type>(__u.get_deleter());
+ __deleter_ = std::forward<deleter_type>(__u.get_deleter());
return *this;
}
@@ -228,7 +232,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
class = _EnableIfDeleterAssignable<_Ep> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT {
reset(__u.release());
- __ptr_.second() = std::forward<_Ep>(__u.get_deleter());
+ __deleter_ = std::forward<_Ep>(__u.get_deleter());
return *this;
}
@@ -255,32 +259,36 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const
_NOEXCEPT_(_NOEXCEPT_(*std::declval<pointer>())) {
- return *__ptr_.first();
+ return *__ptr_;
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer operator->() const _NOEXCEPT { return __ptr_.first(); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_.first(); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __ptr_.second(); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer operator->() const _NOEXCEPT { return __ptr_; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __deleter_; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 const deleter_type& get_deleter() const _NOEXCEPT {
- return __ptr_.second();
+ return __deleter_;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit operator bool() const _NOEXCEPT {
- return __ptr_.first() != nullptr;
+ return __ptr_ != nullptr;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer release() _NOEXCEPT {
- pointer __t = __ptr_.first();
- __ptr_.first() = pointer();
+ pointer __t = __ptr_;
+ __ptr_ = pointer();
return __t;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset(pointer __p = pointer()) _NOEXCEPT {
- pointer __tmp = __ptr_.first();
- __ptr_.first() = __p;
+ pointer __tmp = __ptr_;
+ __ptr_ = __p;
if (__tmp)
- __ptr_.second()(__tmp);
+ __deleter_(__tmp);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT { __ptr_.swap(__u.__ptr_); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT {
+ using std::swap;
+ swap(__ptr_, __u.__ptr_);
+ swap(__deleter_, __u.__deleter_);
+ }
};
template <class _Tp, class _Dp>
@@ -302,7 +310,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
void>;
private:
- __compressed_pair<pointer, deleter_type> __ptr_;
+ _LIBCPP_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_);
template <class _From>
struct _CheckArrayPointerConversion : is_same<_From, pointer> {};
@@ -351,42 +359,46 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
public:
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(__value_init_tag(), __value_init_tag()) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(), __deleter_() {}
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT
- : __ptr_(__value_init_tag(), __value_init_tag()) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT : __ptr_(), __deleter_() {}
template <class _Pp,
bool _Dummy = true,
class = _EnableIfDeleterDefaultConstructible<_Dummy>,
class = _EnableIfPointerConvertible<_Pp> >
- _LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(_Pp __p) _NOEXCEPT : __ptr_(__p, __value_init_tag()) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(_Pp __p) _NOEXCEPT
+ : __ptr_(__p),
+ __deleter_() {}
template <class _Pp,
bool _Dummy = true,
class = _EnableIfDeleterConstructible<_LValRefType<_Dummy> >,
class = _EnableIfPointerConvertible<_Pp> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) _NOEXCEPT
- : __ptr_(__p, __d) {}
+ : __ptr_(__p),
+ __deleter_(__d) {}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_LValRefType<_Dummy> > >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) _NOEXCEPT
- : __ptr_(nullptr, __d) {}
+ : __ptr_(nullptr),
+ __deleter_(__d) {}
template <class _Pp,
bool _Dummy = true,
class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy> >,
class = _EnableIfPointerConvertible<_Pp> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(_Pp __p, _GoodRValRefType<_Dummy> __d) _NOEXCEPT
- : __ptr_(__p, std::move(__d)) {
+ : __ptr_(__p),
+ __deleter_(std::move(__d)) {
static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy> > >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) _NOEXCEPT
- : __ptr_(nullptr, std::move(__d)) {
+ : __ptr_(nullptr),
+ __deleter_(std::move(__d)) {
static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
}
@@ -397,11 +409,12 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
_LIBCPP_HIDE_FROM_ABI unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT
- : __ptr_(__u.release(), std::forward<deleter_type>(__u.get_deleter())) {}
+ : __ptr_(__u.release()),
+ __deleter_(std::forward<deleter_type>(__u.get_deleter())) {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT {
reset(__u.release());
- __ptr_.second() = std::forward<deleter_type>(__u.get_deleter());
+ __deleter_ = std::forward<deleter_type>(__u.get_deleter());
return *this;
}
@@ -410,7 +423,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>,
class = _EnableIfDeleterConvertible<_Ep> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT
- : __ptr_(__u.release(), std::forward<_Ep>(__u.get_deleter())) {}
+ : __ptr_(__u.release()),
+ __deleter_(std::forward<_Ep>(__u.get_deleter())) {}
template <class _Up,
class _Ep,
@@ -418,7 +432,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
class = _EnableIfDeleterAssignable<_Ep> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT {
reset(__u.release());
- __ptr_.second() = std::forward<_Ep>(__u.get_deleter());
+ __deleter_ = std::forward<_Ep>(__u.get_deleter());
return *this;
}
@@ -436,41 +450,45 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator[](size_t __i) const {
- return __ptr_.first()[__i];
+ return __ptr_[__i];
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_.first(); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_; }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __ptr_.second(); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __deleter_; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 const deleter_type& get_deleter() const _NOEXCEPT {
- return __ptr_.second();
+ return __deleter_;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit operator bool() const _NOEXCEPT {
- return __ptr_.first() != nullptr;
+ return __ptr_ != nullptr;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer release() _NOEXCEPT {
- pointer __t = __ptr_.first();
- __ptr_.first() = pointer();
+ pointer __t = __ptr_;
+ __ptr_ = pointer();
return __t;
}
template <class _Pp, __enable_if_t<_CheckArrayPointerConversion<_Pp>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset(_Pp __p) _NOEXCEPT {
- pointer __tmp = __ptr_.first();
- __ptr_.first() = __p;
+ pointer __tmp = __ptr_;
+ __ptr_ = __p;
if (__tmp)
- __ptr_.second()(__tmp);
+ __deleter_(__tmp);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset(nullptr_t = nullptr) _NOEXCEPT {
- pointer __tmp = __ptr_.first();
- __ptr_.first() = nullptr;
+ pointer __tmp = __ptr_;
+ __ptr_ = nullptr;
if (__tmp)
- __ptr_.second()(__tmp);
+ __deleter_(__tmp);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT { __ptr_.swap(__u.__ptr_); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT {
+ using std::swap;
+ swap(__ptr_, __u.__ptr_);
+ swap(__deleter_, __u.__deleter_);
+ }
};
template <class _Tp, class _Dp, __enable_if_t<__is_swappable_v<_Dp>, int> = 0>
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index bab724d1b8963b..7916769bd83bfa 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -78,7 +78,7 @@ public:
pointer __first_;
pointer __begin_;
pointer __end_;
- __compressed_pair<pointer, allocator_type> __end_cap_;
+ _LIBCPP_COMPRESSED_PAIR(pointer, __end_cap_, allocator_type, __alloc_);
using __alloc_ref = __add_lvalue_reference_t<allocator_type>;
using __alloc_const_ref = __add_lvalue_reference_t<allocator_type>;
@@ -88,13 +88,13 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __default_init_tag()) {}
+ : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr) {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a)
- : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a) {}
+ : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr), __alloc_(__a) {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a)
- : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a) {}
+ : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr), __alloc_(__a) {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a);
@@ -111,15 +111,11 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~__split_buffer();
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __alloc_rr& __alloc() _NOEXCEPT { return __end_cap_.second(); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const __alloc_rr& __alloc() const _NOEXCEPT {
- return __end_cap_.second();
- }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __alloc_rr& __alloc() _NOEXCEPT { return __alloc_; }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const __alloc_rr& __alloc() const _NOEXCEPT { return __alloc_; }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return __end_cap_.first(); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT {
- return __end_cap_.first();
- }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return __end_cap_; }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT { return __end_cap_; }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __begin_; }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __begin_; }
@@ -346,7 +342,7 @@ __split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
- : __end_cap_(nullptr, __a) {
+ : __end_cap_(nullptr), __alloc_(__a) {
if (__cap == 0) {
__first_ = nullptr;
} else {
@@ -371,7 +367,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__
: __first_(std::move(__c.__first_)),
__begin_(std::move(__c.__begin_)),
__end_(std::move(__c.__end_)),
- __end_cap_(std::move(__c.__end_cap_)) {
+ __end_cap_(std::move(__c.__end_cap_)),
+ __alloc_(std::move(__c.__alloc_)) {
__c.__first_ = nullptr;
__c.__begin_ = nullptr;
__c.__end_ = nullptr;
@@ -381,7 +378,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
__split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a)
- : __end_cap_(nullptr, __a) {
+ : __end_cap_(nullptr), __alloc_(__a) {
if (__a == __c.__alloc()) {
__first_ = __c.__first_;
__begin_ = __c.__begin_;
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index 1990fa602d39ca..6ded2c597f6fa7 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -932,21 +932,21 @@ private:
private:
__iter_pointer __begin_node_;
- __compressed_pair<__end_node_t, __node_allocator> __pair1_;
- __compressed_pair<size_type, value_compare> __pair3_;
+ _LIBCPP_COMPRESSED_PAIR(__end_node_t, __end_node_, __node_allocator, __node_alloc_);
+ _LIBCPP_COMPRESSED_PAIR(size_type, __size_, value_compare, __value_comp_);
public:
_LIBCPP_HIDE_FROM_ABI __iter_pointer __end_node() _NOEXCEPT {
- return static_cast<__iter_pointer>(pointer_traits<__end_node_ptr>::pointer_to(__pair1_.first()));
+ return static_cast<__iter_pointer>(pointer_traits<__end_node_ptr>::pointer_to(__end_node_));
}
_LIBCPP_HIDE_FROM_ABI __iter_pointer __end_node() const _NOEXCEPT {
return static_cast<__iter_pointer>(
- pointer_traits<__end_node_ptr>::pointer_to(const_cast<__end_node_t&>(__pair1_.first())));
+ pointer_traits<__end_node_ptr>::pointer_to(const_cast<__end_node_t&>(__end_node_)));
}
- _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __pair1_.second(); }
+ _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __node_alloc_; }
private:
- _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __pair1_.second(); }
+ _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __node_alloc_; }
_LIBCPP_HIDE_FROM_ABI __iter_pointer& __begin_node() _NOEXCEPT { return __begin_node_; }
_LIBCPP_HIDE_FROM_ABI const __iter_pointer& __begin_node() const _NOEXCEPT { return __begin_node_; }
@@ -954,12 +954,12 @@ public:
_LIBCPP_HIDE_FROM_ABI allocator_type __alloc() const _NOEXCEPT { return allocator_type(__node_alloc()); }
private:
- _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __pair3_.first(); }
+ _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
public:
- _LIBCPP_HIDE_FROM_ABI const size_type& size() const _NOEXCEPT { return __pair3_.first(); }
- _LIBCPP_HIDE_FROM_ABI value_compare& value_comp() _NOEXCEPT { return __pair3_.second(); }
- _LIBCPP_HIDE_FROM_ABI const value_compare& value_comp() const _NOEXCEPT { return __pair3_.second(); }
+ _LIBCPP_HIDE_FROM_ABI const size_type& size() const _NOEXCEPT { return __size_; }
+ _LIBCPP_HIDE_FROM_ABI value_compare& value_comp() _NOEXCEPT { return __value_comp_; }
+ _LIBCPP_HIDE_FROM_ABI const value_compare& value_comp() const _NOEXCEPT { return __value_comp_; }
public:
_LIBCPP_HIDE_FROM_ABI __node_pointer __root() const _NOEXCEPT {
@@ -1324,21 +1324,19 @@ private:
template <class _Tp, class _Compare, class _Allocator>
__tree<_Tp, _Compare, _Allocator>::__tree(const value_compare& __comp) _NOEXCEPT_(
is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_copy_constructible<value_compare>::value)
- : __pair3_(0, __comp) {
+ : __size_(0), __value_comp_(__comp) {
__begin_node() = __end_node();
}
template <class _Tp, class _Compare, class _Allocator>
__tree<_Tp, _Compare, _Allocator>::__tree(const allocator_type& __a)
- : __begin_node_(__iter_pointer()),
- __pair1_(__default_init_tag(), __node_allocator(__a)),
- __pair3_(0, __default_init_tag()) {
+ : __begin_node_(__iter_pointer()), __node_alloc_(__node_allocator(__a)), __size_(0) {
__begin_node() = __end_node();
}
template <class _Tp, class _Compare, class _Allocator>
__tree<_Tp, _Compare, _Allocator>::__tree(const value_compare& __comp, const allocator_type& __a)
- : __begin_node_(__iter_pointer()), __pair1_(__default_init_tag(), __node_allocator(__a)), __pair3_(0, __comp) {
+ : __begin_node_(__iter_pointer()), __node_alloc_(__node_allocator(__a)), __size_(0), __value_comp_(__comp) {
__begin_node() = __end_node();
}
@@ -1437,8 +1435,9 @@ void __tree<_Tp, _Compare, _Allocator>::__assign_multi(_InputIterator __first, _
template <class _Tp, class _Compare, class _Allocator>
__tree<_Tp, _Compare, _Allocator>::__tree(const __tree& __t)
: __begin_node_(__iter_pointer()),
- __pair1_(__default_init_tag(), __node_traits::select_on_container_copy_construction(__t.__node_alloc())),
- __pair3_(0, __t.value_comp()) {
+ __node_alloc_(__node_traits::select_on_container_copy_construction(__t.__node_alloc())),
+ __size_(0),
+ __value_comp_(__t.value_comp()) {
__begin_node() = __end_node();
}
@@ -1446,8 +1445,10 @@ template <class _Tp, class _Compare, class _Allocator>
__tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_(
is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<value_compare>::value)
: __begin_node_(std::move(__t.__begin_node_)),
- __pair1_(std::move(__t.__pair1_)),
- __pair3_(std::move(__t.__pair3_)) {
+ __end_node_(std::move(__t.__end_node_)),
+ __node_alloc_(std::move(__t.__node_alloc_)),
+ __size_(__t.__size_),
+ __value_comp_(std::move(__t.__value_comp_)) {
if (size() == 0)
__begin_node() = __end_node();
else {
@@ -1460,7 +1461,7 @@ __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_(
template <class _Tp, class _Compare, class _Allocator>
__tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t, const allocator_type& __a)
- : __pair1_(__default_init_tag(), __node_allocator(__a)), __pair3_(0, std::move(__t.value_comp())) {
+ : __node_alloc_(__node_allocator(__a)), __size_(0), __value_comp_(std::move(__t.value_comp())) {
if (__a == __t.__alloc()) {
if (__t.size() == 0)
__begin_node() = __end_node();
@@ -1482,10 +1483,11 @@ template <class _Tp, class _Compare, class _Allocator>
void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type)
_NOEXCEPT_(is_nothrow_move_assignable<value_compare>::value&& is_nothrow_move_assignable<__node_allocator>::value) {
destroy(static_cast<__node_pointer>(__end_node()->__left_));
- __begin_node_ = __t.__begin_node_;
- __pair1_.first() = __t.__pair1_.first();
+ __begin_node_ = __t.__begin_node_;
+ __end_node_ = __t.__end_node_;
__move_assign_alloc(__t);
- __pair3_ = std::move(__t.__pair3_);
+ __size_ = __t.__size_;
+ __value_comp_ = std::move(__t.__value_comp_);
if (size() == 0)
__begin_node() = __end_node();
else {
@@ -1554,9 +1556,10 @@ void __tree<_Tp, _Compare, _Allocator>::swap(__tree& __t)
{
using std::swap;
swap(__begin_node_, __t.__begin_node_);
- swap(__pair1_.first(), __t.__pair1_.first());
+ swap(__end_node_, __t.__end_node_);
std::__swap_allocator(__node_alloc(), __t.__node_alloc());
- __pair3_.swap(__t.__pair3_);
+ swap(__size_, __t.__size_);
+ swap(__value_comp_, __t.__value_comp_);
if (size() == 0)
__begin_node() = __end_node();
else
diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h
index b4cbd1ddfa8deb..0eb2dace8db4dd 100644
--- a/libcxx/include/__type_traits/datasizeof.h
+++ b/libcxx/include/__type_traits/datasizeof.h
@@ -45,6 +45,9 @@ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
template <class _Tp>
inline const size_t __datasizeof_v = offsetof(_FirstPaddingByte<_Tp>, __first_padding_byte_);
_LIBCPP_DIAGNOSTIC_POP
+
+template <class _Tp>
+inline const size_t __datasizeof_v<_Tp&> = __datasizeof_v<_Tp>;
#endif // __has_extension(datasizeof)
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/deque b/libcxx/include/deque
index 759de5d3a030a6..9ee1761d246478 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -582,12 +582,12 @@ private:
__map __map_;
size_type __start_;
- __compressed_pair<size_type, allocator_type> __size_;
+ _LIBCPP_COMPRESSED_PAIR(size_type, __size_, allocator_type, __alloc_);
public:
// construct/copy/destroy:
_LIBCPP_HIDE_FROM_ABI deque() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __start_(0), __size_(0, __default_init_tag()) {
+ : __start_(0), __size_(0) {
__annotate_new(0);
}
@@ -601,7 +601,7 @@ public:
}
_LIBCPP_HIDE_FROM_ABI explicit deque(const allocator_type& __a)
- : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+ : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
__annotate_new(0);
}
@@ -613,7 +613,7 @@ public:
template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI deque(size_type __n, const value_type& __v, const allocator_type& __a)
- : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+ : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
__annotate_new(0);
if (__n > 0)
__append(__n, __v);
@@ -627,7 +627,7 @@ public:
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<_Tp> _Range>
_LIBCPP_HIDE_FROM_ABI deque(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type())
- : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+ : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
__append_with_size(ranges::begin(__range), ranges::distance(__range));
@@ -690,8 +690,8 @@ public:
_LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const value_type& __v);
_LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT;
- _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __size_.second(); }
- _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __size_.second(); }
+ _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __alloc_; }
+ _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __alloc_; }
// iterators:
@@ -730,8 +730,8 @@ public:
// capacity:
_LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size(); }
- _LIBCPP_HIDE_FROM_ABI size_type& __size() _NOEXCEPT { return __size_.first(); }
- _LIBCPP_HIDE_FROM_ABI const size_type& __size() const _NOEXCEPT { return __size_.first(); }
+ _LIBCPP_HIDE_FROM_ABI size_type& __size() _NOEXCEPT { return __size_; }
+ _LIBCPP_HIDE_FROM_ABI const size_type& __size() const _NOEXCEPT { return __size_; }
_LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
return std::min<size_type>(__alloc_traits::max_size(__alloc()), numeric_limits<difference_type>::max());
@@ -1251,7 +1251,7 @@ deque(from_range_t, _Range&&, _Alloc = _Alloc()) -> deque<ranges::range_value_t<
#endif
template <class _Tp, class _Allocator>
-deque<_Tp, _Allocator>::deque(size_type __n) : __start_(0), __size_(0, __default_init_tag()) {
+deque<_Tp, _Allocator>::deque(size_type __n) : __start_(0), __size_(0) {
__annotate_new(0);
if (__n > 0)
__append(__n);
@@ -1260,7 +1260,7 @@ deque<_Tp, _Allocator>::deque(size_type __n) : __start_(0), __size_(0, __default
#if _LIBCPP_STD_VER >= 14
template <class _Tp, class _Allocator>
deque<_Tp, _Allocator>::deque(size_type __n, const _Allocator& __a)
- : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+ : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
__annotate_new(0);
if (__n > 0)
__append(__n);
@@ -1268,7 +1268,7 @@ deque<_Tp, _Allocator>::deque(size_type __n, const _Allocator& __a)
#endif
template <class _Tp, class _Allocator>
-deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v) : __start_(0), __size_(0, __default_init_tag()) {
+deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v) : __start_(0), __size_(0) {
__annotate_new(0);
if (__n > 0)
__append(__n, __v);
@@ -1276,7 +1276,7 @@ deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v) : __start_(0
template <class _Tp, class _Allocator>
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> >
-deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l) : __start_(0), __size_(0, __default_init_tag()) {
+deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l) : __start_(0), __size_(0) {
__annotate_new(0);
__append(__f, __l);
}
@@ -1284,7 +1284,7 @@ deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l) : __start_(0), __s
template <class _Tp, class _Allocator>
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> >
deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l, const allocator_type& __a)
- : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+ : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
__annotate_new(0);
__append(__f, __l);
}
@@ -1293,14 +1293,15 @@ template <class _Tp, class _Allocator>
deque<_Tp, _Allocator>::deque(const deque& __c)
: __map_(__pointer_allocator(__alloc_traits::select_on_container_copy_construction(__c.__alloc()))),
__start_(0),
- __size_(0, __map_.__alloc()) {
+ __size_(0),
+ __alloc_(__map_.__alloc()) {
__annotate_new(0);
__append(__c.begin(), __c.end());
}
template <class _Tp, class _Allocator>
deque<_Tp, _Allocator>::deque(const deque& __c, const __type_identity_t<allocator_type>& __a)
- : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+ : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
__annotate_new(0);
__append(__c.begin(), __c.end());
}
@@ -1317,21 +1318,24 @@ deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(const deque& __c) {
#ifndef _LIBCPP_CXX03_LANG
template <class _Tp, class _Allocator>
-deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il) : __start_(0), __size_(0, __default_init_tag()) {
+deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il) : __start_(0), __size_(0) {
__annotate_new(0);
__append(__il.begin(), __il.end());
}
template <class _Tp, class _Allocator>
deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il, const allocator_type& __a)
- : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+ : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
__annotate_new(0);
__append(__il.begin(), __il.end());
}
template <class _Tp, class _Allocator>
inline deque<_Tp, _Allocator>::deque(deque&& __c) noexcept(is_nothrow_move_constructible<allocator_type>::value)
- : __map_(std::move(__c.__map_)), __start_(std::move(__c.__start_)), __size_(std::move(__c.__size_)) {
+ : __map_(std::move(__c.__map_)),
+ __start_(std::move(__c.__start_)),
+ __size_(std::move(__c.__size_)),
+ __alloc_(std::move(__c.__alloc_)) {
__c.__start_ = 0;
__c.__size() = 0;
}
@@ -1340,7 +1344,8 @@ template <class _Tp, class _Allocator>
inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t<allocator_type>& __a)
: __map_(std::move(__c.__map_), __pointer_allocator(__a)),
__start_(std::move(__c.__start_)),
- __size_(std::move(__c.__size()), __a) {
+ __size_(std::move(__c.__size_)),
+ __alloc_(__a) {
if (__a == __c.__alloc()) {
__c.__start_ = 0;
__c.__size() = 0;
diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index 6c0dc5f96a5d5e..719c5cedd80fc6 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -228,6 +228,7 @@ template <class T, class Allocator, class Predicate>
#include <__type_traits/type_identity.h>
#include <__utility/forward.h>
#include <__utility/move.h>
+#include <__utility/swap.h>
#include <limits>
#include <new> // __launder
#include <version>
@@ -490,27 +491,27 @@ protected:
typedef __rebind_alloc<allocator_traits<allocator_type>, __begin_node> __begin_node_allocator;
typedef typename allocator_traits<__begin_node_allocator>::pointer __begin_node_pointer;
- __compressed_pair<__begin_node, __node_allocator> __before_begin_;
+ _LIBCPP_COMPRESSED_PAIR(__begin_node, __before_begin_, __node_allocator, __alloc_);
_LIBCPP_HIDE_FROM_ABI __begin_node_pointer __before_begin() _NOEXCEPT {
- return pointer_traits<__begin_node_pointer>::pointer_to(__before_begin_.first());
+ return pointer_traits<__begin_node_pointer>::pointer_to(__before_begin_);
}
_LIBCPP_HIDE_FROM_ABI __begin_node_pointer __before_begin() const _NOEXCEPT {
- return pointer_traits<__begin_node_pointer>::pointer_to(const_cast<__begin_node&>(__before_begin_.first()));
+ return pointer_traits<__begin_node_pointer>::pointer_to(const_cast<__begin_node&>(__before_begin_));
}
- _LIBCPP_HIDE_FROM_ABI __node_allocator& __alloc() _NOEXCEPT { return __before_begin_.second(); }
- _LIBCPP_HIDE_FROM_ABI const __node_allocator& __alloc() const _NOEXCEPT { return __before_begin_.second(); }
+ _LIBCPP_HIDE_FROM_ABI __node_allocator& __alloc() _NOEXCEPT { return __alloc_; }
+ _LIBCPP_HIDE_FROM_ABI const __node_allocator& __alloc() const _NOEXCEPT { return __alloc_; }
typedef __forward_list_iterator<__node_pointer> iterator;
typedef __forward_list_const_iterator<__node_pointer> const_iterator;
_LIBCPP_HIDE_FROM_ABI __forward_list_base() _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value)
- : __before_begin_(__begin_node(), __default_init_tag()) {}
+ : __before_begin_(__begin_node()) {}
_LIBCPP_HIDE_FROM_ABI explicit __forward_list_base(const allocator_type& __a)
- : __before_begin_(__begin_node(), __node_allocator(__a)) {}
+ : __before_begin_(__begin_node()), __alloc_(__node_allocator(__a)) {}
_LIBCPP_HIDE_FROM_ABI explicit __forward_list_base(const __node_allocator& __a)
- : __before_begin_(__begin_node(), __a) {}
+ : __before_begin_(__begin_node()), __alloc_(__a) {}
public:
#ifndef _LIBCPP_CXX03_LANG
@@ -592,13 +593,13 @@ private:
template <class _Tp, class _Alloc>
inline __forward_list_base<_Tp, _Alloc>::__forward_list_base(__forward_list_base&& __x) noexcept(
is_nothrow_move_constructible<__node_allocator>::value)
- : __before_begin_(std::move(__x.__before_begin_)) {
+ : __before_begin_(std::move(__x.__before_begin_)), __alloc_(std::move(__x.__alloc_)) {
__x.__before_begin()->__next_ = nullptr;
}
template <class _Tp, class _Alloc>
inline __forward_list_base<_Tp, _Alloc>::__forward_list_base(__forward_list_base&& __x, const allocator_type& __a)
- : __before_begin_(__begin_node(), __node_allocator(__a)) {
+ : __before_begin_(__begin_node()), __alloc_(__node_allocator(__a)) {
if (__alloc() == __x.__alloc()) {
__before_begin()->__next_ = __x.__before_begin()->__next_;
__x.__before_begin()->__next_ = nullptr;
diff --git a/libcxx/include/future b/libcxx/include/future
index 0be32620139e37..4963f5ea72054e 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -1399,13 +1399,13 @@ class __packaged_task_func;
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
class __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)> : public __packaged_task_base<_Rp(_ArgTypes...)> {
- __compressed_pair<_Fp, _Alloc> __f_;
+ _LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Alloc, __alloc_);
public:
- _LIBCPP_HIDE_FROM_ABI explicit __packaged_task_func(const _Fp& __f) : __f_(__f, __default_init_tag()) {}
- _LIBCPP_HIDE_FROM_ABI explicit __packaged_task_func(_Fp&& __f) : __f_(std::move(__f), __default_init_tag()) {}
- _LIBCPP_HIDE_FROM_ABI __packaged_task_func(const _Fp& __f, const _Alloc& __a) : __f_(__f, __a) {}
- _LIBCPP_HIDE_FROM_ABI __packaged_task_func(_Fp&& __f, const _Alloc& __a) : __f_(std::move(__f), __a) {}
+ _LIBCPP_HIDE_FROM_ABI explicit __packaged_task_func(const _Fp& __f) : __func_(__f) {}
+ _LIBCPP_HIDE_FROM_ABI explicit __packaged_task_func(_Fp&& __f) : __func_(std::move(__f)) {}
+ _LIBCPP_HIDE_FROM_ABI __packaged_task_func(const _Fp& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {}
+ _LIBCPP_HIDE_FROM_ABI __packaged_task_func(_Fp&& __f, const _Alloc& __a) : __func_(std::move(__f)), __alloc_(__a) {}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __move_to(__packaged_task_base<_Rp(_ArgTypes...)>*) _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy();
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy_deallocate();
@@ -1415,12 +1415,13 @@ public:
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
void __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::__move_to(
__packaged_task_base<_Rp(_ArgTypes...)>* __p) _NOEXCEPT {
- ::new ((void*)__p) __packaged_task_func(std::move(__f_.first()), std::move(__f_.second()));
+ ::new ((void*)__p) __packaged_task_func(std::move(__func_), std::move(__alloc_));
}
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
void __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy() {
- __f_.~__compressed_pair<_Fp, _Alloc>();
+ __func_.~_Fp();
+ __alloc_.~_Alloc();
}
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
@@ -1428,14 +1429,15 @@ void __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy_deallocate()
typedef typename __allocator_traits_rebind<_Alloc, __packaged_task_func>::type _Ap;
typedef allocator_traits<_Ap> _ATraits;
typedef pointer_traits<typename _ATraits::pointer> _PTraits;
- _Ap __a(__f_.second());
- __f_.~__compressed_pair<_Fp, _Alloc>();
+ _Ap __a(__alloc_);
+ __func_.~_Fp();
+ __alloc_.~_Alloc();
__a.deallocate(_PTraits::pointer_to(*this), 1);
}
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
_Rp __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::operator()(_ArgTypes&&... __arg) {
- return std::__invoke(__f_.first(), std::forward<_ArgTypes>(__arg)...);
+ return std::__invoke(__func_, std::forward<_ArgTypes>(__arg)...);
}
template <class _Callable>
diff --git a/libcxx/include/list b/libcxx/include/list
index 76b1d9241b41ca..af00de12fa7a6b 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -497,16 +497,16 @@ protected:
"internal allocator type must differ from user-specified type; otherwise overload resolution breaks");
__node_base __end_;
- __compressed_pair<size_type, __node_allocator> __size_alloc_;
+ _LIBCPP_COMPRESSED_PAIR(size_type, __size_, __node_allocator, __node_alloc_);
_LIBCPP_HIDE_FROM_ABI __link_pointer __end_as_link() const _NOEXCEPT {
return __node_pointer_traits::__unsafe_link_pointer_cast(const_cast<__node_base&>(__end_).__self());
}
- _LIBCPP_HIDE_FROM_ABI size_type& __sz() _NOEXCEPT { return __size_alloc_.first(); }
- _LIBCPP_HIDE_FROM_ABI const size_type& __sz() const _NOEXCEPT { return __size_alloc_.first(); }
- _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __size_alloc_.second(); }
- _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __size_alloc_.second(); }
+ _LIBCPP_HIDE_FROM_ABI size_type& __sz() _NOEXCEPT { return __size_; }
+ _LIBCPP_HIDE_FROM_ABI const size_type& __sz() const _NOEXCEPT { return __size_; }
+ _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __node_alloc_; }
+ _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __node_alloc_; }
_LIBCPP_HIDE_FROM_ABI size_type __node_alloc_max_size() const _NOEXCEPT {
return __node_alloc_traits::max_size(__node_alloc());
@@ -600,17 +600,20 @@ inline void __list_imp<_Tp, _Alloc>::__unlink_nodes(__link_pointer __f, __link_p
template <class _Tp, class _Alloc>
inline __list_imp<_Tp, _Alloc>::__list_imp() _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value)
- : __size_alloc_(0, __default_init_tag()) {}
+ : __size_(0) {}
template <class _Tp, class _Alloc>
-inline __list_imp<_Tp, _Alloc>::__list_imp(const allocator_type& __a) : __size_alloc_(0, __node_allocator(__a)) {}
+inline __list_imp<_Tp, _Alloc>::__list_imp(const allocator_type& __a)
+ : __size_(0), __node_alloc_(__node_allocator(__a)) {}
template <class _Tp, class _Alloc>
-inline __list_imp<_Tp, _Alloc>::__list_imp(const __node_allocator& __a) : __size_alloc_(0, __a) {}
+inline __list_imp<_Tp, _Alloc>::__list_imp(const __node_allocator& __a) : __size_(0), __node_alloc_(__a) {}
#ifndef _LIBCPP_CXX03_LANG
template <class _Tp, class _Alloc>
-inline __list_imp<_Tp, _Alloc>::__list_imp(__node_allocator&& __a) _NOEXCEPT : __size_alloc_(0, std::move(__a)) {}
+inline __list_imp<_Tp, _Alloc>::__list_imp(__node_allocator&& __a) _NOEXCEPT
+ : __size_(0),
+ __node_alloc_(std::move(__a)) {}
#endif
template <class _Tp, class _Alloc>
diff --git a/libcxx/include/string b/libcxx/include/string
index 5cb0693ad10bc3..c62093ce76c9d7 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -917,18 +917,18 @@ private:
__long __l;
};
- __compressed_pair<__rep, allocator_type> __r_;
+ _LIBCPP_COMPRESSED_PAIR(__rep, __rep_, allocator_type, __alloc_);
// Construct a string with the given allocator and enough storage to hold `__size` characters, but
// don't initialize the characters. The contents of the string, including the null terminator, must be
// initialized separately.
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(
__uninitialized_size_tag, size_type __size, const allocator_type& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
if (__size > max_size())
__throw_length_error();
if (__fits_in_sso(__size)) {
- __r_.first() = __rep();
+ __rep_ = __rep();
__set_short_size(__size);
} else {
auto __capacity = __recommend(__size) + 1;
@@ -944,7 +944,7 @@ private:
template <class _Iter, class _Sent>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string(__init_with_sentinel_tag, _Iter __first, _Sent __last, const allocator_type& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
__init_with_sentinel(std::move(__first), std::move(__last));
}
@@ -982,7 +982,7 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __r_(__value_init_tag(), __default_init_tag()) {
+ : __rep_() {
__annotate_new(0);
}
@@ -992,14 +992,14 @@ public:
#else
_NOEXCEPT
#endif
- : __r_(__value_init_tag(), __a) {
+ : __rep_(), __alloc_(__a) {
__annotate_new(0);
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str)
- : __r_(__default_init_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) {
+ : __alloc_(__alloc_traits::select_on_container_copy_construction(__str.__alloc())) {
if (!__str.__is_long()) {
- __r_.first() = __str.__r_.first();
+ __rep_ = __str.__rep_;
__annotate_new(__get_short_size());
} else
__init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
@@ -1007,9 +1007,9 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
basic_string(const basic_string& __str, const allocator_type& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
if (!__str.__is_long()) {
- __r_.first() = __str.__r_.first();
+ __rep_ = __str.__rep_;
__annotate_new(__get_short_size());
} else
__init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
@@ -1025,28 +1025,29 @@ public:
// Turning off ASan instrumentation for variable initialization with _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
// does not work consistently during initialization of __r_, so we instead unpoison __str's memory manually first.
// __str's memory needs to be unpoisoned only in the case where it's a short string.
- : __r_([](basic_string& __s) -> decltype(__s.__r_)&& {
+ : __rep_([](basic_string& __s) -> decltype(__s.__rep_)&& {
if (!__s.__is_long())
__s.__annotate_delete();
- return std::move(__s.__r_);
- }(__str)) {
- __str.__r_.first() = __rep();
+ return std::move(__s.__rep_);
+ }(__str)),
+ __alloc_(std::move(__str.__alloc_)) {
+ __str.__rep_ = __rep();
__str.__annotate_new(0);
if (!__is_long())
__annotate_new(size());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str, const allocator_type& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
if (__str.__is_long() && __a != __str.__alloc()) // copy, not move
__init(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
else {
if (__libcpp_is_constant_evaluated())
- __r_.first() = __rep();
+ __rep_ = __rep();
if (!__str.__is_long())
__str.__annotate_delete();
- __r_.first() = __str.__r_.first();
- __str.__r_.first() = __rep();
+ __rep_ = __str.__rep_;
+ __str.__rep_ = __rep();
__str.__annotate_new(0);
if (!__is_long() && this != std::addressof(__str))
__annotate_new(size());
@@ -1055,15 +1056,14 @@ public:
#endif // _LIBCPP_CXX03_LANG
template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s)
- : __r_(__default_init_tag(), __default_init_tag()) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s) {
_LIBCPP_ASSERT_NON_NULL(__s != nullptr, "basic_string(const char*) detected nullptr");
__init(__s, traits_type::length(__s));
}
template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, const _Allocator& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
_LIBCPP_ASSERT_NON_NULL(__s != nullptr, "basic_string(const char*, allocator) detected nullptr");
__init(__s, traits_type::length(__s));
}
@@ -1072,23 +1072,19 @@ public:
basic_string(nullptr_t) = delete;
#endif
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, size_type __n)
- : __r_(__default_init_tag(), __default_init_tag()) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, size_type __n) {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr");
__init(__s, __n);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string(const _CharT* __s, size_type __n, const _Allocator& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
_LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "basic_string(const char*, n, allocator) detected nullptr");
__init(__s, __n);
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c)
- : __r_(__default_init_tag(), __default_init_tag()) {
- __init(__n, __c);
- }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c) { __init(__n, __c); }
#if _LIBCPP_STD_VER >= 23
_LIBCPP_HIDE_FROM_ABI constexpr basic_string(
@@ -1097,7 +1093,7 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr basic_string(
basic_string&& __str, size_type __pos, size_type __n, const _Allocator& __alloc = _Allocator())
- : __r_(__default_init_tag(), __alloc) {
+ : __alloc_(__alloc) {
if (__pos > __str.size())
__throw_out_of_range();
@@ -1113,13 +1109,13 @@ public:
template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c, const _Allocator& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
__init(__n, __c);
}
_LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string(const basic_string& __str, size_type __pos, size_type __n, const _Allocator& __a = _Allocator())
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
size_type __str_sz = __str.size();
if (__pos > __str_sz)
__throw_out_of_range();
@@ -1128,7 +1124,7 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string(const basic_string& __str, size_type __pos, const _Allocator& __a = _Allocator())
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
size_type __str_sz = __str.size();
if (__pos > __str_sz)
__throw_out_of_range();
@@ -1141,7 +1137,7 @@ public:
int> = 0>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string(const _Tp& __t, size_type __pos, size_type __n, const allocator_type& __a = allocator_type())
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
__self_view __sv0 = __t;
__self_view __sv = __sv0.substr(__pos, __n);
__init(__sv.data(), __sv.size());
@@ -1151,8 +1147,8 @@ public:
__enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value &&
!__is_same_uncvref<_Tp, basic_string>::value,
int> = 0>
- _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t)
- : __r_(__default_init_tag(), __default_init_tag()) {
+ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t) {
__self_view __sv = __t;
__init(__sv.data(), __sv.size());
}
@@ -1163,21 +1159,20 @@ public:
int> = 0>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
_LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t, const allocator_type& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
__self_view __sv = __t;
__init(__sv.data(), __sv.size());
}
template <class _InputIterator, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(_InputIterator __first, _InputIterator __last)
- : __r_(__default_init_tag(), __default_init_tag()) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(_InputIterator __first, _InputIterator __last) {
__init(__first, __last);
}
template <class _InputIterator, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
__init(__first, __last);
}
@@ -1185,7 +1180,7 @@ public:
template <_ContainerCompatibleRange<_CharT> _Range>
_LIBCPP_HIDE_FROM_ABI constexpr basic_string(
from_range_t, _Range&& __range, const allocator_type& __a = allocator_type())
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
__init_with_size(ranges::begin(__range), ranges::end(__range), ranges::distance(__range));
} else {
@@ -1195,13 +1190,12 @@ public:
#endif
#ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(initializer_list<_CharT> __il)
- : __r_(__default_init_tag(), __default_init_tag()) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(initializer_list<_CharT> __il) {
__init(__il.begin(), __il.end());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(initializer_list<_CharT> __il, const _Allocator& __a)
- : __r_(__default_init_tag(), __a) {
+ : __alloc_(__a) {
__init(__il.begin(), __il.end());
}
#endif // _LIBCPP_CXX03_LANG
@@ -1466,8 +1460,8 @@ public:
size_type __old_sz = __str.size();
if (!__str.__is_long())
__str.__annotate_delete();
- __r_.first() = __str.__r_.first();
- __str.__r_.first() = __rep();
+ __rep_ = __str.__rep_;
+ __str.__rep_ = __rep();
__str.__annotate_new(0);
_Traits::move(data(), data() + __pos, __len);
@@ -1874,10 +1868,10 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
__is_long() const _NOEXCEPT {
- if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__r_.first().__l.__is_long_)) {
- return __r_.first().__l.__is_long_;
+ if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__rep_.__l.__is_long_)) {
+ return __rep_.__l.__is_long_;
}
- return __r_.first().__s.__is_long_;
+ return __rep_.__s.__is_long_;
}
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __begin_lifetime(pointer __begin, size_type __n) {
@@ -1946,27 +1940,27 @@ private:
_LIBCPP_CONSTEXPR_SINCE_CXX20 iterator
__insert_with_size(const_iterator __pos, _Iterator __first, _Sentinel __last, size_type __n);
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __r_.second(); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __r_.second(); }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __alloc_; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __alloc_; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void
__set_short_size(size_type __s) _NOEXCEPT {
_LIBCPP_ASSERT_INTERNAL(__s < __min_cap, "__s should never be greater than or equal to the short string capacity");
- __r_.first().__s.__size_ = __s;
- __r_.first().__s.__is_long_ = false;
+ __rep_.__s.__size_ = __s;
+ __rep_.__s.__is_long_ = false;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS size_type
__get_short_size() const _NOEXCEPT {
- _LIBCPP_ASSERT_INTERNAL(!__r_.first().__s.__is_long_, "String has to be short when trying to get the short size");
- return __r_.first().__s.__size_;
+ _LIBCPP_ASSERT_INTERNAL(!__rep_.__s.__is_long_, "String has to be short when trying to get the short size");
+ return __rep_.__s.__size_;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_size(size_type __s) _NOEXCEPT {
- __r_.first().__l.__size_ = __s;
+ __rep_.__l.__size_ = __s;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_size() const _NOEXCEPT {
- return __r_.first().__l.__size_;
+ return __rep_.__l.__size_;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_size(size_type __s) _NOEXCEPT {
if (__is_long())
@@ -1976,31 +1970,36 @@ private:
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_cap(size_type __s) _NOEXCEPT {
- __r_.first().__l.__cap_ = __s / __endian_factor;
- __r_.first().__l.__is_long_ = true;
+ __rep_.__l.__cap_ = __s / __endian_factor;
+ __rep_.__l.__is_long_ = true;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_cap() const _NOEXCEPT {
- return __r_.first().__l.__cap_ * __endian_factor;
+ return __rep_.__l.__cap_ * __endian_factor;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_pointer(pointer __p) _NOEXCEPT {
- __r_.first().__l.__data_ = __p;
+ __rep_.__l.__data_ = __p;
}
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_long_pointer() _NOEXCEPT {
- return _LIBCPP_ASAN_VOLATILE_WRAPPER(__r_.first().__l.__data_);
+ return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_);
}
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer __get_long_pointer() const _NOEXCEPT {
- return _LIBCPP_ASAN_VOLATILE_WRAPPER(__r_.first().__l.__data_);
+ return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_);
}
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS pointer
__get_short_pointer() _NOEXCEPT {
- return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<pointer>::pointer_to(__r_.first().__s.__data_[0]));
+ return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<pointer>::pointer_to(__rep_.__s.__data_[0]));
}
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS const_pointer
__get_short_pointer() const _NOEXCEPT {
- return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<const_pointer>::pointer_to(__r_.first().__s.__data_[0]));
+ return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<const_pointer>::pointer_to(__rep_.__s.__data_[0]));
}
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_pointer() _NOEXCEPT {
return __is_long() ? __get_long_pointer() : __get_short_pointer();
}
@@ -2305,7 +2304,7 @@ template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve) {
if (__libcpp_is_constant_evaluated())
- __r_.first() = __rep();
+ __rep_ = __rep();
if (__reserve > max_size())
__throw_length_error();
pointer __p;
@@ -2329,7 +2328,7 @@ template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz) {
if (__libcpp_is_constant_evaluated())
- __r_.first() = __rep();
+ __rep_ = __rep();
if (__sz > max_size())
__throw_length_error();
pointer __p;
@@ -2353,7 +2352,7 @@ template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void
basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(const value_type* __s, size_type __sz) {
if (__libcpp_is_constant_evaluated())
- __r_.first() = __rep();
+ __rep_ = __rep();
pointer __p;
if (__fits_in_sso(__sz)) {
@@ -2376,7 +2375,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(const value
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c) {
if (__libcpp_is_constant_evaluated())
- __r_.first() = __rep();
+ __rep_ = __rep();
if (__n > max_size())
__throw_length_error();
@@ -2408,7 +2407,7 @@ template <class _CharT, class _Traits, class _Allocator>
template <class _InputIterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator __first, _Sentinel __last) {
- __r_.first() = __rep();
+ __rep_ = __rep();
__annotate_new(0);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
@@ -2439,7 +2438,7 @@ template <class _InputIterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
basic_string<_CharT, _Traits, _Allocator>::__init_with_size(_InputIterator __first, _Sentinel __last, size_type __sz) {
if (__libcpp_is_constant_evaluated())
- __r_.first() = __rep();
+ __rep_ = __rep();
if (__sz > max_size())
__throw_length_error();
@@ -2659,7 +2658,7 @@ basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str)
size_type __old_size = __get_short_size();
if (__get_short_size() < __str.__get_short_size())
__annotate_increase(__str.__get_short_size() - __get_short_size());
- __r_.first() = __str.__r_.first();
+ __rep_ = __str.__rep_;
if (__old_size > __get_short_size())
__annotate_shrink(__old_size);
} else {
@@ -2707,7 +2706,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
bool __str_was_short = !__str.__is_long();
__move_assign_alloc(__str);
- __r_.first() = __str.__r_.first();
+ __rep_ = __str.__rep_;
__str.__set_short_size(0);
traits_type::assign(__str.__get_short_pointer()[0], value_type());
@@ -3452,7 +3451,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
__annotate_delete();
if (this != std::addressof(__str) && !__str.__is_long())
__str.__annotate_delete();
- std::swap(__r_.first(), __str.__r_.first());
+ std::swap(__rep_, __str.__rep_);
std::__swap_allocator(__alloc(), __str.__alloc());
if (!__is_long())
__annotate_new(__get_short_size());
@@ -3807,7 +3806,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
if (__is_long()) {
__annotate_delete();
__alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1);
- __r_.first() = __rep();
+ __rep_ = __rep();
}
}
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 2442852c764a63..50ccf3d9c308d5 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -434,7 +434,7 @@ public:
#else
noexcept
#endif
- : __end_cap_(nullptr, __a) {
+ : __alloc_(__a) {
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n) {
@@ -448,7 +448,7 @@ public:
#if _LIBCPP_STD_VER >= 14
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n, const allocator_type& __a)
- : __end_cap_(nullptr, __a) {
+ : __alloc_(__a) {
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
if (__n > 0) {
__vallocate(__n);
@@ -470,7 +470,7 @@ public:
template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(size_type __n, const value_type& __x, const allocator_type& __a)
- : __end_cap_(nullptr, __a) {
+ : __alloc_(__a) {
if (__n > 0) {
__vallocate(__n);
__construct_at_end(__n, __x);
@@ -508,7 +508,7 @@ public:
template <_ContainerCompatibleRange<_Tp> _Range>
_LIBCPP_HIDE_FROM_ABI constexpr vector(
from_range_t, _Range&& __range, const allocator_type& __alloc = allocator_type())
- : __end_cap_(nullptr, __alloc) {
+ : __alloc_(__alloc) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
__init_with_size(ranges::begin(__range), ranges::end(__range), __n);
@@ -764,8 +764,7 @@ public:
private:
pointer __begin_ = nullptr;
pointer __end_ = nullptr;
- __compressed_pair<pointer, allocator_type> __end_cap_ =
- __compressed_pair<pointer, allocator_type>(nullptr, __default_init_tag());
+ _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_);
// Allocate space for __n objects
// throws length_error if __n > max_size()
@@ -961,17 +960,14 @@ private:
++__tx.__pos_;
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT {
- return this->__end_cap_.second();
- }
+ // TODO: Remove these now redundant accessors
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return this->__alloc_; }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT {
- return this->__end_cap_.second();
- }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT {
- return this->__end_cap_.first();
+ return this->__alloc_;
}
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return this->__cap_; }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT {
- return this->__end_cap_.first();
+ return this->__cap_;
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __clear() _NOEXCEPT {
@@ -1205,7 +1201,7 @@ template <class _InputIterator,
int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
- : __end_cap_(nullptr, __a) {
+ : __alloc_(__a) {
__init_with_sentinel(__first, __last);
}
@@ -1226,21 +1222,21 @@ template <class _ForwardIterator,
int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
- : __end_cap_(nullptr, __a) {
+ : __alloc_(__a) {
size_type __n = static_cast<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(const vector& __x)
- : __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc())) {
+ : __alloc_(__alloc_traits::select_on_container_copy_construction(__x.__alloc())) {
__init_with_size(__x.__begin_, __x.__end_, __x.size());
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
- : __end_cap_(nullptr, __a) {
+ : __alloc_(__a) {
__init_with_size(__x.__begin_, __x.__end_, __x.size());
}
@@ -1251,7 +1247,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
#endif
- : __end_cap_(nullptr, std::move(__x.__alloc())) {
+ : __alloc_(std::move(__x.__alloc())) {
this->__begin_ = __x.__begin_;
this->__end_ = __x.__end_;
this->__end_cap() = __x.__end_cap();
@@ -1261,7 +1257,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI
vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
- : __end_cap_(nullptr, __a) {
+ : __alloc_(__a) {
if (__a == __x.__alloc()) {
this->__begin_ = __x.__begin_;
this->__end_ = __x.__end_;
@@ -1291,7 +1287,7 @@ vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il) {
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
- : __end_cap_(nullptr, __a) {
+ : __alloc_(__a) {
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
if (__il.size() > 0) {
__vallocate(__il.size());
@@ -1878,7 +1874,7 @@ private:
__storage_pointer __begin_;
size_type __size_;
- __compressed_pair<size_type, __storage_allocator> __cap_alloc_;
+ _LIBCPP_COMPRESSED_PAIR(size_type, __cap_, __storage_allocator, __alloc_);
public:
typedef __bit_reference<vector> reference;
@@ -1889,15 +1885,12 @@ public:
#endif
private:
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type& __cap() _NOEXCEPT { return __cap_alloc_.first(); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const size_type& __cap() const _NOEXCEPT {
- return __cap_alloc_.first();
- }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __storage_allocator& __alloc() _NOEXCEPT {
- return __cap_alloc_.second();
- }
+ // TODO: Remove these now redundant accessors
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type& __cap() _NOEXCEPT { return __cap_; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const size_type& __cap() const _NOEXCEPT { return __cap_; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __storage_allocator& __alloc() _NOEXCEPT { return __alloc_; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const __storage_allocator& __alloc() const _NOEXCEPT {
- return __cap_alloc_.second();
+ return __alloc_;
}
static const unsigned __bits_per_word = static_cast<unsigned>(sizeof(__storage_type) * CHAR_BIT);
@@ -1960,7 +1953,7 @@ public:
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<bool> _Range>
_LIBCPP_HIDE_FROM_ABI constexpr vector(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type())
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
__init_with_size(ranges::begin(__range), ranges::end(__range), __n);
@@ -2365,7 +2358,7 @@ vector<bool, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel _
template <class _Allocator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {}
+ : __begin_(nullptr), __size_(0), __cap_(0) {}
template <class _Allocator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const allocator_type& __a)
@@ -2374,12 +2367,12 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocat
#else
_NOEXCEPT
#endif
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
}
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+ : __begin_(nullptr), __size_(0), __cap_(0) {
if (__n > 0) {
__vallocate(__n);
__construct_at_end(__n, false);
@@ -2389,7 +2382,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n)
#if _LIBCPP_STD_VER >= 14
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, const allocator_type& __a)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
if (__n > 0) {
__vallocate(__n);
__construct_at_end(__n, false);
@@ -2399,7 +2392,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, const value_type& __x)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+ : __begin_(nullptr), __size_(0), __cap_(0) {
if (__n > 0) {
__vallocate(__n);
__construct_at_end(__n, __x);
@@ -2409,7 +2402,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const allocator_type& __a)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
if (__n > 0) {
__vallocate(__n);
__construct_at_end(__n, __x);
@@ -2419,7 +2412,7 @@ vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const all
template <class _Allocator>
template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+ : __begin_(nullptr), __size_(0), __cap_(0) {
__init_with_sentinel(__first, __last);
}
@@ -2427,14 +2420,14 @@ template <class _Allocator>
template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
__init_with_sentinel(__first, __last);
}
template <class _Allocator>
template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+ : __begin_(nullptr), __size_(0), __cap_(0) {
auto __n = static_cast<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
@@ -2443,7 +2436,7 @@ template <class _Allocator>
template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
auto __n = static_cast<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
@@ -2452,7 +2445,7 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(initializer_list<value_type> __il)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+ : __begin_(nullptr), __size_(0), __cap_(0) {
size_type __n = static_cast<size_type>(__il.size());
if (__n > 0) {
__vallocate(__n);
@@ -2463,7 +2456,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(initializer_list<
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
size_type __n = static_cast<size_type>(__il.size());
if (__n > 0) {
__vallocate(__n);
@@ -2477,7 +2470,8 @@ template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v)
: __begin_(nullptr),
__size_(0),
- __cap_alloc_(0, __storage_traits::select_on_container_copy_construction(__v.__alloc())) {
+ __cap_(0),
+ __alloc_(__storage_traits::select_on_container_copy_construction(__v.__alloc())) {
if (__v.size() > 0) {
__vallocate(__v.size());
__construct_at_end(__v.begin(), __v.end(), __v.size());
@@ -2486,7 +2480,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v, const allocator_type& __a)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, __a) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(__a) {
if (__v.size() > 0) {
__vallocate(__v.size());
__construct_at_end(__v.begin(), __v.end(), __v.size());
@@ -2518,7 +2512,8 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocat
#endif
: __begin_(__v.__begin_),
__size_(__v.__size_),
- __cap_alloc_(std::move(__v.__cap_alloc_)) {
+ __cap_(__v.__cap_),
+ __alloc_(std::move(__v.__alloc_)) {
__v.__begin_ = nullptr;
__v.__size_ = 0;
__v.__cap() = 0;
@@ -2527,7 +2522,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocat
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<bool, _Allocator>::vector(vector&& __v, const __type_identity_t<allocator_type>& __a)
- : __begin_(nullptr), __size_(0), __cap_alloc_(0, __a) {
+ : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(__a) {
if (__a == allocator_type(__v.__alloc())) {
this->__begin_ = __v.__begin_;
this->__size_ = __v.__size_;
diff --git a/libcxx/test/libcxx/containers/associative/unord.map/abi.compile.pass.cpp b/libcxx/test/libcxx/containers/associative/unord.map/abi.compile.pass.cpp
index c8e5ba0ec899eb..9147ca93866b23 100644
--- a/libcxx/test/libcxx/containers/associative/unord.map/abi.compile.pass.cpp
+++ b/libcxx/test/libcxx/containers/associative/unord.map/abi.compile.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: libcpp-has-abi-fix-unordered-container-size-type
+// UNSUPPORTED: libcpp-has-abi-fix-unordered-container-size-type, libcpp-abi-no-compressed-pair-padding
#include <cstdint>
#include <unordered_map>
@@ -93,7 +93,8 @@ static_assert(TEST_ALIGNOF(unordered_map_alloc<char, final_small_iter_allocator<
struct TEST_ALIGNAS(32) AlignedHash {};
struct UnalignedEqualTo {};
-static_assert(sizeof(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 96, "");
+// This part of the ABI has been broken between LLVM 19 and LLVM 20.
+static_assert(sizeof(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 64, "");
static_assert(TEST_ALIGNOF(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 32, "");
#elif __SIZE_WIDTH__ == 32
@@ -126,7 +127,7 @@ static_assert(TEST_ALIGNOF(unordered_map_alloc<char, final_small_iter_allocator<
struct TEST_ALIGNAS(32) AlignedHash {};
struct UnalignedEqualTo {};
-static_assert(sizeof(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 96);
+static_assert(sizeof(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 64);
static_assert(TEST_ALIGNOF(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 32);
#else
diff --git a/libcxx/test/libcxx/containers/associative/unord.set/abi.compile.pass.cpp b/libcxx/test/libcxx/containers/associative/unord.set/abi.compile.pass.cpp
index 359e248ff7a4f0..dc6cc082c3b99e 100644
--- a/libcxx/test/libcxx/containers/associative/unord.set/abi.compile.pass.cpp
+++ b/libcxx/test/libcxx/containers/associative/unord.set/abi.compile.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: libcpp-has-abi-fix-unordered-container-size-type
+// UNSUPPORTED: libcpp-has-abi-fix-unordered-container-size-type, libcpp-abi-no-compressed-pair-padding
#include <cstdint>
#include <unordered_set>
@@ -92,7 +92,8 @@ static_assert(TEST_ALIGNOF(unordered_set_alloc<char, final_small_iter_allocator<
struct TEST_ALIGNAS(32) AlignedHash {};
struct UnalignedEqualTo {};
-static_assert(sizeof(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 96, "");
+// This part of the ABI has been broken between LLVM 19 and LLVM 20.
+static_assert(sizeof(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 64, "");
static_assert(TEST_ALIGNOF(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 32, "");
#elif __SIZE_WIDTH__ == 32
@@ -124,7 +125,7 @@ static_assert(TEST_ALIGNOF(unordered_set_alloc<char, final_small_iter_allocator<
struct TEST_ALIGNAS(32) AlignedHash {};
struct UnalignedEqualTo {};
-static_assert(sizeof(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 96);
+static_assert(sizeof(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 64);
static_assert(TEST_ALIGNOF(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 32);
#else
diff --git a/libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp
index 7d2dd218f967b2..30586d8b2422c5 100644
--- a/libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: libcpp-abi-no-compressed-pair-padding
+
#include <cstdint>
#include <deque>
diff --git a/libcxx/test/libcxx/containers/sequences/vector.bool/abi.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector.bool/abi.compile.pass.cpp
index 48337a0c5cc1b7..6e6ea67d9742b3 100644
--- a/libcxx/test/libcxx/containers/sequences/vector.bool/abi.compile.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector.bool/abi.compile.pass.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: libcpp-abi-no-compressed-pair-padding
+
#include <vector>
#include "min_allocator.h"
diff --git a/libcxx/test/libcxx/containers/unord/unord.set/missing_hash_specialization.verify.cpp b/libcxx/test/libcxx/containers/unord/unord.set/missing_hash_specialization.verify.cpp
index f492b760edf26a..f6d93c7e6ca573 100644
--- a/libcxx/test/libcxx/containers/unord/unord.set/missing_hash_specialization.verify.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.set/missing_hash_specialization.verify.cpp
@@ -48,11 +48,10 @@ int main(int, char**) {
using Set = std::unordered_set<VT>;
Set s; // expected-error at __hash_table:* {{the specified hash does not meet the Hash requirements}}
-
- // FIXME: It would be great to suppress the below diagnostic all together.
- // but for now it's sufficient that it appears last. However there is
- // currently no way to test the order diagnostics are issued.
- // expected-error@*:* {{call to implicitly-deleted default constructor of 'std::}}
+ // FIXME: It would be great to suppress the below diagnostic all together.
+ // but for now it's sufficient that it appears last. However there is
+ // currently no way to test the order diagnostics are issued.
+ // expected-error@*:* {{call to implicitly-deleted default constructor}}
}
{
using Set = std::unordered_set<int, BadHashNoCopy>;
diff --git a/libcxx/test/libcxx/memory/compressed_pair/compressed_pair.pass.cpp b/libcxx/test/libcxx/memory/compressed_pair/compressed_pair.pass.cpp
deleted file mode 100644
index 4258089813e0d4..00000000000000
--- a/libcxx/test/libcxx/memory/compressed_pair/compressed_pair.pass.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include <__memory/compressed_pair.h>
-#include <assert.h>
-#include <new>
-
-#include "test_macros.h"
-
-typedef std::__compressed_pair<int, unsigned> IntPair;
-
-void test_constructor() {
- IntPair value;
- assert(value.first() == 0);
- assert(value.second() == 0);
-
- value.first() = 1;
- value.second() = 2;
- new (&value) IntPair;
- assert(value.first() == 0);
- assert(value.second() == 0);
-}
-
-void test_constructor_default_init() {
- IntPair value;
- value.first() = 1;
- value.second() = 2;
-
- new (&value) IntPair(std::__default_init_tag(), 3);
- assert(value.first() == 1);
- assert(value.second() == 3);
-
- new (&value) IntPair(4, std::__default_init_tag());
- assert(value.first() == 4);
- assert(value.second() == 3);
-
- new (&value) IntPair(std::__default_init_tag(), std::__default_init_tag());
- assert(value.first() == 4);
- assert(value.second() == 3);
-}
-
-int main(int, char**)
-{
- test_constructor();
- test_constructor_default_init();
- return 0;
-}
diff --git a/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp b/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp
index 90463b0ac06e43..51e3a8534baea5 100644
--- a/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp
+++ b/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp
@@ -26,6 +26,10 @@ struct Empty {};
static_assert(std::__datasizeof_v<Empty> == 0, "");
+struct FinalEmpty final {};
+
+static_assert(std::__datasizeof_v<FinalEmpty> == 0, "");
+
struct OneBytePadding final {
OneBytePadding() {}
diff --git a/libcxx/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp b/libcxx/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp
index 0af79eef4687ac..a298f55ea7cf5c 100644
--- a/libcxx/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp
+++ b/libcxx/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
+// UNSUPPORTED: libcpp-abi-no-compressed-pair-padding
// This test makes sure that the control block implementation used for non-array
// types in std::make_shared and std::allocate_shared is ABI compatible with the
@@ -18,6 +19,7 @@
#include <cassert>
#include <cstddef>
#include <memory>
+#include <tuple>
#include <type_traits>
#include <utility>
@@ -26,6 +28,44 @@
#include "test_macros.h"
+struct value_init_tag {};
+
+template <class T, int _Idx, bool CanBeEmptyBase = std::is_empty<T>::value && !std::__libcpp_is_final<T>::value>
+struct compressed_pair_elem {
+ explicit compressed_pair_elem(value_init_tag) : value_() {}
+
+ template <class U>
+ explicit compressed_pair_elem(U&& u) : value_(std::forward<U>(u)) {}
+
+ T& get() { return value_; }
+
+private:
+ T value_;
+};
+
+template <class T, int _Idx>
+struct compressed_pair_elem<T, _Idx, true> : private T {
+ explicit compressed_pair_elem(value_init_tag) : T() {}
+
+ template <class U>
+ explicit compressed_pair_elem(U&& u) : T(std::forward<U>(u)) {}
+
+ T& get() { return *this; }
+};
+
+template <class T1, class T2>
+class compressed_pair : private compressed_pair_elem<T1, 0>, private compressed_pair_elem<T2, 1> {
+public:
+ using Base1 = compressed_pair_elem<T1, 0>;
+ using Base2 = compressed_pair_elem<T2, 1>;
+
+ template <class U1, class U2>
+ explicit compressed_pair(U1&& t1, U2&& t2) : Base1(std::forward<U1>(t1)), Base2(std::forward<U2>(t2)) {}
+
+ T1& first() { return static_cast<Base1&>(*this).get(); }
+ T2& second() { return static_cast<Base2&>(*this).get(); }
+};
+
// This is the pre-C++20 implementation of the control block used by non-array
// std::allocate_shared and std::make_shared. We keep it here so that we can
// make sure our implementation is backwards compatible with it forever.
@@ -33,10 +73,8 @@
// Of course, the class and its methods were renamed, but the size and layout
// of the class should remain the same as the original implementation.
template <class T, class Alloc>
-struct OldEmplaceControlBlock
- : std::__shared_weak_count
-{
- explicit OldEmplaceControlBlock(Alloc a) : data_(std::move(a), std::__value_init_tag()) { }
+struct OldEmplaceControlBlock : std::__shared_weak_count {
+ explicit OldEmplaceControlBlock(Alloc a) : data_(std::move(a), value_init_tag()) {}
T* get_elem() noexcept { return std::addressof(data_.second()); }
Alloc* get_alloc() noexcept { return std::addressof(data_.first()); }
@@ -49,7 +87,7 @@ struct OldEmplaceControlBlock
// Not implemented
}
- std::__compressed_pair<Alloc, T> data_;
+ compressed_pair<Alloc, T> data_;
};
template <class T, template <class> class Alloc>
@@ -67,8 +105,8 @@ void test() {
// 1. Check the stored object
{
- char const* old_elem = reinterpret_cast<char const*>(old.get_elem());
- char const* new_elem = reinterpret_cast<char const*>(new_.__get_elem());
+ char const* old_elem = reinterpret_cast<char const*>(old.get_elem());
+ char const* new_elem = reinterpret_cast<char const*>(new_.__get_elem());
std::ptrdiff_t old_offset = old_elem - reinterpret_cast<char const*>(&old);
std::ptrdiff_t new_offset = new_elem - reinterpret_cast<char const*>(&new_);
assert(new_offset == old_offset && "offset of stored element changed");
@@ -76,8 +114,8 @@ void test() {
// 2. Check the allocator
{
- char const* old_alloc = reinterpret_cast<char const*>(old.get_alloc());
- char const* new_alloc = reinterpret_cast<char const*>(new_.__get_alloc());
+ char const* old_alloc = reinterpret_cast<char const*>(old.get_alloc());
+ char const* new_alloc = reinterpret_cast<char const*>(new_.__get_alloc());
std::ptrdiff_t old_offset = old_alloc - reinterpret_cast<char const*>(&old);
std::ptrdiff_t new_offset = new_alloc - reinterpret_cast<char const*>(&new_);
assert(new_offset == old_offset && "offset of allocator changed");
@@ -89,48 +127,66 @@ void test() {
}
// Object types to store in the control block
-struct TrivialEmptyType { };
-struct TrivialNonEmptyType { char c[11]; };
-struct FinalEmptyType final { };
+struct TrivialEmptyType {};
+
+struct alignas(32) OveralignedEmptyType {};
+
+struct TrivialNonEmptyType {
+ char c[11];
+};
+
+struct FinalEmptyType final {};
+
struct NonTrivialType {
char c[22];
- NonTrivialType() : c{'x'} { }
+ NonTrivialType() : c{'x'} {}
+};
+
+struct VirtualFunctionType {
+ virtual ~VirtualFunctionType() {}
};
// Allocator types
template <class T>
struct TrivialEmptyAlloc {
- using value_type = T;
+ using value_type = T;
TrivialEmptyAlloc() = default;
- template <class U> TrivialEmptyAlloc(TrivialEmptyAlloc<U>) { }
+ template <class U>
+ TrivialEmptyAlloc(TrivialEmptyAlloc<U>) {}
T* allocate(std::size_t) { return nullptr; }
- void deallocate(T*, std::size_t) { }
+ void deallocate(T*, std::size_t) {}
};
+
template <class T>
struct TrivialNonEmptyAlloc {
char storage[77];
- using value_type = T;
+ using value_type = T;
TrivialNonEmptyAlloc() = default;
- template <class U> TrivialNonEmptyAlloc(TrivialNonEmptyAlloc<U>) { }
+ template <class U>
+ TrivialNonEmptyAlloc(TrivialNonEmptyAlloc<U>) {}
T* allocate(std::size_t) { return nullptr; }
- void deallocate(T*, std::size_t) { }
+ void deallocate(T*, std::size_t) {}
};
+
template <class T>
struct FinalEmptyAlloc final {
- using value_type = T;
+ using value_type = T;
FinalEmptyAlloc() = default;
- template <class U> FinalEmptyAlloc(FinalEmptyAlloc<U>) { }
+ template <class U>
+ FinalEmptyAlloc(FinalEmptyAlloc<U>) {}
T* allocate(std::size_t) { return nullptr; }
- void deallocate(T*, std::size_t) { }
+ void deallocate(T*, std::size_t) {}
};
+
template <class T>
struct NonTrivialAlloc {
char storage[88];
using value_type = T;
- NonTrivialAlloc() { }
- template <class U> NonTrivialAlloc(NonTrivialAlloc<U>) { }
+ NonTrivialAlloc() {}
+ template <class U>
+ NonTrivialAlloc(NonTrivialAlloc<U>) {}
T* allocate(std::size_t) { return nullptr; }
- void deallocate(T*, std::size_t) { }
+ void deallocate(T*, std::size_t) {}
};
int main(int, char**) {
@@ -139,21 +195,30 @@ int main(int, char**) {
test<TrivialEmptyType, FinalEmptyAlloc>();
test<TrivialEmptyType, NonTrivialAlloc>();
+ test<OveralignedEmptyType, TrivialEmptyAlloc>();
+ test<OveralignedEmptyType, TrivialNonEmptyAlloc>();
+ test<OveralignedEmptyType, FinalEmptyAlloc>();
+ test<OveralignedEmptyType, NonTrivialAlloc>();
+
test<TrivialNonEmptyType, TrivialEmptyAlloc>();
test<TrivialNonEmptyType, TrivialNonEmptyAlloc>();
test<TrivialNonEmptyType, FinalEmptyAlloc>();
test<TrivialNonEmptyType, NonTrivialAlloc>();
test<FinalEmptyType, TrivialEmptyAlloc>();
- test<FinalEmptyType, TrivialNonEmptyAlloc>();
- test<FinalEmptyType, FinalEmptyAlloc>();
- test<FinalEmptyType, NonTrivialAlloc>();
+ // FinalEmptyType combined with TrivialNonEmptyAlloc, FinalEmptyAlloc or NonTrivialAlloc is known to have an ABI break
+ // between LLVM 19 and LLVM 20. It's been deemed not severe enough to cause actual breakage.
test<NonTrivialType, TrivialEmptyAlloc>();
test<NonTrivialType, TrivialNonEmptyAlloc>();
test<NonTrivialType, FinalEmptyAlloc>();
test<NonTrivialType, NonTrivialAlloc>();
+ test<VirtualFunctionType, TrivialEmptyAlloc>();
+ test<VirtualFunctionType, TrivialNonEmptyAlloc>();
+ test<VirtualFunctionType, FinalEmptyAlloc>();
+ test<VirtualFunctionType, NonTrivialAlloc>();
+
// Test a few real world types just to make sure we didn't mess up badly somehow
test<std::string, std::allocator>();
test<int, std::allocator>();
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp
index 5b3f4f10cadbb5..5afc3ad0c863e5 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp
@@ -6,10 +6,6 @@
//
//===----------------------------------------------------------------------===//
-// FIXME: In MSVC mode, even "std::function<int(int)> f(aref);" causes
-// allocations.
-// XFAIL: target=x86_64-pc-windows-msvc && stdlib=libc++ && libcpp-abi-version=1
-
// UNSUPPORTED: c++03
// <functional>
diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py
index 3f39232ab4d3b8..49087f94c06265 100644
--- a/libcxx/utils/gdb/libcxx/printers.py
+++ b/libcxx/utils/gdb/libcxx/printers.py
@@ -154,11 +154,6 @@ def _typename_with_n_generic_arguments(gdb_type, n):
result = (template[:-2] + ">") % tuple(arg_list)
return result
-
-def _typename_with_first_generic_argument(gdb_type):
- return _typename_with_n_generic_arguments(gdb_type, 1)
-
-
class StdTuplePrinter(object):
"""Print a std::tuple."""
@@ -196,33 +191,6 @@ def children(self):
return iter(())
return self._Children(self.val)
-
-def _get_base_subobject(child_class_value, index=0):
- """Returns the object's value in the form of the parent class at index.
-
- This function effectively casts the child_class_value to the base_class's
- type, but the type-to-cast to is stored in the field at index, and once
- we know the field, we can just return the data.
-
- Args:
- child_class_value: the value to cast
- index: the parent class index
-
- Raises:
- Exception: field at index was not a base-class field.
- """
-
- field = child_class_value.type.fields()[index]
- if not field.is_base_class:
- raise Exception("Not a base-class field.")
- return child_class_value[field]
-
-
-def _value_of_pair_first(value):
- """Convenience for _get_base_subobject, for the common case."""
- return _get_base_subobject(value, 0)["__value_"]
-
-
class StdStringPrinter(object):
"""Print a std::string."""
@@ -231,7 +199,7 @@ def __init__(self, val):
def to_string(self):
"""Build a python string from the data whether stored inline or separately."""
- value_field = _value_of_pair_first(self.val["__r_"])
+ value_field = self.val["__rep_"]
short_field = value_field["__s"]
short_size = short_field["__size_"]
if short_field["__is_long_"]:
@@ -270,7 +238,7 @@ class StdUniquePtrPrinter(object):
def __init__(self, val):
self.val = val
- self.addr = _value_of_pair_first(self.val["__ptr_"])
+ self.addr = self.val["__ptr_"]
self.pointee_type = self.val.type.template_argument(0)
def to_string(self):
@@ -397,16 +365,12 @@ def __init__(self, val):
self.typename += "<bool>"
self.length = self.val["__size_"]
bits_per_word = self.val["__bits_per_word"]
- self.capacity = (
- _value_of_pair_first(self.val["__cap_alloc_"]) * bits_per_word
- )
+ self.capacity = self.val["__cap_"] * bits_per_word
self.iterator = self._VectorBoolIterator(begin, self.length, bits_per_word)
else:
end = self.val["__end_"]
self.length = end - begin
- self.capacity = (
- _get_base_subobject(self.val["__end_cap_"])["__value_"] - begin
- )
+ self.capacity = self.val["__cap_"] - begin
self.iterator = self._VectorIterator(begin, end)
def to_string(self):
@@ -461,7 +425,7 @@ class StdDequePrinter(object):
def __init__(self, val):
self.val = val
- self.size = int(_value_of_pair_first(val["__size_"]))
+ self.size = int(val["__size_"])
self.start_ptr = self.val["__map_"]["__begin_"]
self.first_block_start_index = int(self.val["__start_"])
self.node_type = self.start_ptr.type
@@ -513,8 +477,7 @@ class StdListPrinter(object):
def __init__(self, val):
self.val = val
- size_alloc_field = self.val["__size_alloc_"]
- self.size = int(_value_of_pair_first(size_alloc_field))
+ self.size = int(self.val["__size_"])
dummy_node = self.val["__end_"]
self.nodetype = gdb.lookup_type(
re.sub(
@@ -646,9 +609,8 @@ class AbstractRBTreePrinter(object):
def __init__(self, val):
self.val = val
tree = self.val["__tree_"]
- self.size = int(_value_of_pair_first(tree["__pair3_"]))
- dummy_root = tree["__pair1_"]
- root = _value_of_pair_first(dummy_root)["__left_"]
+ self.size = int(tree["__size_"])
+ root = tree["__end_node_"]["__left_"]
cast_type = self._init_cast_type(val.type)
self.util = RBTreeUtils(cast_type, root)
@@ -815,13 +777,13 @@ class AbstractUnorderedCollectionPrinter(object):
def __init__(self, val):
self.val = val
self.table = val["__table_"]
- self.sentinel = self.table["__p1_"]
- self.size = int(_value_of_pair_first(self.table["__p2_"]))
- node_base_type = self.sentinel.type.template_argument(0)
+ self.sentinel = self.table["__first_node_"]
+ self.size = int(self.table["__size_"])
+ node_base_type = self.sentinel.type
self.cast_type = node_base_type.template_argument(0)
def _list_it(self, sentinel_ptr):
- next_ptr = _value_of_pair_first(sentinel_ptr)["__next_"]
+ next_ptr = sentinel_ptr["__next_"]
while str(next_ptr.cast(_void_pointer_type)) != "0x0":
next_val = next_ptr.cast(self.cast_type).dereference()
for key_value in self._get_key_value(next_val):
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index 2cd04124a6ca5e..15456171b54837 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -376,6 +376,7 @@ def _mingwSupportsModules(cfg):
"_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR": "libcpp-has-abi-bounded-iterators-in-vector",
"_LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE": "libcpp-has-abi-fix-unordered-container-size-type",
"_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR": "libcpp-deprecated-abi-disable-pair-trivial-copy-ctor",
+ "_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING": "libcpp-abi-no-compressed-pair-padding",
"_LIBCPP_HAS_NO_FILESYSTEM": "no-filesystem",
"_LIBCPP_HAS_NO_RANDOM_DEVICE": "no-random-device",
"_LIBCPP_HAS_NO_LOCALIZATION": "no-localization",
More information about the libcxx-commits
mailing list