diff --git a/Cargo.toml b/Cargo.toml index 9cc0b6dc..42d7ec08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ strip = false allocator-api = [] allocator-api2 = ["dep:allocator-api2", "allocator-api"] internals = [] +may_dangle = [] proptest = ["dep:proptest", "std"] rayon = ["std", "dep:rayon"] serde = ["dep:serde_core"] diff --git a/src/lib.rs b/src/lib.rs index 22663609..539b4a81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(feature = "specialization", allow(incomplete_features))] #![cfg_attr(feature = "specialization", feature(specialization, trusted_len))] +#![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] #![cfg_attr( all(feature = "allocator-api", not(feature = "allocator-api2")), feature(allocator_api) @@ -1492,6 +1493,33 @@ impl Drop for DropDealloc<'_, Heap> { } } +#[cfg(feature = "may_dangle")] +unsafe impl<#[may_dangle] Item, const INLINE: usize, Heap: Allocator> Drop + for SmallVec +{ + fn drop(&mut self) { + let (length, on_heap) = self.length.parts(); + // SAFETY: the tag tells which member is active + let ptr = unsafe { self.raw.as_mut_ptr(on_heap) }; + // SAFETY: see above + unsafe { + let _drop_dealloc = if on_heap { + let capacity = self.raw.heap.1; + Some(DropDealloc { + ptr: NonNull::new_unchecked(ptr as *mut u8), + size_bytes: capacity * size_of::(), + align: align_of::(), + allocator: &self.allocator + }) + } else { + None + }; + core::ptr::slice_from_raw_parts_mut(ptr, length).drop_in_place(); + } + } +} + +#[cfg(not(feature = "may_dangle"))] impl Drop for SmallVec { fn drop(&mut self) { let (length, on_heap) = self.length.parts(); diff --git a/tests/may_dangle.rs b/tests/may_dangle.rs new file mode 100644 index 00000000..58b40146 --- /dev/null +++ b/tests/may_dangle.rs @@ -0,0 +1,15 @@ +#![cfg(feature = "may_dangle")] + +use smallvec::SmallVec; + +#[derive(Default)] +struct MyData<'a> { + arr: SmallVec<&'a u8, 5>, + dat: u8 +} + +#[test] +fn may_dangle_allows_borrow_of_another_field() { + let mut dat = MyData::default(); + dat.arr.push(&dat.dat); +}