Skip to content

Commit c52540b

Browse files
committed
Use DrainRaw in vec::Drain too.
1 parent 0fe05cc commit c52540b

File tree

4 files changed

+42
-39
lines changed

4 files changed

+42
-39
lines changed

library/alloc/src/vec/drain.rs

+18-35
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::alloc::{Allocator, Global};
22
use core::fmt;
33
use core::iter::{FusedIterator, TrustedLen};
4-
use core::mem::{self, ManuallyDrop, SizedTypeProperties};
4+
use core::marker::PhantomData;
5+
use core::mem::{ManuallyDrop, SizedTypeProperties};
56
use core::ptr::{self, NonNull};
67
use core::slice::{self};
78

@@ -29,14 +30,15 @@ pub struct Drain<
2930
/// Length of tail
3031
pub(super) tail_len: usize,
3132
/// Current remaining range to remove
32-
pub(super) iter: slice::Iter<'a, T>,
33+
pub(super) iter: slice::DrainRaw<T>,
3334
pub(super) vec: NonNull<Vec<T, A>>,
35+
pub(super) phantom: PhantomData<&'a [T]>,
3436
}
3537

3638
#[stable(feature = "collection_debug", since = "1.17.0")]
3739
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
3840
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39-
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
41+
f.debug_tuple("Drain").field(&self.as_slice()).finish()
4042
}
4143
}
4244

@@ -55,7 +57,9 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
5557
#[must_use]
5658
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
5759
pub fn as_slice(&self) -> &[T] {
58-
self.iter.as_slice()
60+
// SAFETY: Restricting the lifetime of the returned slice to the self
61+
// borrow keeps anything else from dropping them.
62+
unsafe { self.iter.as_nonnull_slice().as_ref() }
5963
}
6064

6165
/// Returns a reference to the underlying allocator.
@@ -108,8 +112,9 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
108112
let start = source_vec.len();
109113
let tail = this.tail_start;
110114

111-
let unyielded_len = this.iter.len();
112-
let unyielded_ptr = this.iter.as_slice().as_ptr();
115+
let keep_items = this.iter.forget_remaining();
116+
let unyielded_len = keep_items.len();
117+
let unyielded_ptr = keep_items.as_mut_ptr();
113118

114119
// ZSTs have no identity, so we don't need to move them around.
115120
if !T::IS_ZST {
@@ -154,7 +159,7 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
154159

155160
#[inline]
156161
fn next(&mut self) -> Option<T> {
157-
self.iter.next().map(|elt| unsafe { ptr::read(elt as *const _) })
162+
self.iter.next()
158163
}
159164

160165
fn size_hint(&self) -> (usize, Option<usize>) {
@@ -166,7 +171,7 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
166171
impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
167172
#[inline]
168173
fn next_back(&mut self) -> Option<T> {
169-
self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) })
174+
self.iter.next_back()
170175
}
171176
}
172177

@@ -195,16 +200,13 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
195200
}
196201
}
197202

198-
let iter = mem::take(&mut self.iter);
199-
let drop_len = iter.len();
200-
201-
let mut vec = self.vec;
202-
203203
if T::IS_ZST {
204+
let drop_len = self.iter.forget_remaining().len();
205+
204206
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
205207
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
206208
unsafe {
207-
let vec = vec.as_mut();
209+
let vec = self.vec.as_mut();
208210
let old_len = vec.len();
209211
vec.set_len(old_len + drop_len + self.tail_len);
210212
vec.truncate(old_len + self.tail_len);
@@ -214,28 +216,9 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
214216
}
215217

216218
// ensure elements are moved back into their appropriate places, even when drop_in_place panics
217-
let _guard = DropGuard(self);
219+
let guard = DropGuard(self);
218220

219-
if drop_len == 0 {
220-
return;
221-
}
222-
223-
// as_slice() must only be called when iter.len() is > 0 because
224-
// it also gets touched by vec::Splice which may turn it into a dangling pointer
225-
// which would make it and the vec pointer point to different allocations which would
226-
// lead to invalid pointer arithmetic below.
227-
let drop_ptr = iter.as_slice().as_ptr();
228-
229-
unsafe {
230-
// drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
231-
// a pointer with mutable provenance is necessary. Therefore we must reconstruct
232-
// it from the original vec but also avoid creating a &mut to the front since that could
233-
// invalidate raw pointers to it which some unsafe code might rely on.
234-
let vec_ptr = vec.as_mut().as_mut_ptr();
235-
let drop_offset = drop_ptr.sub_ptr(vec_ptr);
236-
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
237-
ptr::drop_in_place(to_drop);
238-
}
221+
guard.0.iter.drop_remaining();
239222
}
240223
}
241224

library/alloc/src/vec/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1389,7 +1389,11 @@ impl<T, A: Allocator> Vec<T, A> {
13891389
pub fn as_mut_ptr(&mut self) -> *mut T {
13901390
// We shadow the slice method of the same name to avoid going through
13911391
// `deref_mut`, which creates an intermediate reference.
1392-
self.buf.ptr()
1392+
self.as_nonnull_ptr().as_ptr()
1393+
}
1394+
1395+
fn as_nonnull_ptr(&mut self) -> NonNull<T> {
1396+
self.buf.non_null()
13931397
}
13941398

13951399
/// Returns a reference to the underlying allocator.
@@ -2199,12 +2203,13 @@ impl<T, A: Allocator> Vec<T, A> {
21992203
unsafe {
22002204
// set self.vec length's to start, to be safe in case Drain is leaked
22012205
self.set_len(start);
2202-
let range_slice = slice::from_raw_parts(self.as_ptr().add(start), end - start);
2206+
let drain = DrainRaw::from_parts(self.as_nonnull_ptr().add(start), end - start);
22032207
Drain {
22042208
tail_start: end,
22052209
tail_len: len - end,
2206-
iter: range_slice.iter(),
2210+
iter: drain,
22072211
vec: NonNull::from(self),
2212+
phantom: PhantomData,
22082213
}
22092214
}
22102215
}

library/alloc/src/vec/splice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
5959
// Which means we can replace the slice::Iter with pointers that won't point to deallocated
6060
// memory, so that Drain::drop is still allowed to call iter.len(), otherwise it would break
6161
// the ptr.sub_ptr contract.
62-
self.drain.iter = (&[]).iter();
62+
self.drain.iter = Default::default();
6363

6464
unsafe {
6565
if self.drain.tail_len == 0 {

library/core/src/slice/drain.rs

+15
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,21 @@ impl<T: fmt::Debug> fmt::Debug for DrainRaw<T> {
4848
}
4949
}
5050

51+
#[unstable(feature = "slice_drain_raw_iter", issue = "none")]
52+
impl<T> Default for DrainRaw<T> {
53+
/// Creates an empty slice iterator.
54+
///
55+
/// ```
56+
/// # use core::slice::IterMut;
57+
/// let iter: IterMut<'_, u8> = Default::default();
58+
/// assert_eq!(iter.len(), 0);
59+
/// ```
60+
fn default() -> Self {
61+
// SAFETY: dangling is sufficiently-aligned so zero-length is always fine
62+
unsafe { DrainRaw::from_parts(NonNull::dangling(), 0) }
63+
}
64+
}
65+
5166
impl<T> DrainRaw<T> {
5267
/// Creates a new iterator which moves the `len` items starting at `ptr`
5368
/// while it's iterated, or drops them when the iterator is dropped.

0 commit comments

Comments
 (0)