diff --git a/lib.rs b/lib.rs index 46090a8..2368c7d 100644 --- a/lib.rs +++ b/lib.rs @@ -83,6 +83,23 @@ enum SmallVecData { Heap { ptr: *mut A::Item, capacity: usize }, } +impl Drop for SmallVecData { + fn drop(&mut self) { + unsafe { + match *self { + ref mut inline @ Inline { .. } => { + // Inhibit the array destructor. + ptr::write(inline, Heap { + ptr: ptr::null_mut(), + capacity: 0, + }); + } + Heap { ptr, capacity } => deallocate(ptr, capacity), + } + } + } +} + pub struct SmallVec { len: usize, @@ -378,22 +395,13 @@ impl SmallVec { impl Drop for SmallVec { fn drop(&mut self) { + // Note on panic safety: dropping an element may panic, + // but the inner SmallVecData destructor will still run unsafe { let ptr = self.as_ptr(); for i in 0 .. self.len { ptr::read(ptr.offset(i as isize)); } - - match self.data { - Inline { .. } => { - // Inhibit the array destructor. - ptr::write(&mut self.data, Heap { - ptr: ptr::null_mut(), - capacity: 0, - }); - } - Heap { ptr, capacity } => deallocate(ptr, capacity), - } } } } @@ -578,4 +586,21 @@ pub mod tests { assert_eq!(&v.iter().map(|v| **v).collect::>(), &[0, 3, 2]); } + + #[test] + #[should_panic] + fn test_drop_panic_smallvec() { + // This test should only panic once, and not double panic, + // which would mean a double drop + struct DropPanic; + + impl Drop for DropPanic { + fn drop(&mut self) { + panic!("drop"); + } + } + + let mut v = SmallVec::<[_; 1]>::new(); + v.push(DropPanic); + } }