diff --git a/libcxx/include/__config b/libcxx/include/__config index 23b9123fa6917..b4c081dcdff1b 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1176,12 +1176,6 @@ typedef __char32_t char32_t; # define _LIBCPP_NO_SPECIALIZATIONS # endif -# if __has_cpp_attribute(_Clang::__standalone_debug__) -# define _LIBCPP_STANDALONE_DEBUG [[_Clang::__standalone_debug__]] -# else -# define _LIBCPP_STANDALONE_DEBUG -# endif - # if __has_cpp_attribute(_Clang::__preferred_name__) # define _LIBCPP_PREFERRED_NAME(x) [[_Clang::__preferred_name__(x)]] # else diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index f0e88bbf2bc38..2018b5a194e89 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -166,7 +166,12 @@ public: } #endif - _LIBCPP_HIDE_FROM_ABI explicit __hash_node(__next_pointer __next, size_t __hash) : _Base(__next), __hash_(__hash) {} + template + _LIBCPP_HIDE_FROM_ABI explicit __hash_node(size_t __hash, _Alloc& __na, _Args&&... __args) + : _Base(nullptr), __hash_(__hash) { + allocator_traits<_Alloc>::construct(__na, std::addressof(__get_value()), std::forward<_Args>(__args)...); + } + _LIBCPP_HIDE_FROM_ABI ~__hash_node() {} }; @@ -1855,16 +1860,13 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&&... __args) { __node_allocator& __na = __node_alloc(); __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - // Begin the lifetime of the node itself. Note that this doesn't begin the lifetime of the value - // held inside the node, since we need to use the allocator's construct() method for that. + // Begin the lifetime of the node itself and the value_type contained within. // // We don't use the allocator's construct() method to construct the node itself since the // Cpp17FooInsertable named requirements don't require the allocator's construct() method // to work on anything other than the value_type. - std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ 0); + std::__construct_at(std::addressof(*__h), /* hash = */ 0, __na, std::forward<_Args>(__args)...); - // Now construct the value_type using the allocator's construct() method. - __node_traits::construct(__na, std::addressof(__h->__get_value()), std::forward<_Args>(__args)...); __h.get_deleter().__value_constructed = true; __h->__hash_ = hash_function()(__h->__get_value()); @@ -1878,8 +1880,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(size_t __hash, _ static_assert(!__is_hash_value_type<_Args...>::value, "Construct cannot be called with a hash value type"); __node_allocator& __na = __node_alloc(); __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ __hash); - __node_traits::construct(__na, std::addressof(__h->__get_value()), std::forward<_Args>(__args)...); + std::__construct_at(std::addressof(*__h), /* hash = */ __hash, __na, std::forward<_Args>(__args)...); __h.get_deleter().__value_constructed = true; return __h; } diff --git a/libcxx/include/__tree b/libcxx/include/__tree index 81a73342cc61b..61c910c52c536 100644 --- a/libcxx/include/__tree +++ b/libcxx/include/__tree @@ -20,9 +20,11 @@ #include <__memory/addressof.h> #include <__memory/allocator_traits.h> #include <__memory/compressed_pair.h> +#include <__memory/construct_at.h> #include <__memory/pointer_traits.h> #include <__memory/swap_allocator.h> #include <__memory/unique_ptr.h> +#include <__new/launder.h> #include <__type_traits/copy_cvref.h> #include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> @@ -559,8 +561,7 @@ public: }; template -class _LIBCPP_STANDALONE_DEBUG -__tree_node_base : public __tree_end_node<__rebind_pointer_t<_VoidPtr, __tree_node_base<_VoidPtr> > > { +class __tree_node_base : public __tree_end_node<__rebind_pointer_t<_VoidPtr, __tree_node_base<_VoidPtr> > > { public: using pointer = __rebind_pointer_t<_VoidPtr, __tree_node_base>; using __end_node_pointer _LIBCPP_NODEBUG = __rebind_pointer_t<_VoidPtr, __tree_end_node >; @@ -573,22 +574,41 @@ public: _LIBCPP_HIDE_FROM_ABI void __set_parent(pointer __p) { __parent_ = static_cast<__end_node_pointer>(__p); } - ~__tree_node_base() = delete; + _LIBCPP_HIDE_FROM_ABI __tree_node_base() = default; __tree_node_base(__tree_node_base const&) = delete; __tree_node_base& operator=(__tree_node_base const&) = delete; }; template -class _LIBCPP_STANDALONE_DEBUG __tree_node : public __tree_node_base<_VoidPtr> { +class __tree_node : public __tree_node_base<_VoidPtr> { public: using __node_value_type _LIBCPP_NODEBUG = __get_node_value_type_t<_Tp>; +// We use a union to avoid initialization during member initialization, which allows us +// to use the allocator from the container to construct the `__node_value_type` in the +// memory provided by the union member +#ifndef _LIBCPP_CXX03_LANG + private: - __node_value_type __value_; + union { + __node_value_type __value_; + }; public: _LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() { return __value_; } +#else + +private: + _ALIGNAS_TYPE(__node_value_type) unsigned char __buffer_[sizeof(__node_value_type)]; +public: + _LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() { return *reinterpret_cast<__node_value_type*>(__buffer_); } +#endif + + template + _LIBCPP_HIDE_FROM_ABI explicit __tree_node(_Alloc& __na, _Args&&... __args) { + allocator_traits<_Alloc>::construct(__na, std::addressof(__get_value()), std::forward<_Args>(__args)...); + } ~__tree_node() = delete; __tree_node(__tree_node const&) = delete; __tree_node& operator=(__tree_node const&) = delete; @@ -1816,7 +1836,7 @@ typename __tree<_Tp, _Compare, _Allocator>::__node_holder __tree<_Tp, _Compare, _Allocator>::__construct_node(_Args&&... __args) { __node_allocator& __na = __node_alloc(); __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - __node_traits::construct(__na, std::addressof(__h->__get_value()), std::forward<_Args>(__args)...); + std::__construct_at(std::addressof(*__h), __na, std::forward<_Args>(__args)...); __h.get_deleter().__value_constructed = true; return __h; }