Skip to content

Commit e6b792d

Browse files
committed
[libc++] Avoid type-punning between __Value_type and pair
1 parent 4cde945 commit e6b792d

File tree

8 files changed

+125
-154
lines changed

8 files changed

+125
-154
lines changed

libcxx/include/__fwd/pair.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2222
template <class, class>
2323
struct pair;
2424

25+
template <class _Type>
26+
inline const bool __is_pair_v = false;
27+
28+
template <class _Type1, class _Type2>
29+
inline const bool __is_pair_v<pair<_Type1, _Type2> > = true;
30+
2531
template <size_t _Ip, class _T1, class _T2>
2632
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type&
2733
get(pair<_T1, _T2>&) _NOEXCEPT;

libcxx/include/__memory/uses_allocator_construction.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <__memory/uses_allocator.h>
1515
#include <__tuple/tuple_like_no_subrange.h>
1616
#include <__type_traits/enable_if.h>
17-
#include <__type_traits/is_same.h>
1817
#include <__type_traits/remove_cv.h>
1918
#include <__utility/declval.h>
2019
#include <__utility/pair.h>
@@ -31,14 +30,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
3130

3231
#if _LIBCPP_STD_VER >= 17
3332

34-
template <class _Type>
35-
inline constexpr bool __is_std_pair = false;
36-
37-
template <class _Type1, class _Type2>
38-
inline constexpr bool __is_std_pair<pair<_Type1, _Type2>> = true;
39-
4033
template <class _Tp>
41-
inline constexpr bool __is_cv_std_pair = __is_std_pair<remove_cv_t<_Tp>>;
34+
inline constexpr bool __is_cv_std_pair = __is_pair_v<remove_cv_t<_Tp>>;
4235

4336
template <class _Tp, class = void>
4437
struct __uses_allocator_construction_args;

libcxx/include/__node_handle

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public:
6262
#include <__config>
6363
#include <__memory/allocator_traits.h>
6464
#include <__memory/pointer_traits.h>
65+
#include <__type_traits/is_specialization.h>
6566
#include <optional>
6667

6768
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -173,17 +174,40 @@ struct __set_node_handle_specifics {
173174
_LIBCPP_HIDE_FROM_ABI value_type& value() const { return static_cast<_Derived const*>(this)->__ptr_->__get_value(); }
174175
};
175176

177+
template <class, class>
178+
struct __hash_value_type;
179+
176180
template <class _NodeType, class _Derived>
177181
struct __map_node_handle_specifics {
178-
typedef typename _NodeType::__node_value_type::key_type key_type;
179-
typedef typename _NodeType::__node_value_type::mapped_type mapped_type;
182+
template <class _Tp>
183+
struct __get_type {
184+
using key_type = __remove_const_t<typename _Tp::first_type>;
185+
using mapped_type = typename _Tp::second_type;
186+
};
187+
188+
template <class _Key, class _Mapped>
189+
struct __get_type<__hash_value_type<_Key, _Mapped> > {
190+
using key_type = _Key;
191+
using mapped_type = _Mapped;
192+
};
193+
194+
using key_type = typename __get_type<typename _NodeType::__node_value_type>::key_type;
195+
using mapped_type = typename __get_type<typename _NodeType::__node_value_type>::mapped_type;
180196

181197
_LIBCPP_HIDE_FROM_ABI key_type& key() const {
182-
return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().first;
198+
if constexpr (__is_specialization_v<typename _NodeType::__node_value_type, __hash_value_type>) {
199+
return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().first;
200+
} else {
201+
return const_cast<key_type&>(static_cast<_Derived const*>(this)->__ptr_->__get_value().first);
202+
}
183203
}
184204

185205
_LIBCPP_HIDE_FROM_ABI mapped_type& mapped() const {
186-
return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().second;
206+
if constexpr (__is_specialization_v<typename _NodeType::__node_value_type, __hash_value_type>) {
207+
return static_cast<_Derived const*>(this)->__ptr_->__get_value().__ref().second;
208+
} else {
209+
return static_cast<_Derived const*>(this)->__ptr_->__get_value().second;
210+
}
187211
}
188212
};
189213

