[libcxx-commits] [libcxx] [libc++] Avoid type-punning between __value_type and pair (PR #134819)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sat Apr 12 01:22:47 PDT 2025


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/134819

>From 0eeaaaf975182a1a5818f798d1dab502f6a525e2 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 7 Apr 2025 15:01:38 +0200
Subject: [PATCH] [libc++] Avoid type-punning between __Value_type and pair

---
 libcxx/include/__fwd/pair.h                   |   6 +
 .../__memory/uses_allocator_construction.h    |   9 +-
 libcxx/include/__node_handle                  |  32 ++++-
 libcxx/include/__tree                         |  97 ++++++++------
 libcxx/include/map                            | 125 +++++-------------
 .../tree_key_value_traits.pass.cpp            |   4 -
 libcxx/utils/gdb/libcxx/printers.py           |   4 +-
 7 files changed, 124 insertions(+), 153 deletions(-)

diff --git a/libcxx/include/__fwd/pair.h b/libcxx/include/__fwd/pair.h
index ea81a81ef8e11..cf07eabab6903 100644
--- a/libcxx/include/__fwd/pair.h
+++ b/libcxx/include/__fwd/pair.h
@@ -22,6 +22,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 template <class, class>
 struct pair;
 
+template <class _Type>
+inline const bool __is_pair_v = false;
+
+template <class _Type1, class _Type2>
+inline const bool __is_pair_v<pair<_Type1, _Type2> > = true;
+
 template <size_t _Ip, class _T1, class _T2>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type&
 get(pair<_T1, _T2>&) _NOEXCEPT;
diff --git a/libcxx/include/__memory/uses_allocator_construction.h b/libcxx/include/__memory/uses_allocator_construction.h
index 955879ffc5845..49ddf99d9cc95 100644
--- a/libcxx/include/__memory/uses_allocator_construction.h
+++ b/libcxx/include/__memory/uses_allocator_construction.h
@@ -14,7 +14,6 @@
 #include <__memory/uses_allocator.h>
 #include <__tuple/tuple_like_no_subrange.h>
 #include <__type_traits/enable_if.h>
-#include <__type_traits/is_same.h>
 #include <__type_traits/remove_cv.h>
 #include <__utility/declval.h>
 #include <__utility/pair.h>
@@ -31,14 +30,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 17
 
-template <class _Type>
-inline constexpr bool __is_std_pair = false;
-
-template <class _Type1, class _Type2>
-inline constexpr bool __is_std_pair<pair<_Type1, _Type2>> = true;
-
 template <class _Tp>
-inline constexpr bool __is_cv_std_pair = __is_std_pair<remove_cv_t<_Tp>>;
+inline constexpr bool __is_cv_std_pair = __is_pair_v<remove_cv_t<_Tp>>;
 
 template <class _Tp, class = void>
 struct __uses_allocator_construction_args;
diff --git a/libcxx/include/__node_handle b/libcxx/include/__node_handle
index 08c4ffa5ff17b..5c559c657ef50 100644
--- a/libcxx/include/__node_handle
+++ b/libcxx/include/__node_handle
@@ -62,6 +62,7 @@ public:
 #include <__config>
 #include <__memory/allocator_traits.h>
 #include <__memory/pointer_traits.h>
+#include <__type_traits/is_specialization.h>
 #include <optional>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -173,17 +174,40 @@ struct __set_node_handle_specifics {
   _LIBCPP_HIDE_FROM_ABI value_type& value() const { return static_cast<_Derived const*>(this)->__ptr_->__get_value(); }
 };
 
