Skip to content

Commit c9a47bb

Browse files
Get updates from PR#134330
1 parent 35e1e4e commit c9a47bb

File tree

7 files changed

+339
-352
lines changed

7 files changed

+339
-352
lines changed

libcxx/docs/ReleaseNotes/22.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ Implemented Papers
4848
- P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
4949
- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
5050
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
51-
- P3372R3: ``constexpr map`` (`Github <https://llvm.org/PR134330>`__) (The paper is partially implemented. ``constexpr map`` is implemented in this release)
5251

5352
Improvements and New Features
5453
-----------------------------

libcxx/include/__node_handle

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,28 @@ private:
3030
3131
public:
3232
// [container.node.cons], constructors, copy, and assignment
33-
constexpr node-handle() noexcept : ptr_(), alloc_() {} // constexpr since C++26
34-
node-handle(node-handle&&) noexcept; // constexpr since C++26
35-
node-handle& operator=(node-handle&&); // constexpr since C++26
33+
constexpr node-handle() noexcept : ptr_(), alloc_() {}
34+
constexpr node-handle(node-handle&&) noexcept; // constexpr since C++26
35+
constexpr node-handle& operator=(node-handle&&); // constexpr since C++26
3636
3737
// [container.node.dtor], destructor
38-
~node-handle(); // constexpr since C++26
38+
constexpr ~node-handle(); // constexpr since C++26
3939
4040
// [container.node.observers], observers
41-
value_type& value() const; // not present for map containers
42-
key_type& key() const; // not present for set containers
43-
mapped_type& mapped() const; // not present for set containers // constexpr since C++26
41+
value_type& value() const; // not present for map containers
42+
key_type& key() const; // not present for set containers
43+
constexpr mapped_type& mapped() const; // not present for set containers, constexpr since C++26
4444
45-
allocator_type get_allocator() const; // constexpr since C++26
46-
explicit operator bool() const noexcept; // constexpr since C++26
47-
[[nodiscard]] bool empty() const noexcept; // nodiscard since C++20 // constexpr since C++26
45+
constexpr allocator_type get_allocator() const; // constexpr since C++26
46+
constexpr explicit operator bool() const noexcept; // constexpr since C++26
47+
[[nodiscard]] constexpr bool empty() const noexcept; // nodiscard since C++20, constexpr since C++26
4848
4949
// [container.node.modifiers], modifiers
50-
void swap(node-handle&)
50+
constexpr void swap(node-handle&)
5151
noexcept(ator_traits::propagate_on_container_swap::value ||
5252
ator_traits::is_always_equal::value); // constexpr since C++26
5353
54-
friend void swap(node-handle& x, node-handle& y) noexcept(noexcept(x.swap(y))) {
54+
constexpr friend void swap(node-handle& x, node-handle& y) noexcept(noexcept(x.swap(y))) {
5555
x.swap(y);
5656
} // constexpr since C++26
5757
};

libcxx/include/__tree

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _EndNodePtr __tree_ne
209209
return std::__static_fancy_pointer_cast<_EndNodePtr>(std::__tree_min(__x->__right_));
210210
while (!std::__tree_is_left_child(__x))
211211
__x = __x->__parent_unsafe();
212-
return static_cast<_EndNodePtr>(__x->__parent_);
212+
return std::__static_fancy_pointer_cast<_EndNodePtr>(__x->__parent_);
213213
}
214214

215215
// Returns: pointer to the previous in-order node before __x.
@@ -620,13 +620,10 @@ public:
620620