libcxx/include/__tree

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <__assert>
1515
#include <__config>
1616
#include <__fwd/map.h>
17+
#include <__fwd/pair.h>
1718
#include <__fwd/set.h>
1819
#include <__iterator/distance.h>
1920
#include <__iterator/iterator_traits.h>
@@ -25,6 +26,7 @@
2526
#include <__memory/swap_allocator.h>
2627
#include <__memory/unique_ptr.h>
2728
#include <__type_traits/can_extract_key.h>
29+
#include <__type_traits/copy_cvref.h>
2830
#include <__type_traits/enable_if.h>
2931
#include <__type_traits/invoke.h>
3032
#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
505507
template <class _Tp>
506508
struct __tree_key_value_types {
507509
typedef _Tp key_type;
508-
typedef _Tp __node_value_type;
509510
typedef _Tp __container_value_type;
510511
static const bool __is_map = false;
511512

512513
_LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(_Tp const& __v) { return __v; }
513-
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __v) { return __v; }
514-
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) { return std::addressof(__n); }
515-
_LIBCPP_HIDE_FROM_ABI static __container_value_type&& __move(__node_value_type& __v) { return std::move(__v); }
516514
};
517515

518516
template <class _Key, class _Tp>
519517
struct __tree_key_value_types<__value_type<_Key, _Tp> > {
520518
typedef _Key key_type;
521519
typedef _Tp mapped_type;
522-
typedef __value_type<_Key, _Tp> __node_value_type;
523520
typedef pair<const _Key, _Tp> __container_value_type;
524521
typedef __container_value_type __map_value_type;
525522
static const bool __is_map = true;
526523

527-
_LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(__node_value_type const& __t) {
528-
return __t.__get_value().first;
529-
}
530-
531524
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
532525
_LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(_Up& __t) {
533526
return __t.first;
534527
}
535-
536-
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __t) {
537-
return __t.__get_value();
538-
}
539-
540-
template <class _Up, __enable_if_t<__is_same_uncvref<_Up, __container_value_type>::value, int> = 0>
541-
_LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) {
542-
return __t;
543-
}
544-
545-
_LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) {
546-
return std::addressof(__n.__get_value());
547-
}
548-
549-
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); }
550528
};
551529

552530
template <class _VoidPtr>
@@ -587,6 +565,19 @@ struct __tree_map_pointer_types<_Tp, _AllocPtr, _KVTypes, true> {
587565
typedef __rebind_pointer_t<_AllocPtr, const _Mv> __const_map_value_type_pointer;
588566
};
589567

568+
template <class _Tp>
569+
struct __get_node_value_type {
570+
using type _LIBCPP_NODEBUG = _Tp;
571+
};
572+
573+
template <class _Key, class _ValueT>
574+
struct __get_node_value_type<__value_type<_Key, _ValueT> > {
575+
using type _LIBCPP_NODEBUG = pair<const _Key, _ValueT>;
576+
};
577+
578+
template <class _Tp>
579+
using __get_node_value_type_t _LIBCPP_NODEBUG = typename __get_node_value_type<_Tp>::type;
580+
590581
template <class _NodePtr, class _NodeT = typename pointer_traits<_NodePtr>::element_type>
591582
struct __tree_node_types;
592583

@@ -601,7 +592,7 @@ public:
601592
typedef typename pointer_traits<_NodePtr>::element_type __node_type;
602593
typedef _NodePtr __node_pointer;
603594

604-
typedef _Tp __node_value_type;
595+
using __node_value_type _LIBCPP_NODEBUG = __get_node_value_type_t<_Tp>;
605596
typedef __rebind_pointer_t<_VoidPtr, __node_value_type> __node_value_type_pointer;
606597
typedef __rebind_pointer_t<_VoidPtr, const __node_value_type> __const_node_value_type_pointer;
607598
typedef typename __base::__end_node_pointer __iter_pointer;
@@ -653,11 +644,11 @@ public:
653644
template <class _Tp, class _VoidPtr>
654645
class _LIBCPP_STANDALONE_DEBUG __tree_node : public __tree_node_base<_VoidPtr> {
655646
public:
656-
typedef _Tp __node_value_type;
647+
using __node_value_type _LIBCPP_NODEBUG = __get_node_value_type_t<_Tp>;
657648

658649
__node_value_type __value_;
659650

660-
_LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return __value_; }
651+
_LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() { return __value_; }
661652

