diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst index aecac6692932b8..f3aa92b1ab97af 100644 --- a/libcxx/docs/ReleaseNotes/20.rst +++ b/libcxx/docs/ReleaseNotes/20.rst @@ -43,7 +43,6 @@ Implemented Papers - P2985R0: A type trait for detecting virtual base classes (`Github `__) - ``std::jthread`` and ```` are not guarded behind ``-fexperimental-library`` anymore - Improvements and New Features ----------------------------- @@ -53,6 +52,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 ------------------------- @@ -97,8 +99,16 @@ 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 9f3bab33865923..ff5e3cf5faf0e0 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`). // #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 ff31011caa329d..0d95c9a6ef2bbd 100644 --- a/libcxx/include/__functional/function.h +++ b/libcxx/include/__functional/function.h @@ -143,45 +143,46 @@ class __default_alloc_func; template 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 __alloc_traits; typedef typename __alloc_traits::size_type size_type; - __compressed_pair __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::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::value) - : __data_(__size, __a) {} + : __size_(__size), __alloc_(__a) {} _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(__bucket_list_deallocator&& __x) _NOEXCEPT_(is_nothrow_move_constructible::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 __p2_; - __compressed_pair __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::value&& is_nothrow_default_constructible::value) - : __p2_(0, __default_init_tag()), __p3_(1.0f, __default_init_tag()) {} + : __size_(0), __max_load_factor_(1.0f) {} template 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 __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 __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 __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 __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 __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::value&& is_nothrow_move_constructible::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 __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::value, "Hasher must be copy-constructible."); #endif - __deallocate_node(__p1_.first().__next_); + __deallocate_node(__first_node_.__next_); } template @@ -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 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 @@ -1300,7 +1316,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() _NOEXCEPT { template 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 @@ -1312,8 +1328,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT { template 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 diff --git a/libcxx/include/__memory/compressed_pair.h b/libcxx/include/__memory/compressed_pair.h index 40e5cfc35fb040..629e3ad8848ffa 100644 --- a/libcxx/include/__memory/compressed_pair.h +++ b/libcxx/include/__memory/compressed_pair.h @@ -11,161 +11,80 @@ #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 +#include <__type_traits/is_reference.h> #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 ::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 >::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 - _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 -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 >::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 - _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 __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 , _Dummy>::value && - __dependent_type, _Dummy>::value, - int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair() - : _Base1(__value_init_tag()), _Base2(__value_init_tag()) {} - - template - _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 - _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::type()), - _Base2(__pc, std::move(__second_args), typename __make_tuple_indices::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 __compressed_pair_padding { + char __padding_[((is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value) || is_reference<_ToPad>::value) + ? 0 + : sizeof(_ToPad) - __datasizeof_v<_ToPad>]; }; -template -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 _LIBCPP_CONCAT3(__padding1_, __LINE__, _); \ + _LIBCPP_NO_UNIQUE_ADDRESS T2 Initializer2; \ + _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding _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 _LIBCPP_CONCAT3(__padding1_, __LINE__, _); \ + _LIBCPP_NO_UNIQUE_ADDRESS T2 Initializer2; \ + _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding _LIBCPP_CONCAT3(__padding2_, __LINE__, _); \ + _LIBCPP_NO_UNIQUE_ADDRESS T3 Initializer3; \ + _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding _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 5dcd475e2c9f9d..70964e6122d5a6 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -200,11 +200,11 @@ class _LIBCPP_EXPORTED_FROM_ABI __shared_weak_count : private __shared_count { template 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; @@ -219,15 +219,15 @@ class __shared_ptr_pointer : public __shared_weak_count { template 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 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 @@ -236,8 +236,8 @@ void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT { typedef allocator_traits<_Al> _ATraits; typedef pointer_traits _PTraits; - _Al __a(__data_.second()); - __data_.second().~_Alloc(); + _Al __a(__alloc_); + __alloc_.~_Alloc(); __a.deallocate(_PTraits::pointer_to(*this), 1); } @@ -295,36 +295,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 392cf421378214..9ca13d0e4fd1a7 100644 --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -144,7 +144,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr { void>; private: - __compressed_pair __ptr_; + _LIBCPP_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_); typedef _LIBCPP_NODEBUG __unique_ptr_deleter_sfinae<_Dp> _DeleterSFINAE; @@ -178,23 +178,25 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr { public: template > - _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 > - _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 > - _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 > > _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(pointer __p, _LValRefType<_Dummy> __d) _NOEXCEPT - : __ptr_(__p, __d) {} + : __ptr_(__p), + __deleter_(__d) {} template > > _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::value, "rvalue deleter bound to reference"); } @@ -202,24 +204,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(__u.get_deleter())) {} + : __ptr_(__u.release()), + __deleter_(std::forward(__u.get_deleter())) {} template , _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 ::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(__u.get_deleter()); + __deleter_ = std::forward(__u.get_deleter()); return *this; } @@ -229,7 +233,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; } @@ -256,32 +260,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())) { - 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 @@ -303,7 +311,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> void>; private: - __compressed_pair __ptr_; + _LIBCPP_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_); template struct _CheckArrayPointerConversion : is_same<_From, pointer> {}; @@ -352,42 +360,46 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> public: template > - _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 > - _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 = _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 = _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 > > _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 = _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::value, "rvalue deleter bound to reference"); } template > > _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::value, "rvalue deleter bound to reference"); } @@ -398,11 +410,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(__u.get_deleter())) {} + : __ptr_(__u.release()), + __deleter_(std::forward(__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(__u.get_deleter()); + __deleter_ = std::forward(__u.get_deleter()); return *this; } @@ -411,7 +424,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> class = _EnableIfMoveConvertible, _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 = _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; } @@ -437,41 +451,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 ::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 , 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 __end_cap_; + _LIBCPP_COMPRESSED_PAIR(pointer, __end_cap_, allocator_type, __alloc_); using __alloc_ref = __add_lvalue_reference_t; using __alloc_const_ref = __add_lvalue_reference_t; @@ -88,13 +88,13 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer() _NOEXCEPT_(is_nothrow_default_constructible::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 _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 _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 __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 __tree<_Tp, _Compare, _Allocator>::__tree(const value_compare& __comp) _NOEXCEPT_( is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_copy_constructible::value) - : __pair3_(0, __comp) { + : __size_(0), __value_comp_(__comp) { __begin_node() = __end_node(); } template __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 __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 __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 __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_( is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible::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 __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 void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type) _NOEXCEPT_(is_nothrow_move_assignable::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/deque b/libcxx/include/deque index f2f6122fd0b9ce..78e11fdd65d603 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -582,12 +582,12 @@ private: __map __map_; size_type __start_; - __compressed_pair __size_; + _LIBCPP_COMPRESSED_PAIR(size_type, __size_, allocator_type, __alloc_); public: // construct/copy/destroy: _LIBCPP_HIDE_FROM_ABI deque() _NOEXCEPT_(is_nothrow_default_constructible::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(__alloc_traits::max_size(__alloc()), numeric_limits::max()); @@ -1251,7 +1251,7 @@ deque(from_range_t, _Range&&, _Alloc = _Alloc()) -> deque -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 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 -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 template ::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 template ::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 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 deque<_Tp, _Allocator>::deque(const deque& __c, const __type_identity_t& __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 -deque<_Tp, _Allocator>::deque(initializer_list __il) : __start_(0), __size_(0, __default_init_tag()) { +deque<_Tp, _Allocator>::deque(initializer_list __il) : __start_(0), __size_(0) { __annotate_new(0); __append(__il.begin(), __il.end()); } template deque<_Tp, _Allocator>::deque(initializer_list __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 inline deque<_Tp, _Allocator>::deque(deque&& __c) noexcept(is_nothrow_move_constructible::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 inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t& __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 9a8041306bbd50..098b95f1a06495 100644 --- a/libcxx/include/forward_list +++ b/libcxx/include/forward_list @@ -229,6 +229,7 @@ template #include <__type_traits/type_identity.h> #include <__utility/forward.h> #include <__utility/move.h> +#include <__utility/swap.h> #include #include // __launder #include @@ -491,27 +492,27 @@ protected: typedef __rebind_alloc, __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 @@ -593,13 +594,13 @@ private: template 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 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 8eadbcb07e3a42..e14622e3233009 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -1400,13 +1400,13 @@ class __packaged_task_func; template 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(); @@ -1416,12 +1416,13 @@ public: template 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 void __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy() { - __f_.~__compressed_pair<_Fp, _Alloc>(); + __func_.~_Fp(); + __alloc_.~_Alloc(); } template @@ -1429,14 +1430,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 _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 _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 diff --git a/libcxx/include/list b/libcxx/include/list index dc3b6797858478..85fc381d1125c5 100644 --- a/libcxx/include/list +++ b/libcxx/include/list @@ -498,16 +498,16 @@ protected: "internal allocator type must differ from user-specified type; otherwise overload resolution breaks"); __node_base __end_; - __compressed_pair __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()); @@ -601,17 +601,20 @@ inline void __list_imp<_Tp, _Alloc>::__unlink_nodes(__link_pointer __f, __link_p template inline __list_imp<_Tp, _Alloc>::__list_imp() _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value) - : __size_alloc_(0, __default_init_tag()) {} + : __size_(0) {} template -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 -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 -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 diff --git a/libcxx/include/string b/libcxx/include/string index e8c9bcee53e3df..76359022f3650c 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -918,18 +918,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; @@ -945,7 +945,7 @@ private: template _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)); } @@ -983,7 +983,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string() _NOEXCEPT_(is_nothrow_default_constructible::value) - : __r_(__value_init_tag(), __default_init_tag()) { + : __rep_() { __annotate_new(0); } @@ -993,14 +993,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()); @@ -1008,9 +1008,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()); @@ -1026,28 +1026,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()); @@ -1056,15 +1057,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)); } @@ -1073,23 +1073,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( @@ -1098,7 +1094,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(); @@ -1114,13 +1110,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(); @@ -1129,7 +1125,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(); @@ -1142,7 +1138,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()); @@ -1152,8 +1148,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()); } @@ -1164,21 +1160,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 ::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 ::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); } @@ -1186,7 +1181,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 { @@ -1196,13 +1191,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 @@ -1467,8 +1461,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); @@ -1875,10 +1869,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) { @@ -1947,27 +1941,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()) @@ -1977,31 +1971,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_to(__r_.first().__s.__data_[0])); + return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits::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::pointer_to(__r_.first().__s.__data_[0])); + return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits::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(); } @@ -2306,7 +2305,7 @@ template _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; @@ -2330,7 +2329,7 @@ template _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; @@ -2354,7 +2353,7 @@ template _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)) { @@ -2377,7 +2376,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(const value template _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(); @@ -2409,7 +2408,7 @@ template template _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 @@ -2440,7 +2439,7 @@ template _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(); @@ -2660,7 +2659,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 { @@ -2708,7 +2707,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()); @@ -3453,7 +3452,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()); @@ -3808,7 +3807,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 4720f8ef15a09c..2a6484988c3102 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(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 __end_cap_ = - __compressed_pair(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 > _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 > _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(std::distance(__first, __last)); __init_with_size(__first, __last, __n); } template _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 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t& __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::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 _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t& __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 __il) { template _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocator>::vector(initializer_list __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 __cap_alloc_; + _LIBCPP_COMPRESSED_PAIR(size_type, __cap_, __storage_allocator, __alloc_); public: typedef __bit_reference 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(sizeof(__storage_type) * CHAR_BIT); @@ -1960,7 +1953,7 @@ public: #if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange _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(ranges::distance(__range)); __init_with_size(ranges::begin(__range), ranges::end(__range), __n); @@ -2365,7 +2358,7 @@ vector::__construct_at_end(_InputIterator __first, _Sentinel _ template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::vector() _NOEXCEPT_(is_nothrow_default_constructible::value) - : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {} + : __begin_(nullptr), __size_(0), __cap_(0) {} template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::vector(const allocator_type& __a) @@ -2374,12 +2367,12 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector(__a)) { + : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) { } template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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::vector(size_type __n) #if _LIBCPP_STD_VER >= 14 template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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::vector(size_type __n, co template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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::vector(size_type __n, co template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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::vector(size_type __n, const value_type& __x, const all template template ::value, int> > _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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 template ::value, int> > _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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 template ::value, int> > _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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(std::distance(__first, __last)); __init_with_size(__first, __last, __n); } @@ -2443,7 +2436,7 @@ template template ::value, int> > _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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(std::distance(__first, __last)); __init_with_size(__first, __last, __n); } @@ -2452,7 +2445,7 @@ vector::vector(_ForwardIterator __first, _ForwardIterator __la template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::vector(initializer_list __il) - : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) { + : __begin_(nullptr), __size_(0), __cap_(0) { size_type __n = static_cast(__il.size()); if (__n > 0) { __vallocate(__n); @@ -2463,7 +2456,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::vector(initializer_list< template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::vector(initializer_list __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(__il.size()); if (__n > 0) { __vallocate(__n); @@ -2477,7 +2470,8 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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::vector(const vector& __v template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::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 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector::vector(vector&& __v, const __type_identity_t& __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 #include @@ -93,7 +93,8 @@ static_assert(TEST_ALIGNOF(unordered_map_alloc) == 96, ""); +// This part of the ABI has been broken between LLVM 19 and LLVM 20. +static_assert(sizeof(std::unordered_map) == 64, ""); static_assert(TEST_ALIGNOF(std::unordered_map) == 32, ""); #elif __SIZE_WIDTH__ == 32 @@ -126,7 +127,7 @@ static_assert(TEST_ALIGNOF(unordered_map_alloc) == 96); +static_assert(sizeof(std::unordered_map) == 64); static_assert(TEST_ALIGNOF(std::unordered_map) == 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 #include @@ -92,7 +92,8 @@ static_assert(TEST_ALIGNOF(unordered_set_alloc) == 96, ""); +// This part of the ABI has been broken between LLVM 19 and LLVM 20. +static_assert(sizeof(std::unordered_set) == 64, ""); static_assert(TEST_ALIGNOF(std::unordered_set) == 32, ""); #elif __SIZE_WIDTH__ == 32 @@ -124,7 +125,7 @@ static_assert(TEST_ALIGNOF(unordered_set_alloc) == 96); +static_assert(sizeof(std::unordered_set) == 64); static_assert(TEST_ALIGNOF(std::unordered_set) == 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 #include 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 #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; Set s; // expected-error@__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; 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 -#include - -#include "test_macros.h" - -typedef std::__compressed_pair 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 == 0, ""); +struct FinalEmpty final {}; + +static_assert(std::__datasizeof_v == 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 #include #include +#include #include #include @@ -26,6 +28,44 @@ #include "test_macros.h" +struct value_init_tag {}; + +template ::value && !std::__libcpp_is_final::value> +struct compressed_pair_elem { + explicit compressed_pair_elem(value_init_tag) : value_() {} + + template + explicit compressed_pair_elem(U&& u) : value_(std::forward(u)) {} + + T& get() { return value_; } + +private: + T value_; +}; + +template +struct compressed_pair_elem : private T { + explicit compressed_pair_elem(value_init_tag) : T() {} + + template + explicit compressed_pair_elem(U&& u) : T(std::forward(u)) {} + + T& get() { return *this; } +}; + +template +class compressed_pair : private compressed_pair_elem, private compressed_pair_elem { +public: + using Base1 = compressed_pair_elem; + using Base2 = compressed_pair_elem; + + template + explicit compressed_pair(U1&& t1, U2&& t2) : Base1(std::forward(t1)), Base2(std::forward(t2)) {} + + T1& first() { return static_cast(*this).get(); } + T2& second() { return static_cast(*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 -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 data_; + compressed_pair data_; }; template class Alloc> @@ -67,8 +105,8 @@ void test() { // 1. Check the stored object { - char const* old_elem = reinterpret_cast(old.get_elem()); - char const* new_elem = reinterpret_cast(new_.__get_elem()); + char const* old_elem = reinterpret_cast(old.get_elem()); + char const* new_elem = reinterpret_cast(new_.__get_elem()); std::ptrdiff_t old_offset = old_elem - reinterpret_cast(&old); std::ptrdiff_t new_offset = new_elem - reinterpret_cast(&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(old.get_alloc()); - char const* new_alloc = reinterpret_cast(new_.__get_alloc()); + char const* old_alloc = reinterpret_cast(old.get_alloc()); + char const* new_alloc = reinterpret_cast(new_.__get_alloc()); std::ptrdiff_t old_offset = old_alloc - reinterpret_cast(&old); std::ptrdiff_t new_offset = new_alloc - reinterpret_cast(&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 struct TrivialEmptyAlloc { - using value_type = T; + using value_type = T; TrivialEmptyAlloc() = default; - template TrivialEmptyAlloc(TrivialEmptyAlloc) { } + template + TrivialEmptyAlloc(TrivialEmptyAlloc) {} T* allocate(std::size_t) { return nullptr; } - void deallocate(T*, std::size_t) { } + void deallocate(T*, std::size_t) {} }; + template struct TrivialNonEmptyAlloc { char storage[77]; - using value_type = T; + using value_type = T; TrivialNonEmptyAlloc() = default; - template TrivialNonEmptyAlloc(TrivialNonEmptyAlloc) { } + template + TrivialNonEmptyAlloc(TrivialNonEmptyAlloc) {} T* allocate(std::size_t) { return nullptr; } - void deallocate(T*, std::size_t) { } + void deallocate(T*, std::size_t) {} }; + template struct FinalEmptyAlloc final { - using value_type = T; + using value_type = T; FinalEmptyAlloc() = default; - template FinalEmptyAlloc(FinalEmptyAlloc) { } + template + FinalEmptyAlloc(FinalEmptyAlloc) {} T* allocate(std::size_t) { return nullptr; } - void deallocate(T*, std::size_t) { } + void deallocate(T*, std::size_t) {} }; + template struct NonTrivialAlloc { char storage[88]; using value_type = T; - NonTrivialAlloc() { } - template NonTrivialAlloc(NonTrivialAlloc) { } + NonTrivialAlloc() {} + template + NonTrivialAlloc(NonTrivialAlloc) {} 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(); test(); + test(); + test(); + test(); + test(); + test(); test(); test(); test(); test(); - test(); - test(); - test(); + // 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(); test(); test(); test(); + test(); + test(); + test(); + test(); + // Test a few real world types just to make sure we didn't mess up badly somehow test(); test(); 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 f(aref);" causes -// allocations. -// XFAIL: target=x86_64-pc-windows-msvc && stdlib=libc++ && libcpp-abi-version=1 - // UNSUPPORTED: c++03 // 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 += "" 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",