+template <class, class>
+struct __hash_value_type;
+
 template <class _NodeType, class _Derived>
 struct __map_node_handle_specifics {
-  typedef typename _NodeType::__node_value_type::key_type key_type;
-  typedef typename _NodeType::__node_value_type::mapped_type mapped_type;
+  template <class _Tp>
+  struct __get_type {
+    using key_type    = __remove_const_t<typename _Tp::first_type>;
+    using mapped_type = typename _Tp::second_type;
+  };
+
+  template <class _Key, class _Mapped>
+  struct __get_type<__hash_value_type<_Key, _Mapped> > {
+    using key_type    = _Key;
+    using mapped_type = _Mapped;
+  };
+
+  using key_type    = typename __get_type<typename _NodeType::__node_value_type>::key_type;
+  using mapped_type = typename __get_type<typename _NodeType::__node_value_type>::mapped_type;
 
   _LIBCPP_HIDE_FROM_ABI key_type& key() const {
-    return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().first;
+    if constexpr (__is_specialization_v<typename _NodeType::__node_value_type, __hash_value_type>) {
+      return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().first;
+    } else {
+      return const_cast<key_type&>(static_cast<_Derived const*>(this)->__ptr_->__get_value().first);
+    }
   }
 
   _LIBCPP_HIDE_FROM_ABI mapped_type& mapped() const {
-    return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().second;
+    if constexpr (__is_specialization_v<typename _NodeType::__node_value_type, __hash_value_type>) {
+      return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().second;
+    } else {
+      return static_cast<_Derived const*>(this)->__ptr_->__get_value().second;
+    }
   }
 };
 
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index e84bc4ffda0bd..4275133f8a351 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -14,6 +14,7 @@
 #include <__assert>
 #include <__config>
 #include <__fwd/map.h>
+#include <__fwd/pair.h>
 #include <__fwd/set.h>
 #include <__iterator/distance.h>
 #include <__iterator/iterator_traits.h>
@@ -25,6 +26,7 @@
 #include <__memory/swap_allocator.h>
 #include <__memory/unique_ptr.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>
@@ -505,48 +507,24 @@ struct __is_tree_value_type<_One> : __is_tree_value_type_imp<__remove_cvref_t<_O
 template <class _Tp>
 struct __tree_key_value_types {
   typedef _Tp key_type;
-  typedef _Tp __node_value_type;
   typedef _Tp __container_value_type;
   static const bool __is_map = false;
 
   _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(_Tp const& __v) { return __v; }
-  _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __v) { return __v; }
-  _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) { return std::addressof(__n); }
-  _LIBCPP_HIDE_FROM_ABI static __container_value_type&& __move(__node_value_type& __v) { return std::move(__v); }
 };
 
 template <class _Key, class _Tp>
 struct __tree_key_value_types<__value_type<_Key, _Tp> > {
   typedef _Key key_type;
   typedef _Tp mapped_type;
-  typedef __value_type<_Key, _Tp> __node_value_type;
   typedef pair<const _Key, _Tp> __container_value_type;
   typedef __container_value_type __map_value_type;
   static const bool __is_map = true;
 
-  _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(__node_value_type const& __t) {
-    return __t.__get_value().first;
-  }
-
   template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(_Up& __t) {
     return __t.first;
   }
-
-  _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __t) {
-    return __t.__get_value();
-  }
-
-  template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) {
-    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 pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
 };
 
 template <class _VoidPtr>
@@ -587,6 +565,19 @@ struct __tree_map_pointer_types<_Tp, _AllocPtr, _KVTypes, true> {
   typedef __rebind_pointer_t<_AllocPtr, const _Mv> __const_map_value_type_pointer;
 };
 
+template <class _Tp>
+struct __get_node_value_type {
+  using type _LIBCPP_NODEBUG = _Tp;
+};
+
+template <class _Key, class _ValueT>
+struct __get_node_value_type<__value_type<_Key, _ValueT> > {
+  using type _LIBCPP_NODEBUG = pair<const _Key, _ValueT>;
+};
+
+template <class _Tp>
+using __get_node_value_type_t _LIBCPP_NODEBUG = typename __get_node_value_type<_Tp>::type;
+
 template <class _NodePtr, class _NodeT = typename pointer_traits<_NodePtr>::element_type>
 struct __tree_node_types;
 