662653
~__tree_node() = delete;
663654
__tree_node(__tree_node const&) = delete;
@@ -688,7 +679,7 @@ public:
688679

689680
_LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT {
690681
if (__value_constructed)
691-
__alloc_traits::destroy(__na_, _NodeTypes::__get_ptr(__p->__value_));
682+
__alloc_traits::destroy(__na_, std::addressof(__p->__value_));
692683
if (__p)
693684
__alloc_traits::deallocate(__na_, __p, 1);
694685
}
@@ -719,7 +710,7 @@ class __tree_iterator {
719710

720711
public:
721712
typedef bidirectional_iterator_tag iterator_category;
722-
typedef _Tp value_type;
713+
using value_type = __get_node_value_type_t<_Tp>;
723714
typedef _DiffType difference_type;
724715
typedef value_type& reference;
725716
typedef typename _NodeTypes::__node_value_type_pointer pointer;
@@ -796,7 +787,7 @@ class __tree_const_iterator {
796787

797788
public:
798789
typedef bidirectional_iterator_tag iterator_category;
799-
typedef _Tp value_type;
790+
using value_type = __get_node_value_type_t<_Tp>;
800791
typedef _DiffType difference_type;
801792
typedef const value_type& reference;
802793
typedef typename _NodeTypes::__const_node_value_type_pointer pointer;
@@ -809,7 +800,7 @@ public:
809800
}
810801

811802
private:
812-
typedef __tree_iterator<value_type, __node_pointer, difference_type> __non_const_iterator;
803+
typedef __tree_iterator<_Tp, __node_pointer, difference_type> __non_const_iterator;
813804

814805
public:
815806
_LIBCPP_HIDE_FROM_ABI __tree_const_iterator(__non_const_iterator __p) _NOEXCEPT : __ptr_(__p.__ptr_) {}
@@ -1135,6 +1126,17 @@ public:
11351126
return __emplace_hint_multi(__p, std::forward<_Vp>(__v));
11361127
}
11371128

1129+
template <class _ValueT = _Tp, __enable_if_t<__is_tree_value_type<_ValueT>::value, int> = 0>
1130+
_LIBCPP_HIDE_FROM_ABI void __insert_from_orphaned_node(const_iterator __p, __get_node_value_type_t<_Tp>&& __value) {
1131+
using __key_type = typename _NodeTypes::key_type;
1132+
__emplace_hint_multi(__p, const_cast<__key_type&&>(__value.first), std::move(__value.second));
1133+
}
1134+
1135+
template <class _ValueT = _Tp, __enable_if_t<!__is_tree_value_type<_ValueT>::value, int> = 0>
1136+
_LIBCPP_HIDE_FROM_ABI void __insert_from_orphaned_node(const_iterator __p, _Tp&& __value) {
1137+
__emplace_hint_multi(__p, std::move(__value));
1138+
}
1139+
11381140
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool>
11391141
__node_assign_unique(const __container_value_type& __v, __node_pointer __dest);
11401142

@@ -1276,6 +1278,19 @@ private:
12761278
}
12771279
_LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__tree&, false_type) _NOEXCEPT {}
12781280

