Skip to content

Commit c2d1b0d

Browse files
committed
Auto merge of #75071 - ssomers:btree_cleanup_5, r=Mark-Simulacrum
BTreeMap: enforce the panic rule imposed by `replace` Also, reveal the unsafe parts in the closures fed to it. r? @Mark-Simulacrum
2 parents 09f4c9f + 734fc04 commit c2d1b0d

File tree

1 file changed

+51
-53
lines changed

1 file changed

+51
-53
lines changed

library/alloc/src/collections/btree/navigate.rs

+51-53
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::intrinsics;
2+
use core::mem;
13
use core::ptr;
24

35
use super::node::{marker, ForceResult::*, Handle, NodeRef};
@@ -79,16 +81,24 @@ def_next_kv_uncheched_dealloc! {unsafe fn next_kv_unchecked_dealloc: right_kv}
7981
def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv}
8082

8183
/// This replaces the value behind the `v` unique reference by calling the
82-
/// relevant function.
84+
/// relevant function, and returns a result obtained along the way.
8385
///
84-
/// Safety: The change closure must not panic.
86+
/// If a panic occurs in the `change` closure, the entire process will be aborted.
8587
#[inline]
86-
unsafe fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
88+
fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
89+
struct PanicGuard;
90+
impl Drop for PanicGuard {
91+
fn drop(&mut self) {
92+
intrinsics::abort()
93+
}
94+
}
95+
let guard = PanicGuard;
8796
let value = unsafe { ptr::read(v) };
8897
let (new_value, ret) = change(value);
8998
unsafe {
9099
ptr::write(v, new_value);
91100
}
101+
mem::forget(guard);
92102
ret
93103
}
94104

@@ -97,26 +107,22 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed
97107
/// key and value in between.
98108
/// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree.
99109
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
100-
unsafe {
101-
replace(self, |leaf_edge| {
102-
let kv = leaf_edge.next_kv();
103-
let kv = unwrap_unchecked(kv.ok());
104-
(kv.next_leaf_edge(), kv.into_kv())
105-
})
106-
}
110+
replace(self, |leaf_edge| {
111+
let kv = leaf_edge.next_kv();
112+
let kv = unsafe { unwrap_unchecked(kv.ok()) };
113+
(kv.next_leaf_edge(), kv.into_kv())
114+
})
107115
}
108116

109117
/// Moves the leaf edge handle to the previous leaf edge and returns references to the
110118
/// key and value in between.
111119
/// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree.
112120
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
113-
unsafe {
114-
replace(self, |leaf_edge| {
115-
let kv = leaf_edge.next_back_kv();
116-
let kv = unwrap_unchecked(kv.ok());
117-
(kv.next_back_leaf_edge(), kv.into_kv())
118-
})
119-
}
121+
replace(self, |leaf_edge| {
122+
let kv = leaf_edge.next_back_kv();
123+
let kv = unsafe { unwrap_unchecked(kv.ok()) };
124+
(kv.next_back_leaf_edge(), kv.into_kv())
125+
})
120126
}
121127
}
122128

@@ -127,16 +133,14 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
127133
/// - The caller must ensure that the leaf edge is not the last one in the tree.
128134
/// - Using the updated handle may well invalidate the returned references.
129135
pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
130-
unsafe {
131-
let kv = replace(self, |leaf_edge| {
132-
let kv = leaf_edge.next_kv();
133-
let kv = unwrap_unchecked(kv.ok());
134-
(ptr::read(&kv).next_leaf_edge(), kv)
135-
});
136-
// Doing the descend (and perhaps another move) invalidates the references
137-
// returned by `into_kv_mut`, so we have to do this last.
138-
kv.into_kv_mut()
139-
}
136+
let kv = replace(self, |leaf_edge| {
137+
let kv = leaf_edge.next_kv();
138+
let kv = unsafe { unwrap_unchecked(kv.ok()) };
139+
(unsafe { ptr::read(&kv) }.next_leaf_edge(), kv)
140+
});
141+
// Doing the descend (and perhaps another move) invalidates the references
142+
// returned by `into_kv_mut`, so we have to do this last.
143+
kv.into_kv_mut()
140144
}
141145

142146
/// Moves the leaf edge handle to the previous leaf and returns references to the
@@ -145,16 +149,14 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
145149
/// - The caller must ensure that the leaf edge is not the first one in the tree.
146150
/// - Using the updated handle may well invalidate the returned references.
147151
pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
148-
unsafe {
149-
let kv = replace(self, |leaf_edge| {
150-
let kv = leaf_edge.next_back_kv();
151-
let kv = unwrap_unchecked(kv.ok());
152-
(ptr::read(&kv).next_back_leaf_edge(), kv)
153-
});
154-
// Doing the descend (and perhaps another move) invalidates the references
155-
// returned by `into_kv_mut`, so we have to do this last.
156-
kv.into_kv_mut()
157-
}
152+
let kv = replace(self, |leaf_edge| {
153+
let kv = leaf_edge.next_back_kv();
154+
let kv = unsafe { unwrap_unchecked(kv.ok()) };
155+
(unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv)
156+
});
157+
// Doing the descend (and perhaps another move) invalidates the references
158+
// returned by `into_kv_mut`, so we have to do this last.
159+
kv.into_kv_mut()
158160
}
159161
}
160162

@@ -172,14 +174,12 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
172174
/// call this method again subject to both preconditions listed in the first point,
173175
/// or call counterpart `next_back_unchecked` subject to its preconditions.
174176
pub unsafe fn next_unchecked(&mut self) -> (K, V) {
175-
unsafe {
176-
replace(self, |leaf_edge| {
177-
let kv = next_kv_unchecked_dealloc(leaf_edge);
178-
let k = ptr::read(kv.reborrow().into_kv().0);
179-
let v = ptr::read(kv.reborrow().into_kv().1);
180-
(kv.next_leaf_edge(), (k, v))
181-
})
182-
}
177+
replace(self, |leaf_edge| {
178+
let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) };
179+
let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
180+
let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
181+
(kv.next_leaf_edge(), (k, v))
182+
})
183183
}
184184

185185
/// Moves the leaf edge handle to the previous leaf edge and returns the key
@@ -195,14 +195,12 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
195195
/// call this method again subject to both preconditions listed in the first point,
196196
/// or call counterpart `next_unchecked` subject to its preconditions.
197197
pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
198-
unsafe {
199-
replace(self, |leaf_edge| {
200-
let kv = next_back_kv_unchecked_dealloc(leaf_edge);
201-
let k = ptr::read(kv.reborrow().into_kv().0);
202-
let v = ptr::read(kv.reborrow().into_kv().1);
203-
(kv.next_back_leaf_edge(), (k, v))
204-
})
205-
}
198+
replace(self, |leaf_edge| {
199+
let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) };
200+
let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
201+
let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
202+
(kv.next_back_leaf_edge(), (k, v))
203+
})
206204
}
207205
}
208206

0 commit comments

Comments
 (0)