Skip to content

Commit 7e18b79

Browse files
authored
Rollup merge of #91426 - eggyal:idfunctor-panic-safety, r=lcnr
Make IdFunctor::try_map_id panic-safe Addresses FIXME comment created in #78313 r? ```@lcnr```
2 parents f7278cf + acd39ff commit 7e18b79

File tree

2 files changed

+30
-24
lines changed

2 files changed

+30
-24
lines changed

compiler/rustc_data_structures/src/functor.rs

+29-24
Original file line numberDiff line numberDiff line change
@@ -34,38 +34,43 @@ impl<T> IdFunctor for Vec<T> {
3434
type Inner = T;
3535

3636
#[inline]
37-
fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
37+
fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
3838
where
3939
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
4040
{
41-
// FIXME: We don't really care about panics here and leak
42-
// far more than we should, but that should be fine for now.
43-
let len = self.len();
44-
unsafe {
45-
self.set_len(0);
46-
let start = self.as_mut_ptr();
47-
for i in 0..len {
48-
let p = start.add(i);
49-
match f(p.read()) {
50-
Ok(val) => p.write(val),
51-
Err(err) => {
52-
// drop all other elements in self
53-
// (current element was "moved" into the call to f)
54-
for j in (0..i).chain(i + 1..len) {
55-
start.add(j).drop_in_place();
56-
}
41+
struct HoleVec<T> {
42+
vec: Vec<mem::ManuallyDrop<T>>,
43+
hole: Option<usize>,
44+
}
5745

58-
// returning will drop self, releasing the allocation
59-
// (len is 0 so elements will not be re-dropped)
60-
return Err(err);
46+
impl<T> Drop for HoleVec<T> {
47+
fn drop(&mut self) {
48+
unsafe {
49+
for (index, slot) in self.vec.iter_mut().enumerate() {
50+
if self.hole != Some(index) {
51+
mem::ManuallyDrop::drop(slot);
52+
}
6153
}
6254
}
6355
}
64-
// Even if we encountered an error, set the len back
65-
// so we don't leak memory.
66-
self.set_len(len);
6756
}
68-
Ok(self)
57+
58+
unsafe {
59+
let (ptr, length, capacity) = self.into_raw_parts();
60+
let vec = Vec::from_raw_parts(ptr.cast(), length, capacity);
61+
let mut hole_vec = HoleVec { vec, hole: None };
62+
63+
for (index, slot) in hole_vec.vec.iter_mut().enumerate() {
64+
hole_vec.hole = Some(index);
65+
let original = mem::ManuallyDrop::take(slot);
66+
let mapped = f(original)?;
67+
*slot = mem::ManuallyDrop::new(mapped);
68+
hole_vec.hole = None;
69+
}
70+
71+
mem::forget(hole_vec);
72+
Ok(Vec::from_raw_parts(ptr, length, capacity))
73+
}
6974
}
7075
}
7176

compiler/rustc_data_structures/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#![feature(once_cell)]
2424
#![feature(test)]
2525
#![feature(thread_id_value)]
26+
#![feature(vec_into_raw_parts)]
2627
#![allow(rustc::default_hash_types)]
2728
#![deny(unaligned_references)]
2829

0 commit comments

Comments
 (0)