1
1
use crate::alloc::{Allocator, Global};
2
2
use core::fmt;
3
3
use core::iter::{FusedIterator, TrustedLen};
4
- use core::mem::{self} ;
4
+ use core::mem;
5
5
use core::ptr::{self, NonNull};
6
6
use core::slice::{self};
7
7
@@ -104,16 +104,11 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
104
104
#[stable(feature = "drain", since = "1.6.0")]
105
105
impl<T, A: Allocator> Drop for Drain<'_, T, A> {
106
106
fn drop(&mut self) {
107
- /// Continues dropping the remaining elements in the `Drain`, then moves back the
108
- /// un-`Drain`ed elements to restore the original `Vec`.
107
+ /// Moves back the un-`Drain`ed elements to restore the original `Vec`.
109
108
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
110
109
111
110
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
112
111
fn drop(&mut self) {
113
- // Continue the same loop we have below. If the loop already finished, this does
114
- // nothing.
115
- self.0.for_each(drop);
116
-
117
112
if self.0.tail_len > 0 {
118
113
unsafe {
119
114
let source_vec = self.0.vec.as_mut();
@@ -131,15 +126,45 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
131
126
}
132
127
}
133
128
134
- // exhaust self first
135
- while let Some(item) = self.next() {
136
- let guard = DropGuard(self);
137
- drop(item);
138
- mem::forget(guard);
129
+ let iter = mem::replace(&mut self.iter, (&mut []).iter());
130
+ let drop_len = iter.len();
131
+ let drop_ptr = iter.as_slice().as_ptr();
132
+
133
+ // forget iter so there's no aliasing reference
134
+ drop(iter);
135
+
136
+ let mut vec = self.vec;
137
+
138
+ if mem::size_of::<T>() == 0 {
139
+ // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
140
+ // this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
141
+ unsafe {
142
+ let vec = vec.as_mut();
143
+ let old_len = vec.len();
144
+ vec.set_len(old_len + drop_len + self.tail_len);
145
+ vec.truncate(old_len + self.tail_len);
146
+ }
147
+
148
+ return;
149
+ }
150
+
151
+ // ensure elements are moved back into their appropriate places, even when drop_in_place panics
152
+ let _guard = DropGuard(self);
153
+
154
+ if drop_len == 0 {
155
+ return;
139
156
}
140
157
141
- // Drop a `DropGuard` to move back the non-drained tail of `self`.
142
- DropGuard(self);
158
+ unsafe {
159
+ // drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
160
+ // a pointer with mutable provenance is necessary. Therefore we must reconstruct
161
+ // it from the original vec but also avoid creating a &mut to the front since that could
162
+ // invalidate raw pointers to it which some unsafe code might rely on.
163
+ let vec_ptr = vec.as_mut().as_mut_ptr();
164
+ let drop_offset = drop_ptr.offset_from(vec_ptr) as usize;
165
+ let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
166
+ ptr::drop_in_place(to_drop);
167
+ }
143
168
}
144
169
}
145
170
0 commit comments