@@ -601,7 +592,7 @@ public:
   typedef typename pointer_traits<_NodePtr>::element_type __node_type;
   typedef _NodePtr __node_pointer;
 
-  typedef _Tp __node_value_type;
+  using __node_value_type _LIBCPP_NODEBUG = __get_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;
   typedef typename __base::__end_node_pointer __iter_pointer;
@@ -653,11 +644,11 @@ public:
 template <class _Tp, class _VoidPtr>
 class _LIBCPP_STANDALONE_DEBUG __tree_node : public __tree_node_base<_VoidPtr> {
 public:
-  typedef _Tp __node_value_type;
+  using __node_value_type _LIBCPP_NODEBUG = __get_node_value_type_t<_Tp>;
 
   __node_value_type __value_;
 
-  _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return __value_; }
+  _LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() { return __value_; }
 
   ~__tree_node()                             = delete;
   __tree_node(__tree_node const&)            = delete;
@@ -688,7 +679,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
     if (__value_constructed)
-      __alloc_traits::destroy(__na_, _NodeTypes::__get_ptr(__p->__value_));
+      __alloc_traits::destroy(__na_, std::addressof(__p->__value_));
     if (__p)
       __alloc_traits::deallocate(__na_, __p, 1);
   }
@@ -719,7 +710,7 @@ class __tree_iterator {
 
 public:
   typedef bidirectional_iterator_tag iterator_category;
-  typedef _Tp value_type;
+  using value_type = __get_node_value_type_t<_Tp>;
   typedef _DiffType difference_type;
   typedef value_type& reference;
   typedef typename _NodeTypes::__node_value_type_pointer pointer;
@@ -796,7 +787,7 @@ class __tree_const_iterator {
 
 public:
   typedef bidirectional_iterator_tag iterator_category;
-  typedef _Tp value_type;
+  using value_type = __get_node_value_type_t<_Tp>;
   typedef _DiffType difference_type;
   typedef const value_type& reference;
   typedef typename _NodeTypes::__const_node_value_type_pointer pointer;
@@ -809,7 +800,7 @@ public:
   }
 
 private:
-  typedef __tree_iterator<value_type, __node_pointer, difference_type> __non_const_iterator;
+  typedef __tree_iterator<_Tp, __node_pointer, difference_type> __non_const_iterator;
 
 public:
   _LIBCPP_HIDE_FROM_ABI __tree_const_iterator(__non_const_iterator __p) _NOEXCEPT : __ptr_(__p.__ptr_) {}
@@ -1135,6 +1126,17 @@ public:
     return __emplace_hint_multi(__p, std::forward<_Vp>(__v));
   }
 
+  template <class _ValueT = _Tp, __enable_if_t<__is_tree_value_type<_ValueT>::value, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI void __insert_from_orphaned_node(const_iterator __p, __get_node_value_type_t<_Tp>&& __value) {
+    using __key_type = typename _NodeTypes::key_type;
+    __emplace_hint_multi(__p, const_cast<__key_type&&>(__value.first), std::move(__value.second));
+  }
+
+  template <class _ValueT = _Tp, __enable_if_t<!__is_tree_value_type<_ValueT>::value, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI void __insert_from_orphaned_node(const_iterator __p, _Tp&& __value) {
+    __emplace_hint_multi(__p, std::move(__value));
+  }
+
   _LIBCPP_HIDE_FROM_ABI pair<iterator, bool>
   __node_assign_unique(const __container_value_type& __v, __node_pointer __dest);
 
@@ -1276,6 +1278,19 @@ private:
   }
   _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__tree&, false_type) _NOEXCEPT {}
 