1281+
template <class _From, __enable_if_t<__is_pair_v<__remove_cvref_t<_From> >, int> = 0>
1282+
_LIBCPP_HIDE_FROM_ABI static void __assign_value(__get_node_value_type_t<value_type>& __lhs, _From&& __rhs) {
1283+
using __key_type = typename _NodeTypes::key_type;
1284+
1285+
const_cast<__key_type&>(__lhs.first) = const_cast<__copy_cvref_t<_From, __key_type>&&>(__rhs.first);
1286+
__lhs.second = std::forward<_From>(__rhs).second;
1287+
}
1288+
1289+
template <class _To, class _From, class _ValueT = _Tp, __enable_if_t<!__is_pair_v<__remove_cvref_t<_From> >, int> = 0>
1290+
_LIBCPP_HIDE_FROM_ABI static void __assign_value(_To& __lhs, _From&& __rhs) {
1291+
__lhs = std::forward<_From>(__rhs);
1292+
}
1293+
12791294
struct _DetachedTreeCache {
12801295
_LIBCPP_HIDE_FROM_ABI explicit _DetachedTreeCache(__tree* __t) _NOEXCEPT
12811296
: __t_(__t),
@@ -1416,13 +1431,13 @@ void __tree<_Tp, _Compare, _Allocator>::__assign_multi(_InputIterator __first, _
14161431
if (size() != 0) {
14171432
_DetachedTreeCache __cache(this);
14181433
for (; __cache.__get() && __first != __last; ++__first) {
1419-
__cache.__get()->__value_ = *__first;
1434+
__assign_value(__cache.__get()->__value_, *__first);
14201435
__node_insert_multi(__cache.__get());
14211436
__cache.__advance();
14221437
}
14231438
}
14241439
for (; __first != __last; ++__first)
1425-
__insert_multi(_NodeTypes::__get_value(*__first));
1440+
__insert_multi(*__first);
14261441
}
14271442

14281443
template <class _Tp, class _Compare, class _Allocator>
@@ -1501,13 +1516,14 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, false_type) {
15011516
if (size() != 0) {
15021517
_DetachedTreeCache __cache(this);
15031518
while (__cache.__get() != nullptr && __t.size() != 0) {
1504-
__cache.__get()->__value_ = std::move(__t.remove(__t.begin())->__value_);
1519+
__assign_value(__cache.__get()->__value_, std::move(__t.remove(__t.begin())->__value_));
15051520
__node_insert_multi(__cache.__get());
15061521
__cache.__advance();
15071522
}
15081523
}
1509-
while (__t.size() != 0)
1510-
__insert_multi(__e, _NodeTypes::__move(__t.remove(__t.begin())->__value_));
1524+
while (__t.size() != 0) {
1525+
__insert_from_orphaned_node(__e, std::move(__t.remove(__t.begin())->__value_));
1526+
}
15111527
}
15121528
}
15131529

@@ -1533,7 +1549,7 @@ void __tree<_Tp, _Compare, _Allocator>::destroy(__node_pointer __nd) _NOEXCEPT {
15331549
destroy(static_cast<__node_pointer>(__nd->__left_));
15341550
destroy(static_cast<__node_pointer>(__nd->__right_));
15351551
__node_allocator& __na = __node_alloc();
1536-
__node_traits::destroy(__na, _NodeTypes::__get_ptr(__nd->__value_));
1552+
__node_traits::destroy(__na, std::addressof(__nd->__value_));
15371553
__node_traits::deallocate(__na, __nd, 1);
15381554
}
15391555
}
@@ -1803,10 +1819,9 @@ template <class _Tp, class _Compare, class _Allocator>
18031819
template <class... _Args>
18041820
typename __tree<_Tp, _Compare, _Allocator>::__node_holder
18051821
__tree<_Tp, _Compare, _Allocator>::__construct_node(_Args&&... __args) {
1806-
static_assert(!__is_tree_value_type<_Args...>::value, "Cannot construct from __value_type");
18071822
__node_allocator& __na = __node_alloc();
18081823
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
1809-
__node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), std::forward<_Args>(__args)...);
1824+
__node_traits::construct(__na, std::addressof(__h->__value_), std::forward<_Args>(__args)...);
18101825
__h.get_deleter().__value_constructed = true;
18111826
return __h;
18121827
}
@@ -1874,7 +1889,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_assign_unique(const __container_value_
18741889
__node_pointer __r = static_cast<__node_pointer>(__child);
18751890
bool __inserted = false;
18761891
if (__child == nullptr) {
1877-
__nd->__value_ = __v;
1892+
__assign_value(__nd->__value_, __v);
18781893
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd));
18791894
__r = __nd;
18801895
__inserted = true;
@@ -2036,7 +2051,7 @@ typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allo
20362051
__node_pointer __np = __p.__get_np();
20372052
iterator __r = __remove_node_pointer(__np);
20382053
__node_allocator& __na = __node_alloc();
2039-
__node_traits::destroy(__na, _NodeTypes::__get_ptr(const_cast<__node_value_type&>(*__p)));
2054+
__node_traits::destroy(__na, std::addressof(const_cast<__node_value_type&>(*__p)));
20402055
__node_traits::deallocate(__na, __np, 1);
20412056
return __r;
20422057
}

0 commit comments

Comments
 (0)