621621
// This line fails with:
622622
// libcxx/test-suite-install/include/c++/v1/__memory/construct_at.h:38:49: note: non-literal type
623-
// 'std::__tree_node<std::__value_type<Key, int>, void *>' cannot be used in a constant expression
624-
//
623+
// `'std::__tree_node<std::__value_type<Key, int>, void *>' cannot be used in a constant expression`
625624
// during constant evaluation as part of P3372
626625
// on:
627-
// 1. Arm CI which is on clang 19.x (will be fixed in: https://github.com/llvm/llvm-project/issues/161159 )
628-
// 2. AppleClang is not yet using clang >= 20.x, which has "fixed" this issue
629-
// 3. A few others like FreeBSD/amd64, AArch64, AIX
626+
// 1. AppleClang, which is not yet using clang >= 20.x, which has "fixed" this issue
630627
// FIXME: when AppleClang is based off of clang >= 20.x
631628
// FIXME: when Clang-based CI is using clang >= 20.x
632629
#if (defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER < 2000) || \
@@ -1069,10 +1066,10 @@ public:
10691066
#if _LIBCPP_STD_VER >= 26
10701067
if (std::is_constant_evaluated() && std::is_copy_constructible_v<decltype(__value.first)>) {
10711068
// We create a sfinae wrapper method here, because if the __emplace_hint_unique method gets template instantiated
1072-
// within __insert_unique_from_orphaned_node, the code will fail to compile where the value is not
1073-
// copy_constructible for runtime execution as well; unless we use `if constexpr`. Given the copy-constructible
1069+
// within __insert_unique_from_orphaned_node, the code will fail to compile when the value is not
1070+
// copy_constructible (even for runtime execution); unless we use `if constexpr`. Given the copy-constructible
10741071
// code path will be a performance regression, we want to restrict it to only execute during constant evaluation
1075-
//, we need to delay the template instantiation
1072+
// , hence, we need to delay the template instantiation.
10761073
__emplace_hint_unique__sfinae(
10771074
integral_constant< bool, std::is_copy_constructible_v<decltype(__value.first)> >(),
10781075
__p,
@@ -1426,7 +1423,7 @@ private:
14261423
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
14271424
__assign_value__sfinae(false_type, __get_node_value_type_t<value_type>&, _From&&) {
14281425
// This method body should never be run. It only exists to allow for compilation. See note in __assign_value for
1429-
// more information
1426+
// more information.
14301427
}
14311428

14321429
template <class _From, class _ValueT = _Tp, __enable_if_t<__is_tree_value_type_v<_ValueT>, int> = 0>
@@ -1437,22 +1434,23 @@ private:
14371434
#if _LIBCPP_STD_VER >= 26
14381435

14391436
if (std::is_constant_evaluated() && std::is_copy_constructible_v<decltype(__rhs.first)>) {
1440-
// we use copy, and not "move" as the constraint
1441-
// because we can NOT move from `const key_type`, which is how `value_type` is defined
1442-
// atleast for map
1443-
// typedef pair<const key_type, mapped_type> value_type;
1444-
// so we must copy it
1445-
1446-
// const_cast is not allowed at constexpr time.
1447-
// we get around this by deleting __lhs and creating a new node in-place
1448-
// to avoid const_cast __lhs.first
1449-
1450-
// We create a sfinae wrapper method here, because if the body of the true_type overload for
1451-
// __assign_value__sfinae() gets template instantiated within __assign_value, the code will fail to compile where
1452-
// the value is not copy_constructible for runtime execution as well; unless we use `if constexpr`. Given the
1453-
// copy-constructible code path will be a performance regression, we want to restrict it to only execute during
1454-
// constant evaluation
1455-
//, we need to delay the template instantiation
1437+
// We use copy, and not "move" as the constraint here because we can NOT move
1438+
// from `const key_type`, which is how `value_type` is defined for `std::map`
1439+
// `typedef pair<const key_type, mapped_type> value_type;`
1440+
// so we must copy it to not perform undefined behavior which
1441+
// is disallowed during constant evaluation.
1442+
1443+
// Furthermore, `const_cast` is not allowed during constant evaluation.
1444+
// We get around this by deleting `__lhs` and creating a new node in-place
1445+
// to avoid the `const_cast` when attempting to assign to `__lhs.first`.
1446+
1447+
// We create a sfinae wrapper method here, because if the body of the `true_type` overload for
1448+
// `__assign_value__sfinae()` gets template instantiated within `__assign_value`,
1449+
// the code will fail to compile when
1450+
// the value is not copy_constructible (even for runtime execution); unless we use `if constexpr`.
1451+
// Given that the copy-constructible code path will be a performance regression,
1452+
// we want to restrict it to only execute during constant evaluation
1453+
//, we need to delay the template instantiation.
14561454

14571455
__assign_value__sfinae(std::integral_constant<bool, std::is_copy_constructible_v<decltype(__rhs.first)>>(),
14581456
std::forward<decltype(__lhs)>(__lhs),
@@ -1493,7 +1491,7 @@ private:
14931491
__t_->destroy(__cache_elem_);
14941492
if (__cache_root_) {
14951493
while (__cache_root_->__parent_ != nullptr)
1496-
__cache_root_ = static_cast<__node_pointer>(__cache_root_->__parent_);
1494+
__cache_root_ = std::__static_fancy_pointer_cast<__node_pointer>(__cache_root_->__parent_);
14971495
__t_->destroy(__cache_root_);
14981496
}
14991497
}
@@ -1639,14 +1637,14 @@ __tree<_Tp, _Compare, _Allocator>::_DetachedTreeCache::__detach_next(__node_poin
16391637
__cache = std::__static_fancy_pointer_cast<__node_pointer>(__cache->__parent_);
16401638
if (__cache->__right_ == nullptr)
16411639
return __cache;
1642-
return static_cast<__node_pointer>(std::__tree_leaf(__cache->__right_));
1640+
return std::__static_fancy_pointer_cast<__node_pointer>(std::__tree_leaf(__cache->__right_));
16431641
}
16441642
// __cache is right child
16451643
__cache->__parent_unsafe()->__right_ = nullptr;
16461644
__cache = std::__static_fancy_pointer_cast<__node_pointer>(__cache->__parent_);
16471645
if (__cache->__left_ == nullptr)
16481646
return __cache;
1649-
return static_cast<__node_pointer>(std::__tree_leaf(__cache->__left_));
1647+
return std::__static_fancy_pointer_cast<__node_pointer>(std::__tree_leaf(__cache->__left_));
16501648
}
16511649

16521650
template <class _Tp, class _Compare, class _Allocator>
@@ -1741,7 +1739,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 __tree<_Tp, _Compare, _Allocator>::__tree(__tree&&
17411739
if (__size_ == 0)
17421740
__begin_node_ = __end_node();
17431741
else {
1744-
__end_node()->__left_->__parent_ = static_cast<__end_node_pointer>(__end_node());
1742+
__end_node()->__left_->__parent_ = std::__static_fancy_pointer_cast<__end_node_pointer>(__end_node());
17451743
__t.__begin_node_ = __t.__end_node();
17461744
__t.__end_node()->__left_ = nullptr;
17471745
__t.__size_ = 0;
@@ -1757,7 +1755,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 __tree<_Tp, _Compare, _Allocator>::__tree(__tree&&
17571755
else {
17581756
__begin_node_ = __t.__begin_node_;
17591757
__end_node()->__left_ = __t.__end_node()->__left_;
1760-
__end_node()->__left_->__parent_ = static_cast<__end_node_pointer>(__end_node());
1758+
__end_node()->__left_->__parent_ = std::__static_fancy_pointer_cast<__end_node_pointer>(__end_node());
17611759
__size_ = __t.__size_;
17621760
__t.__begin_node_ = __t.__end_node();
17631761
__t.__end_node()->__left_ = nullptr;
@@ -1771,7 +1769,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 __tree<_Tp, _Compare, _Allocator>::__tree(__tree&&
17711769
template <class _Tp, class _Compare, class _Allocator>
17721770
_LIBCPP_CONSTEXPR_SINCE_CXX26 void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type)
17731771
_NOEXCEPT_(is_nothrow_move_assignable<value_compare>::value&& is_nothrow_move_assignable<__node_allocator>::value) {
1774-
destroy(static_cast<__node_pointer>(__end_node()->__left_));
1772+
destroy(std::__static_fancy_pointer_cast<__node_pointer>(__end_node()->__left_));
17751773
__begin_node_ = __t.__begin_node_;
17761774
__end_node_ = __t.__end_node_;
17771775
__move_assign_alloc(__t);
@@ -1780,7 +1778,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __tree<_Tp, _Compare, _Allocator>::__move_ass
17801778
if (__size_ == 0)
17811779
__begin_node_ = __end_node();
17821780
else {
1783-
__end_node()->__left_->__parent_ = static_cast<__end_node_pointer>(__end_node());
1781+
__end_node()->__left_->__parent_ = std::__static_fancy_pointer_cast<__end_node_pointer>(__end_node());
17841782
__t.__begin_node_ = __t.__end_node();
17851783
__t.__end_node()->__left_ = nullptr;
17861784
__t.__size_ = 0;
@@ -1852,16 +1850,16 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf_low(__end_node_pointer& __parent,
18521850
while (true) {
18531851
if (value_comp()(__nd->__get_value(), __v)) {
18541852
if (__nd->__right_ != nullptr)
1855-
__nd = static_cast<__node_pointer>(__nd->__right_);
1853+
__nd = std::__static_fancy_pointer_cast<__node_pointer>(__nd->__right_);
18561854
else {
1857-
__parent = static_cast<__end_node_pointer>(__nd);
1855+
__parent = std::__static_fancy_pointer_cast<__end_node_pointer>(__nd);
18581856
return __nd->__right_;
18591857
}
18601858
} else {
18611859
if (__nd->__left_ != nullptr)
1862-
__nd = static_cast<__node_pointer>(__nd->__left_);
1860+
__nd = std::__static_fancy_pointer_cast<__node_pointer>(__nd->__left_);
18631861
else {
1864-
__parent = static_cast<__end_node_pointer>(__nd);
1862+
__parent = std::__static_fancy_pointer_cast<__end_node_pointer>(__nd);
18651863
return __parent->__left_;
18661864
}
18671865
}
@@ -1918,10 +1916,10 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf(
19181916
if (__prior == begin() || !value_comp()(__v, *--__prior)) {
19191917
// *prev(__hint) <= __v <= *__hint
19201918
if (__hint.__ptr_->__left_ == nullptr) {
1921-
__parent = static_cast<__end_node_pointer>(__hint.__ptr_);
1919+
__parent = std::__static_fancy_pointer_cast<__end_node_pointer>(__hint.__ptr_);
19221920
return __parent->__left_;
19231921
} else {
1924-
__parent = static_cast<__end_node_pointer>(__prior.__ptr_);
1922+
__parent = std::__static_fancy_pointer_cast<__end_node_pointer>(__prior.__ptr_);
19251923
return std::__static_fancy_pointer_cast<__node_base_pointer>(__prior.__ptr_)->__right_;
19261924
}
19271925
}
@@ -2008,15 +2006,15 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(const_iterator __hint, __node_ba
20082006
if (__next == end() || value_comp()(__v, *__next)) {
20092007
// *__hint < __v < *std::next(__hint)
20102008
if (__hint.__get_np()->__right_ == nullptr)
2011-
return _Pair(__hint.__ptr_, static_cast<__node_pointer>(__hint.__ptr_)->__right_);
2009+
return _Pair(__hint.__ptr_, std::__static_fancy_pointer_cast<__node_pointer>(__hint.__ptr_)->__right_);
20122010
return _Pair(__next.__ptr_, __next.__ptr_->__left_);
20132011
}
20142012
// *next(__hint) <= __v
20152013
return __find_equal(__v);
20162014
}
20172015

20182016
// else __v == *__hint
2019-
__dummy = static_cast<__node_base_pointer>(__hint.__ptr_);
2017+
__dummy = std::__static_fancy_pointer_cast<__node_base_pointer>(__hint.__ptr_);
20202018
return _Pair(__hint.__ptr_, __dummy);
20212019
}
20222020

@@ -2064,14 +2062,14 @@ __tree<_Tp, _Compare, _Allocator>::__emplace_hint_multi(const_iterator __p, _Arg
20642062
__end_node_pointer __parent;
20652063
__node_base_pointer& __child = __find_leaf(__p, __parent, __h->__get_value());
20662064
__insert_node_at(__parent, __child, std::__static_fancy_pointer_cast<__node_base_pointer>(__h.get()));
2067-
return iterator(static_cast<__node_pointer>(__h.release()));
2065+
return iterator(std::__static_fancy_pointer_cast<__node_pointer>(__h.release()));
20682066
}
20692067

20702068
template <class _Tp, class _Compare, class _Allocator>
20712069
pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, bool> _LIBCPP_CONSTEXPR_SINCE_CXX26
20722070
__tree<_Tp, _Compare, _Allocator>::__node_assign_unique(const value_type& __v, __node_pointer __nd) {
20732071
auto [__parent, __child] = __find_equal(__v);
2074-
__node_pointer __r = static_cast<__node_pointer>(__child);
2072+
__node_pointer __r = std::__static_fancy_pointer_cast<__node_pointer>(__child);
20752073
bool __inserted = false;
20762074
if (__child == nullptr) {
20772075
__assign_value(__nd->__get_value(), __v);
@@ -2096,7 +2094,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 typename __tree<_Tp, _Compare, _Allocator>::iterat
20962094
__tree<_Tp, _Compare, _Allocator>::__node_insert_multi(const_iterator __p, __node_pointer __nd) {
20972095
__end_node_pointer __parent;
20982096
__node_base_pointer& __child = __find_leaf(__p, __parent, __nd->__get_value());
2099-
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd));
2097+
__insert_node_at(__parent, __child, std::__static_fancy_pointer_cast<__node_base_pointer>(__nd));
21002098
return iterator(__nd);
21012099
}
21022100

@@ -2123,9 +2121,10 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(_NodeHandle&& __n
21232121
__node_pointer __ptr = __nh.__ptr_;
21242122
auto [__parent, __child] = __find_equal(__ptr->__get_value());
21252123
if (__child != nullptr)
2126-
return _InsertReturnType{iterator(static_cast<__node_pointer>(__child)), false, std::move(__nh)};
2124+
return _InsertReturnType{
2125+
iterator(std::__static_fancy_pointer_cast<__node_pointer>(__child)), false, std::move(__nh)};
21272126

2128-
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__ptr));
2127+
__insert_node_at(__parent, __child, std::__static_fancy_pointer_cast<__node_base_pointer>(__ptr));
21292128
__nh.__release_ptr();
21302129
return _InsertReturnType{iterator(__ptr), true, _NodeHandle()};
21312130
}
@@ -2140,9 +2139,9 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(const_iterator __
21402139
__node_pointer __ptr = __nh.__ptr_;
21412140
__node_base_pointer __dummy;
21422141
auto [__parent, __child] = __find_equal(__hint, __dummy, __ptr->__get_value());
2143-
__node_pointer __r = static_cast<__node_pointer>(__child);
2142+
__node_pointer __r = std::__static_fancy_pointer_cast<__node_pointer>(__child);
21442143
if (__child == nullptr) {
2145-
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__ptr));
2144+
__insert_node_at(__parent, __child, std::__static_fancy_pointer_cast<__node_base_pointer>(__ptr));
21462145
__r = __ptr;
21472146
__nh.__release_ptr();
21482147
}
@@ -2179,7 +2178,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_merge_unique(__tree<_Tp, _Comp2
21792178
if (__child != nullptr)
21802179
continue;
21812180
__source.__remove_node_pointer(__src_ptr);
2182-
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__src_ptr));
2181+
__insert_node_at(__parent, __child, std::__static_fancy_pointer_cast<__node_base_pointer>(__src_ptr));
21832182
}
21842183
}
21852184

@@ -2222,7 +2221,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_merge_multi(__tree<_Tp, _Comp2,
22222221
__node_base_pointer& __child = __find_leaf_high(__parent, __src_ptr->__get_value());
22232222
++__i;
22242223
__source.__remove_node_pointer(__src_ptr);
2225-
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__src_ptr));
2224+
__insert_node_at(__parent, __child, std::__static_fancy_pointer_cast<__node_base_pointer>(__src_ptr));
22262225
}
22272226
}
22282227

@@ -2478,12 +2477,12 @@ __tree<_Tp, _Compare, _Allocator>::remove(const_iterator __p) _NOEXCEPT {
24782477
__node_pointer __np = __p.__get_np();
24792478
if (__begin_node_ == __p.__ptr_) {
24802479
if (__np->__right_ != nullptr)
2481-
__begin_node_ = static_cast<__end_node_pointer>(__np->__right_);
2480+
__begin_node_ = std::__static_fancy_pointer_cast<__end_node_pointer>(__np->__right_);
24822481
else
2483-
__begin_node_ = static_cast<__end_node_pointer>(__np->__parent_);
2482+
__begin_node_ = std::__static_fancy_pointer_cast<__end_node_pointer>(__np->__parent_);
24842483
}
24852484
--__size_;
2486-
std::__tree_remove(__end_node()->__left_, static_cast<__node_base_pointer>(__np));
2485+
std::__tree_remove(__end_node()->__left_, std::__static_fancy_pointer_cast<__node_base_pointer>(__np));
24872486
return __node_holder(__np, _Dp(__node_alloc(), true));
24882487
}
24892488

libcxx/include/__type_traits/make_transparent.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _Comparator& __as_transparen
3838
}
3939

4040
template <class _Comparator, __enable_if_t<!is_same<_Comparator, __make_transparent_t<_Comparator> >::value, int> = 0>
41-
_LIBCPP_HIDE_FROM_ABI __make_transparent_t<_Comparator> __as_transparent(_Comparator&) {
41+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __make_transparent_t<_Comparator> __as_transparent(_Comparator&) {
4242
static_assert(is_empty<_Comparator>::value);
4343
return __make_transparent_t<_Comparator>();
4444
}

0 commit comments

Comments
 (0)