+  template <class _From, __enable_if_t<__is_pair_v<__remove_cvref_t<_From> >, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI static void __assign_value(__get_node_value_type_t<value_type>& __lhs, _From&& __rhs) {
+    using __key_type = typename _NodeTypes::key_type;
+
+    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 _To, class _From, class _ValueT = _Tp, __enable_if_t<!__is_pair_v<__remove_cvref_t<_From> >, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI static void __assign_value(_To& __lhs, _From&& __rhs) {
+    __lhs = std::forward<_From>(__rhs);
+  }
+
   struct _DetachedTreeCache {
     _LIBCPP_HIDE_FROM_ABI explicit _DetachedTreeCache(__tree* __t) _NOEXCEPT
         : __t_(__t),
@@ -1416,13 +1431,13 @@ void __tree<_Tp, _Compare, _Allocator>::__assign_multi(_InputIterator __first, _
   if (size() != 0) {
     _DetachedTreeCache __cache(this);
     for (; __cache.__get() && __first != __last; ++__first) {
-      __cache.__get()->__value_ = *__first;
+      __assign_value(__cache.__get()->__value_, *__first);
       __node_insert_multi(__cache.__get());
       __cache.__advance();
     }
   }
   for (; __first != __last; ++__first)
-    __insert_multi(_NodeTypes::__get_value(*__first));
+    __insert_multi(*__first);
 }
 
 template <class _Tp, class _Compare, class _Allocator>
@@ -1501,13 +1516,14 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, false_type) {
     if (size() != 0) {
       _DetachedTreeCache __cache(this);
       while (__cache.__get() != nullptr && __t.size() != 0) {
-        __cache.__get()->__value_ = std::move(__t.remove(__t.begin())->__value_);
+        __assign_value(__cache.__get()->__value_, std::move(__t.remove(__t.begin())->__value_));
         __node_insert_multi(__cache.__get());
         __cache.__advance();
       }
     }
-    while (__t.size() != 0)
-      __insert_multi(__e, _NodeTypes::__move(__t.remove(__t.begin())->__value_));
+    while (__t.size() != 0) {
+      __insert_from_orphaned_node(__e, std::move(__t.remove(__t.begin())->__value_));
+    }
   }
 }
 
@@ -1533,7 +1549,7 @@ void __tree<_Tp, _Compare, _Allocator>::destroy(__node_pointer __nd) _NOEXCEPT {
     destroy(static_cast<__node_pointer>(__nd->__left_));
     destroy(static_cast<__node_pointer>(__nd->__right_));
     __node_allocator& __na = __node_alloc();
-    __node_traits::destroy(__na, _NodeTypes::__get_ptr(__nd->__value_));
+    __node_traits::destroy(__na, std::addressof(__nd->__value_));
     __node_traits::deallocate(__na, __nd, 1);
   }
 }
@@ -1803,10 +1819,9 @@ template <class _Tp, class _Compare, class _Allocator>
 template <class... _Args>
 typename __tree<_Tp, _Compare, _Allocator>::__node_holder
 __tree<_Tp, _Compare, _Allocator>::__construct_node(_Args&&... __args) {
-  static_assert(!__is_tree_value_type<_Args...>::value, "Cannot construct from __value_type");
   __node_allocator& __na = __node_alloc();
   __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-  __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), std::forward<_Args>(__args)...);
+  __node_traits::construct(__na, std::addressof(__h->__value_), std::forward<_Args>(__args)...);
   __h.get_deleter().__value_constructed = true;
   return __h;
 }
@@ -1874,7 +1889,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_assign_unique(const __container_value_
   __node_pointer __r           = static_cast<__node_pointer>(__child);
   bool __inserted              = false;
   if (__child == nullptr) {
-    __nd->__value_ = __v;
+    __assign_value(__nd->__value_, __v);
     __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd));
     __r        = __nd;
     __inserted = true;
@@ -2036,7 +2051,7 @@ typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allo
   __node_pointer __np    = __p.__get_np();
   iterator __r           = __remove_node_pointer(__np);
   __node_allocator& __na = __node_alloc();
-  __node_traits::destroy(__na, _NodeTypes::__get_ptr(const_cast<__node_value_type&>(*__p)));
+  __node_traits::destroy(__na, std::addressof(const_cast<__node_value_type&>(*__p)));
   __node_traits::deallocate(__na, __np, 1);
   return __r;
 }
