diff --git a/src/libstd/vec_ng.rs b/src/libstd/vec_ng.rs index 76fd68a526513..f324f62f36b09 100644 --- a/src/libstd/vec_ng.rs +++ b/src/libstd/vec_ng.rs @@ -32,6 +32,7 @@ use raw::Slice; use vec::{ImmutableEqVector, ImmutableVector, Items, MutItems, MutableVector}; use vec::{RevItems}; +#[unsafe_no_drop_flag] pub struct Vec { priv len: uint, priv cap: uint, @@ -565,6 +566,8 @@ pub fn append_one(mut lhs: Vec, x: T) -> Vec { #[unsafe_destructor] impl Drop for Vec { fn drop(&mut self) { + // This is (and should always remain) a no-op if the fields are + // zeroed (when moving out, because of #[unsafe_no_drop_flag]). unsafe { for x in self.as_mut_slice().iter() { ptr::read(x); @@ -629,7 +632,54 @@ impl Drop for MoveItems { mod tests { use super::Vec; use iter::{Iterator, range, Extendable}; + use mem::{drop, size_of}; + use ops::Drop; use option::{Some, None}; + use ptr; + + #[test] + fn test_small_vec_struct() { + assert!(size_of::>() == size_of::() * 3); + } + + #[test] + fn test_double_drop() { + struct TwoVec { + x: Vec, + y: Vec + } + + struct DropCounter<'a> { + count: &'a mut int + } + + #[unsafe_destructor] + impl<'a> Drop for DropCounter<'a> { + fn drop(&mut self) { + *self.count += 1; + } + } + + let mut count_x @ mut count_y = 0; + { + let mut tv = TwoVec { + x: Vec::new(), + y: Vec::new() + }; + tv.x.push(DropCounter {count: &mut count_x}); + tv.y.push(DropCounter {count: &mut count_y}); + + // If Vec had a drop flag, here is where it would be zeroed. + // Instead, it should rely on its internal state to prevent + // doing anything significant when dropped multiple times. + drop(tv.x); + + // Here tv goes out of scope, tv.y should be dropped, but not tv.x. + } + + assert_eq!(count_x, 1); + assert_eq!(count_y, 1); + } #[test] fn test_reserve_additional() {