Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/arrayvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,11 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
debug_assert_ne!(ptr, end_ptr);
if mem::size_of::<T>() != 0 {
ptr.write(elt);
} else {
// The ZST element has logically been moved into the vector.
// There is no memory to write, but dropping `elt` here would
// drop it once now and once again when the vector is dropped.
mem::forget(elt);
}
ptr = raw_ptr_add(ptr, 1);
guard.data += 1;
Expand Down
26 changes: 26 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,32 @@ fn test_extend_zst() {
assert_eq!(array.len(), 5);
}

#[test]
fn test_extend_zst_with_drop_is_not_dropped_twice_via_safe_api() {
use std::sync::atomic::{AtomicUsize, Ordering};

static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);

struct ZstWithSafeDrop;

impl Drop for ZstWithSafeDrop {
fn drop(&mut self) {
let previous = DROP_COUNT.fetch_add(1, Ordering::SeqCst);
// Extending with a single ZST moves one logical value into the ArrayVec.
// Its Drop implementation must run exactly once, when the ArrayVec drops.
if previous != 0 {
panic!("ZST value dropped more than once");
}
}
}

DROP_COUNT.store(0, Ordering::SeqCst);

let mut vec = ArrayVec::<ZstWithSafeDrop, 1>::new();
vec.extend(std::iter::once(ZstWithSafeDrop));
drop(vec);
}

#[test]
fn test_try_from_argument() {
use core::convert::TryFrom;
Expand Down
Loading