diff --git a/libcxx/include/map b/libcxx/include/map
index a244696295fb8..1821aa0155a29 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -593,7 +593,6 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred);  // C++20
 #  include <__memory/pointer_traits.h>
 #  include <__memory/unique_ptr.h>
 #  include <__memory_resource/polymorphic_allocator.h>
-#  include <__new/launder.h>
 #  include <__node_handle>
 #  include <__ranges/concepts.h>
 #  include <__ranges/container_compatible_range.h>
@@ -645,13 +644,13 @@ public:
       : _Compare(__c) {}
   _LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return *this; }
   _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
-    return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y.__get_value().first);
+    return static_cast<const _Compare&>(*this)(__x.first, __y.first);
   }
   _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
-    return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
+    return static_cast<const _Compare&>(*this)(__x.first, __y);
   }
   _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
-    return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
+    return static_cast<const _Compare&>(*this)(__x, __y.first);
   }
   _LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
     using std::swap;
@@ -661,12 +660,12 @@ public:
 #  if _LIBCPP_STD_VER >= 14
   template <typename _K2>
   _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
-    return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
+    return static_cast<const _Compare&>(*this)(__x, __y.first);
   }
 
   template <typename _K2>
   _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
-    return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
+    return static_cast<const _Compare&>(*this)(__x.first, __y);
   }
 #  endif
 };
@@ -682,15 +681,9 @@ public:
       : __comp_(__c) {}
   _LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return __comp_; }
 
-  _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
-    return __comp_(__x.__get_value().first, __y.__get_value().first);
-  }
-  _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
-    return __comp_(__x.__get_value().first, __y);
-  }
-  _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
-    return __comp_(__x, __y.__get_value().first);
-  }
+  _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const { return __comp_(__x.first, __y.first); }
+  _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const { return __comp_(__x.first, __y); }
+  _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const { return __comp_(__x, __y.first); }
   void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
     using std::swap;
     swap(__comp_, __y.__comp_);
@@ -749,9 +742,9 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
     if (__second_constructed)
-      __alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().second));
+      __alloc_traits::destroy(__na_, std::addressof(__p->__value_.second));
     if (__first_constructed)
-      __alloc_traits::destroy(__na_, std::addressof(__p->__value_.__get_value().first));
+      __alloc_traits::destroy(__na_, std::addressof(__p->__value_.first));
     if (__p)
       __alloc_traits::deallocate(__na_, __p, 1);
   }
@@ -763,64 +756,7 @@ class __map_const_iterator;
 #  ifndef _LIBCPP_CXX03_LANG
 
 template <class _Key, class _Tp>
-struct _LIBCPP_STANDALONE_DEBUG __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 __value_type& operator=(const __value_type& __v) {
-    __ref() = __v.__get_value();
-    return *this;
-  }
-
-  _LIBCPP_HIDE_FROM_ABI __value_type& operator=(__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 __value_type& operator=(_ValueTp&& __v) {
-    __ref() = std::forward<_ValueTp>(__v);
-    return *this;
-  }
-
-  __value_type()                    = delete;
-  ~__value_type()                   = delete;
-  __value_type(const __value_type&) = delete;
-  __value_type(__value_type&&)      = delete;
-};
+struct _LIBCPP_STANDALONE_DEBUG __value_type;
 
 #  else
 
