[libcxx-commits] [libcxx] 4c8fab3 - [libc++] Avoid type-punning between __hash_value_type and pair (#143501)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jun 26 10:44:03 PDT 2025
Author: Nikolas Klauser
Date: 2025-06-26T19:43:59+02:00
New Revision: 4c8fab399b2ebf37f6a560bc2d5c6b4f0045a19f
URL: https://github.com/llvm/llvm-project/commit/4c8fab399b2ebf37f6a560bc2d5c6b4f0045a19f
DIFF: https://github.com/llvm/llvm-project/commit/4c8fab399b2ebf37f6a560bc2d5c6b4f0045a19f.diff
LOG: [libc++] Avoid type-punning between __hash_value_type and pair (#143501)
This patch is very similar to #134819 in nature. Before this patch, we
were dereferencing pointers to objects which were never constructed. Now
we always assume that nodes store `pair<const KeyT, ValueT>` for
unordered_maps instead, as they actually do.
Added:
Modified:
libcxx/include/__hash_table
libcxx/include/unordered_map
libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/assign_copy.pass.cpp
libcxx/utils/gdb/libcxx/printers.py
Removed:
################################################################################
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index aefa8e19c1864..cc5f6d1348e41 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -29,6 +29,7 @@
#include <__memory/unique_ptr.h>
#include <__new/launder.h>
#include <__type_traits/can_extract_key.h>
+#include <__type_traits/copy_cvref.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/invoke.h>
#include <__type_traits/is_const.h>
@@ -108,9 +109,22 @@ struct __hash_node_base {
_LIBCPP_HIDE_FROM_ABI explicit __hash_node_base(__next_pointer __next) _NOEXCEPT : __next_(__next) {}
};
+template <class _Tp>
+struct __get_hash_node_value_type {
+ using type _LIBCPP_NODEBUG = _Tp;
+};
+
+template <class _Key, class _Tp>
+struct __get_hash_node_value_type<__hash_value_type<_Key, _Tp> > {
+ using type _LIBCPP_NODEBUG = pair<const _Key, _Tp>;
+};
+
+template <class _Tp>
+using __get_hash_node_value_type_t _LIBCPP_NODEBUG = typename __get_hash_node_value_type<_Tp>::type;
+
template <class _Tp, class _VoidPtr>
struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > > {
- typedef _Tp __node_value_type;
+ using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t<_Tp>;
using _Base _LIBCPP_NODEBUG = __hash_node_base<__rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > >;
using __next_pointer _LIBCPP_NODEBUG = typename _Base::__next_pointer;
@@ -122,18 +136,20 @@ struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __has
private:
union {
- _Tp __value_;
+ __node_value_type __value_;
};
public:
- _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return __value_; }
+ _LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() { return __value_; }
#else
private:
- _ALIGNAS_TYPE(_Tp) char __buffer_[sizeof(_Tp)];
+ _ALIGNAS_TYPE(__node_value_type) char __buffer_[sizeof(__node_value_type)];
public:
- _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return *std::__launder(reinterpret_cast<_Tp*>(&__buffer_)); }
+ _LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() {
+ return *std::__launder(reinterpret_cast<__node_value_type*>(&__buffer_));
+ }
#endif
_LIBCPP_HIDE_FROM_ABI explicit __hash_node(__next_pointer __next, size_t __hash) : _Base(__next), __hash_(__hash) {}
@@ -201,8 +217,8 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
return __t;
}
- _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
- return std::addressof(__n.__get_value());
+ _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__container_value_type& __n) {
+ return std::addressof(__n);
}
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
};
@@ -242,7 +258,7 @@ public:
typedef typename __node_base_type::__next_pointer __next_pointer;
- typedef _Tp __node_value_type;
+ using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t<_Tp>;
typedef __rebind_pointer_t<_VoidPtr, __node_value_type> __node_value_type_pointer;
typedef __rebind_pointer_t<_VoidPtr, const __node_value_type> __const_node_value_type_pointer;
@@ -667,14 +683,14 @@ int __diagnose_unordered_container_requirements(void*);
template <class _Tp, class _Hash, class _Equal, class _Alloc>
class __hash_table {
public:
- typedef _Tp value_type;
+ using value_type = __get_hash_node_value_type_t<_Tp>;
typedef _Hash hasher;
typedef _Equal key_equal;
typedef _Alloc allocator_type;
private:
typedef allocator_traits<allocator_type> __alloc_traits;
- typedef typename __make_hash_node_types<value_type, typename __alloc_traits::void_pointer>::type _NodeTypes;
+ typedef typename __make_hash_node_types<_Tp, typename __alloc_traits::void_pointer>::type _NodeTypes;
public:
typedef typename _NodeTypes::__node_value_type __node_value_type;
@@ -845,6 +861,22 @@ public:
return __emplace_unique(std::forward<_Pp>(__x));
}
+ template <class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node(value_type&& __value) {
+ using __key_type = typename _NodeTypes::key_type;
+
+ __node_holder __h = __construct_node(const_cast<__key_type&&>(__value.first), std::move(__value.second));
+ __node_insert_unique(__h.get());
+ __h.release();
+ }
+
+ template <class _ValueT = _Tp, __enable_if_t<!__is_hash_value_type<_ValueT>::value, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node(value_type&& __value) {
+ __node_holder __h = __construct_node(std::move(__value));
+ __node_insert_unique(__h.get());
+ __h.release();
+ }
+
template <class _Pp>
_LIBCPP_HIDE_FROM_ABI iterator __insert_multi(_Pp&& __x) {
return __emplace_multi(std::forward<_Pp>(__x));
@@ -855,6 +887,22 @@ public:
return __emplace_hint_multi(__p, std::forward<_Pp>(__x));
}
+ template <class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node(value_type&& __value) {
+ using __key_type = typename _NodeTypes::key_type;
+
+ __node_holder __h = __construct_node(const_cast<__key_type&&>(__value.first), std::move(__value.second));
+ __node_insert_multi(__h.get());
+ __h.release();
+ }
+
+ template <class _ValueT = _Tp, __enable_if_t<!__is_hash_value_type<_ValueT>::value, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node(value_type&& __value) {
+ __node_holder __h = __construct_node(std::move(__value));
+ __node_insert_multi(__h.get());
+ __h.release();
+ }
+
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __insert_unique(const __container_value_type& __x) {
return __emplace_unique_key_args(_NodeTypes::__get_key(__x), __x);
}
@@ -1020,6 +1068,21 @@ private:
_LIBCPP_HIDE_FROM_ABI void __deallocate_node(__next_pointer __np) _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI __next_pointer __detach() _NOEXCEPT;
+ template <class _From, class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI void __assign_value(__get_hash_node_value_type_t<_Tp>& __lhs, _From&& __rhs) {
+ using __key_type = typename _NodeTypes::key_type;
+
+ // This is technically UB, since the object was constructed as `const`.
+ // Clang doesn't optimize on this currently though.
+ const_cast<__key_type&>(__lhs.first) = const_cast<__copy_cvref_t<_From, __key_type>&&>(__rhs.first);
+ __lhs.second = std::forward<_From>(__rhs).second;
+ }
+
+ template <class _From, class _ValueT = _Tp, __enable_if_t<!__is_hash_value_type<_ValueT>::value, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI void __assign_value(_Tp& __lhs, _From&& __rhs) {
+ __lhs = std::forward<_From>(__rhs);
+ }
+
template <class, class, class, class, class>
friend class unordered_map;
template <class, class, class, class, class>
@@ -1216,8 +1279,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
#endif // _LIBCPP_HAS_EXCEPTIONS
const_iterator __i = __u.begin();
while (__cache != nullptr && __u.size() != 0) {
- __cache->__upcast()->__get_value() = std::move(__u.remove(__i++)->__get_value());
- __next_pointer __next = __cache->__next_;
+ __assign_value(__cache->__upcast()->__get_value(), std::move(__u.remove(__i++)->__get_value()));
+ __next_pointer __next = __cache->__next_;
__node_insert_multi(__cache->__upcast());
__cache = __next;
}
@@ -1230,11 +1293,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
__deallocate_node(__cache);
}
const_iterator __i = __u.begin();
- while (__u.size() != 0) {
- __node_holder __h = __construct_node(_NodeTypes::__move(__u.remove(__i++)->__get_value()));
- __node_insert_multi(__h.get());
- __h.release();
- }
+ while (__u.size() != 0)
+ __insert_multi_from_orphaned_node(std::move(__u.remove(__i++)->__get_value()));
}
}
@@ -1262,8 +1322,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __
try {
#endif // _LIBCPP_HAS_EXCEPTIONS
for (; __cache != nullptr && __first != __last; ++__first) {
- __cache->__upcast()->__get_value() = *__first;
- __next_pointer __next = __cache->__next_;
+ __assign_value(__cache->__upcast()->__get_value(), *__first);
+ __next_pointer __next = __cache->__next_;
__node_insert_unique(__cache->__upcast());
__cache = __next;
}
@@ -1294,7 +1354,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
try {
#endif // _LIBCPP_HAS_EXCEPTIONS
for (; __cache != nullptr && __first != __last; ++__first) {
- __cache->__upcast()->__get_value() = *__first;
+ __assign_value(__cache->__upcast()->__get_value(), *__first);
__next_pointer __next = __cache->__next_;
__node_insert_multi(__cache->__upcast());
__cache = __next;
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index b7f333e5f1178..484f22ce5d72d 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -654,9 +654,7 @@ public:
_LIBCPP_HIDE_FROM_ABI __unordered_map_hasher(const _Hash& __h) _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value)
: _Hash(__h) {}
_LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const _NOEXCEPT { return *this; }
- _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const {
- return static_cast<const _Hash&>(*this)(__x.__get_value().first);
- }
+ _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return static_cast<const _Hash&>(*this)(__x.first); }
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Key& __x) const { return static_cast<const _Hash&>(*this)(__x); }
# if _LIBCPP_STD_VER >= 20
template <typename _K2>
@@ -680,7 +678,7 @@ public:
_LIBCPP_HIDE_FROM_ABI __unordered_map_hasher(const _Hash& __h) _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value)
: __hash_(__h) {}
_LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const _NOEXCEPT { return __hash_; }
- _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return __hash_(__x.__get_value().first); }
+ _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return __hash_(__x.first); }
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Key& __x) const { return __hash_(__x); }
# if _LIBCPP_STD_VER >= 20
template <typename _K2>
@@ -713,10 +711,10 @@ public:
: _Pred(__p) {}
_LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const _NOEXCEPT { return *this; }
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const {
- return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y.__get_value().first);
+ return static_cast<const _Pred&>(*this)(__x.first, __y.first);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const {
- return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);
+ return static_cast<const _Pred&>(*this)(__x.first, __y);
}
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const {
return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);
@@ -724,7 +722,7 @@ public:
# if _LIBCPP_STD_VER >= 20
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _K2& __y) const {
- return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);
+ return static_cast<const _Pred&>(*this)(__x.first, __y);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const {
@@ -755,23 +753,17 @@ public:
_LIBCPP_HIDE_FROM_ABI __unordered_map_equal(const _Pred& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_Pred>::value)
: __pred_(__p) {}
_LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const _NOEXCEPT { return __pred_; }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const {
- return __pred_(__x.__get_value().first, __y.__get_value().first);
- }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const {
- return __pred_(__x.__get_value().first, __y);
- }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const {
- return __pred_(__x, __y.__get_value().first);
- }
+ _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const { return __pred_(__x.first, __y.first); }
+ _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const { return __pred_(__x.first, __y); }
+ _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const { return __pred_(__x, __y.first); }
# if _LIBCPP_STD_VER >= 20
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _K2& __y) const {
- return __pred_(__x.__get_value().first, __y);
+ return __pred_(__x.first, __y);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const {
- return __pred_(__x, __y.__get_value().first);
+ return __pred_(__x, __y.first);
}
template <typename _K2>
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _K2& __y) const {
@@ -833,96 +825,16 @@ public:
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
if (__second_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().__get_value().second));
+ __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().second));
if (__first_constructed)
- __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().__get_value().first));
+ __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().first));
if (__p)
__alloc_traits::deallocate(__na_, __p, 1);
}
};
-# ifndef _LIBCPP_CXX03_LANG
template <class _Key, class _Tp>
-struct _LIBCPP_STANDALONE_DEBUG __hash_value_type {
- typedef _Key key_type;
- typedef _Tp mapped_type;
- typedef pair<const key_type, mapped_type> value_type;
- typedef pair<key_type&, mapped_type&> __nc_ref_pair_type;
- typedef pair<key_type&&, mapped_type&&> __nc_rref_pair_type;
-
-private:
- value_type __cc_;
-
-public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() {
-# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
-# else
- return __cc_;
-# endif
- }
-
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const {
-# if _LIBCPP_STD_VER >= 17
- return *std::launder(std::addressof(__cc_));
-# else
- return __cc_;
-# endif
- }
-
- _LIBCPP_HIDE_FROM_ABI __nc_ref_pair_type __ref() {
- value_type& __v = __get_value();
- return __nc_ref_pair_type(const_cast<key_type&>(__v.first), __v.second);
- }
-
- _LIBCPP_HIDE_FROM_ABI __nc_rref_pair_type __move() {
- value_type& __v = __get_value();
- return __nc_rref_pair_type(std::move(const_cast<key_type&>(__v.first)), std::move(__v.second));
- }
-
- _LIBCPP_HIDE_FROM_ABI __hash_value_type& operator=(const __hash_value_type& __v) {
- __ref() = __v.__get_value();
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI __hash_value_type& operator=(__hash_value_type&& __v) {
- __ref() = __v.__move();
- return *this;
- }
-
- template <class _ValueTp, __enable_if_t<__is_same_uncvref<_ValueTp, value_type>::value, int> = 0>
- _LIBCPP_HIDE_FROM_ABI __hash_value_type& operator=(_ValueTp&& __v) {
- __ref() = std::forward<_ValueTp>(__v);
- return *this;
- }
-
- __hash_value_type(const __hash_value_type& __v) = delete;
- __hash_value_type(__hash_value_type&& __v) = delete;
- template <class... _Args>
- explicit __hash_value_type(_Args&&... __args) = delete;
-
- ~__hash_value_type() = delete;
-};
-
-# else
-
-template <class _Key, class _Tp>
-struct __hash_value_type {
- typedef _Key key_type;
- typedef _Tp mapped_type;
- typedef pair<const key_type, mapped_type> value_type;
-
-private:
- value_type __cc_;
-
-public:
- _LIBCPP_HIDE_FROM_ABI value_type& __get_value() { return __cc_; }
- _LIBCPP_HIDE_FROM_ABI const value_type& __get_value() const { return __cc_; }
-
- ~__hash_value_type() = delete;
-};
-
-# endif
+struct __hash_value_type;
template <class _HashIterator>
class __hash_map_iterator {
@@ -941,8 +853,8 @@ public:
_LIBCPP_HIDE_FROM_ABI __hash_map_iterator(_HashIterator __i) _NOEXCEPT : __i_(__i) {}
- _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __i_->__get_value(); }
- _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__i_->__get_value()); }
+ _LIBCPP_HIDE_FROM_ABI reference operator*() const { return *__i_; }
+ _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(*__i_); }
_LIBCPP_HIDE_FROM_ABI __hash_map_iterator& operator++() {
++__i_;
@@ -995,8 +907,8 @@ public:
__hash_map_const_iterator(__hash_map_iterator<typename _HashIterator::__non_const_iterator> __i) _NOEXCEPT
: __i_(__i.__i_) {}
- _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __i_->__get_value(); }
- _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__i_->__get_value()); }
+ _LIBCPP_HIDE_FROM_ABI reference operator*() const { return *__i_; }
+ _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(*__i_); }
_LIBCPP_HIDE_FROM_ABI __hash_map_const_iterator& operator++() {
++__i_;
@@ -1053,8 +965,8 @@ public:
private:
typedef __hash_value_type<key_type, mapped_type> __value_type;
- typedef __unordered_map_hasher<key_type, __value_type, hasher, key_equal> __hasher;
- typedef __unordered_map_equal<key_type, __value_type, key_equal, hasher> __key_equal;
+ typedef __unordered_map_hasher<key_type, value_type, hasher, key_equal> __hasher;
+ typedef __unordered_map_equal<key_type, value_type, key_equal, hasher> __key_equal;
typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
typedef __hash_table<__value_type, __hasher, __key_equal, __allocator_type> __table;
@@ -1073,9 +985,6 @@ private:
static_assert(__check_valid_allocator<allocator_type>::value, "");
- static_assert(is_same<typename __table::__container_value_type, value_type>::value, "");
- static_assert(is_same<typename __table::__node_value_type, __value_type>::value, "");
-
public:
typedef typename __alloc_traits::pointer pointer;
typedef typename __alloc_traits::const_pointer const_pointer;
@@ -1680,9 +1589,8 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(unordered_map&& __
: __table_(std::move(__u.__table_), typename __table::allocator_type(__a)) {
if (__a != __u.get_allocator()) {
iterator __i = __u.begin();
- while (__u.size() != 0) {
- __table_.__emplace_unique(__u.__table_.remove((__i++).__i_)->__get_value().__move());
- }
+ while (__u.size() != 0)
+ __table_.__insert_unique_from_orphaned_node(std::move(__u.__table_.remove((__i++).__i_)->__get_value()));
}
}
@@ -1741,8 +1649,7 @@ template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
_Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k) {
return __table_
.__emplace_unique_key_args(__k, piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
- .first->__get_value()
- .second;
+ .first->second;
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
@@ -1750,8 +1657,7 @@ _Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k)
return __table_
.__emplace_unique_key_args(
__k, piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
- .first->__get_value()
- .second;
+ .first->second;
}
# else // _LIBCPP_CXX03_LANG
@@ -1760,9 +1666,9 @@ typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node_with_key(const key_type& __k) {
__node_allocator& __na = __table_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, std::addressof(__h->__get_value().__get_value().first), __k);
+ __node_traits::construct(__na, std::addressof(__h->__get_value().first), __k);
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, std::addressof(__h->__get_value().__get_value().second));
+ __node_traits::construct(__na, std::addressof(__h->__get_value().second));
__h.get_deleter().__second_constructed = true;
return __h;
}
@@ -1869,8 +1775,8 @@ public:
private:
typedef __hash_value_type<key_type, mapped_type> __value_type;
- typedef __unordered_map_hasher<key_type, __value_type, hasher, key_equal> __hasher;
- typedef __unordered_map_equal<key_type, __value_type, key_equal, hasher> __key_equal;
+ typedef __unordered_map_hasher<key_type, value_type, hasher, key_equal> __hasher;
+ typedef __unordered_map_equal<key_type, value_type, key_equal, hasher> __key_equal;
typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
typedef __hash_table<__value_type, __hasher, __key_equal, __allocator_type> __table;
@@ -2439,9 +2345,8 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
: __table_(std::move(__u.__table_), typename __table::allocator_type(__a)) {
if (__a != __u.get_allocator()) {
iterator __i = __u.begin();
- while (__u.size() != 0) {
- __table_.__insert_multi(__u.__table_.remove((__i++).__i_)->__get_value().__move());
- }
+ while (__u.size() != 0)
+ __table_.__insert_multi_from_orphaned_node(std::move(__u.__table_.remove((__i++).__i_)->__get_value()));
}
}
diff --git a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/assign_copy.pass.cpp b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/assign_copy.pass.cpp
index 25851e941a7d1..e606e538efcbe 100644
--- a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/assign_copy.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/assign_copy.pass.cpp
@@ -20,6 +20,7 @@
#include <cfloat>
#include <cmath>
#include <cstddef>
+#include <utility>
#include "test_macros.h"
#include "../../../test_compare.h"
@@ -109,6 +110,19 @@ int main(int, char**) {
assert(c.max_load_factor() == 1);
}
#endif
+ { // Test with std::pair, since we have some special handling for pairs inside __hash_table
+ struct pair_hash {
+ size_t operator()(std::pair<int, int> val) const TEST_NOEXCEPT { return val.first | val.second; }
+ };
+
+ std::pair<int, int> arr[] = {
+ std::make_pair(1, 2), std::make_pair(2, 3), std::make_pair(3, 4), std::make_pair(4, 5)};
+ std::unordered_set<std::pair<int, int>, pair_hash> a(arr, arr + 4);
+ std::unordered_set<std::pair<int, int>, pair_hash> b;
+
+ b = a;
+ assert(a == b);
+ }
return 0;
}
diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py
index 90bc54d987ee8..1c8ef6d7feb97 100644
--- a/libcxx/utils/gdb/libcxx/printers.py
+++ b/libcxx/utils/gdb/libcxx/printers.py
@@ -65,16 +65,6 @@ def _remove_generics(typename):
return match.group(1)
-def _cc_field(node):
- """Previous versions of libcxx had inconsistent field naming naming. Handle
- both types.
- """
- try:
- return node["__value_"]["__cc_"]
- except:
- return node["__value_"]["__cc"]
-
-
def _data_field(node):
"""Previous versions of libcxx had inconsistent field naming naming. Handle
both types.
@@ -829,7 +819,7 @@ class StdUnorderedMapPrinter(AbstractUnorderedCollectionPrinter):
"""Print a std::unordered_(multi)map."""
def _get_key_value(self, node):
- key_value = _cc_field(node)
+ key_value = node["__value_"]
return [key_value["first"], key_value["second"]]
def display_hint(self):
@@ -885,7 +875,7 @@ def __init__(self, val):
self._initialize(val, val["__i_"]["__node_"])
def _get_key_value(self):
- key_value = _cc_field(self.node)
+ key_value = self.node["__value_"]
return [key_value["first"], key_value["second"]]
def display_hint(self):
More information about the libcxx-commits
mailing list