@@ -872,8 +808,8 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI __map_iterator(_TreeIterator __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 __map_iterator& operator++() {
     ++__i_;
@@ -930,8 +866,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI
   __map_const_iterator(__map_iterator< typename _TreeIterator::__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 __map_const_iterator& operator++() {
     ++__i_;
@@ -999,7 +935,7 @@ public:
 
 private:
   typedef std::__value_type<key_type, mapped_type> __value_type;
-  typedef __map_value_compare<key_type, __value_type, key_compare> __vc;
+  typedef __map_value_compare<key_type, value_type, key_compare> __vc;
   typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
   typedef __tree<__value_type, __vc, __allocator_type> __base;
   typedef typename __base::__node_traits __node_traits;
@@ -1305,7 +1241,7 @@ public:
         __tree_.__emplace_hint_unique_key_args(__h.__i_, __k, std::move(__k), std::forward<_Vp>(__v));
 
     if (!__inserted)
-      __r->__get_value().second = std::forward<_Vp>(__v);
+      __r->second = std::forward<_Vp>(__v);
 
     return __r;
   }
@@ -1510,8 +1446,10 @@ map<_Key, _Tp, _Compare, _Allocator>::map(map&& __m, const allocator_type& __a)
     : __tree_(std::move(__m.__tree_), typename __base::allocator_type(__a)) {
   if (__a != __m.get_allocator()) {
     const_iterator __e = cend();
-    while (!__m.empty())
-      __tree_.__insert_unique(__e.__i_, __m.__tree_.remove(__m.begin().__i_)->__value_.__move());
+    while (!__m.empty()) {
+      __tree_.__insert_unique(
+          __e.__i_, reinterpret_cast<pair<_Key, _Tp>&&>(__m.__tree_.remove(__m.begin().__i_)->__value_));
+    }
   }
 }
 
@@ -1519,8 +1457,7 @@ template <class _Key, class _Tp, class _Compare, class _Allocator>
 _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
   return __tree_
       .__emplace_unique_key_args(__k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple())
-      .first->__get_value()
-      .second;
+      .first->second;
 }
 
 template <class _Key, class _Tp, class _Compare, class _Allocator>
@@ -1530,8 +1467,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k) {
   return __tree_
       .__emplace_unique_key_args(
           __k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple())
-      .first->__get_value()
-      .second;
+      .first->second;
   // NOLINTEND(bugprone-use-after-move)
 }
 
@@ -1542,9 +1478,9 @@ typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
 map<_Key, _Tp, _Compare, _Allocator>::__construct_node_with_key(const key_type& __k) {
   __node_allocator& __na = __tree_.__node_alloc();
   __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-  __node_traits::construct(__na, std::addressof(__h->__value_.__get_value().first), __k);
+  __node_traits::construct(__na, std::addressof(__h->__value_.first), __k);
   __h.get_deleter().__first_constructed = true;
-  __node_traits::construct(__na, std::addressof(__h->__value_.__get_value().second));
+  __node_traits::construct(__na, std::addressof(__h->__value_.second));
   __h.get_deleter().__second_constructed = true;
   return __h;
 }
@@ -1559,7 +1495,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) {
     __tree_.__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
     __r = __h.release();
   }
-  return __r->__value_.__get_value().second;
+  return __r->__value_.second;
 }
 
 #  endif // _LIBCPP_CXX03_LANG
@@ -1570,7 +1506,7 @@ _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) {
   __node_base_pointer& __child = __tree_.__find_equal(__parent, __k);
   if (__child == nullptr)
     std::__throw_out_of_range("map::at:  key not found");
-  return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
+  return static_cast<__node_pointer>(__child)->__value_.second;
 }
 
 template <class _Key, class _Tp, class _Compare, class _Allocator>
@@ -1579,7 +1515,7 @@ const _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const {
   __node_base_pointer __child = __tree_.__find_equal(__parent, __k);
   if (__child == nullptr)
     std::__throw_out_of_range("map::at:  key not found");
-  return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
+  return static_cast<__node_pointer>(__child)->__value_.second;
 }
 
 template <class _Key, class _Tp, class _Compare, class _Allocator>
@@ -1685,7 +1621,7 @@ public:
 
 private:
   typedef std::__value_type<key_type, mapped_type> __value_type;
-  typedef __map_value_compare<key_type, __value_type, key_compare> __vc;
+  typedef __map_value_compare<key_type, value_type, key_compare> __vc;
   typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
   typedef __tree<__value_type, __vc, __allocator_type> __base;
   typedef typename __base::__node_traits __node_traits;
@@ -2100,7 +2036,8 @@ multimap<_Key, _Tp, _Compare, _Allocator>::multimap(multimap&& __m, const alloca
   if (__a != __m.get_allocator()) {
     const_iterator __e = cend();
     while (!__m.empty())
-      __tree_.__insert_multi(__e.__i_, std::move(__m.__tree_.remove(__m.begin().__i_)->__value_.__move()));
+      __tree_.__insert_multi(
+          __e.__i_, reinterpret_cast<pair<_Key, _Tp>&&>(__m.__tree_.remove(__m.begin().__i_)->__value_));
   }
 }
 #  endif
diff --git a/libcxx/test/libcxx/containers/associative/tree_key_value_traits.pass.cpp b/libcxx/test/libcxx/containers/associative/tree_key_value_traits.pass.cpp
index e3a5a6f634138..04dcb8f54fafc 100644
--- a/libcxx/test/libcxx/containers/associative/tree_key_value_traits.pass.cpp
+++ b/libcxx/test/libcxx/containers/associative/tree_key_value_traits.pass.cpp
@@ -21,7 +21,6 @@ void testKeyValueTrait() {
     typedef int Tp;
     typedef std::__tree_key_value_types<Tp> Traits;
     static_assert((std::is_same<Traits::key_type, int>::value), "");
-    static_assert((std::is_same<Traits::__node_value_type, Tp>::value), "");
     static_assert((std::is_same<Traits::__container_value_type, Tp>::value), "");
     static_assert(Traits::__is_map == false, "");
   }
@@ -29,7 +28,6 @@ void testKeyValueTrait() {
     typedef std::pair<int, int> Tp;
     typedef std::__tree_key_value_types<Tp> Traits;
     static_assert((std::is_same<Traits::key_type, Tp>::value), "");
-    static_assert((std::is_same<Traits::__node_value_type, Tp>::value), "");
     static_assert((std::is_same<Traits::__container_value_type, Tp>::value), "");
     static_assert(Traits::__is_map == false, "");
   }
@@ -37,7 +35,6 @@ void testKeyValueTrait() {
     typedef std::pair<const int, int> Tp;
     typedef std::__tree_key_value_types<Tp> Traits;
     static_assert((std::is_same<Traits::key_type, Tp>::value), "");
-    static_assert((std::is_same<Traits::__node_value_type, Tp>::value), "");
     static_assert((std::is_same<Traits::__container_value_type, Tp>::value), "");
     static_assert(Traits::__is_map == false, "");
   }
@@ -46,7 +43,6 @@ void testKeyValueTrait() {
     typedef std::__tree_key_value_types<Tp> Traits;
     static_assert((std::is_same<Traits::key_type, int>::value), "");
     static_assert((std::is_same<Traits::mapped_type, int>::value), "");
-    static_assert((std::is_same<Traits::__node_value_type, Tp>::value), "");
     static_assert((std::is_same<Traits::__container_value_type, std::pair<const int, int> >::value), "");
     static_assert((std::is_same<Traits::__map_value_type, std::pair<const int, int> >::value), "");
     static_assert(Traits::__is_map == true, "");
diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py
index 31c27a1959cb2..e3d5d87aca325 100644
--- a/libcxx/utils/gdb/libcxx/printers.py
+++ b/libcxx/utils/gdb/libcxx/printers.py
@@ -673,7 +673,7 @@ def display_hint(self):
         return "map"
 
     def _get_key_value(self, node):
-        key_value = _cc_field(node.cast(self.util.cast_type).dereference())
+        key_value = node.cast(self.util.cast_type).dereference()["__value_"]
         return [key_value["first"], key_value["second"]]
 
 
@@ -738,7 +738,7 @@ def __init__(self, val):
         self._initialize(val["__i_"], _remove_generics(_prettify_typename(val.type)))
 
     def _get_node_value(self, node):
-        return _cc_field(node)
+        return node["__value_"]
 
 
 class SetIteratorPrinter(AbstractRBTreeIteratorPrinter):



More information about the libcxx-commits mailing list