11use crate :: alloc:: { Allocator , Global } ;
22use core:: fmt;
33use core:: iter:: { FusedIterator , TrustedLen } ;
4- use core:: mem:: { self } ;
4+ use core:: mem;
55use core:: ptr:: { self , NonNull } ;
66use core:: slice:: { self } ;
77
@@ -104,16 +104,11 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
104104#[ stable( feature = "drain" , since = "1.6.0" ) ]
105105impl < T , A : Allocator > Drop for Drain < ' _ , T , A > {
106106 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`.
109108 struct DropGuard < ' r , ' a , T , A : Allocator > ( & ' r mut Drain < ' a , T , A > ) ;
110109
111110 impl < ' r , ' a , T , A : Allocator > Drop for DropGuard < ' r , ' a , T , A > {
112111 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-
117112 if self . 0 . tail_len > 0 {
118113 unsafe {
119114 let source_vec = self . 0 . vec . as_mut ( ) ;
@@ -131,15 +126,45 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
131126 }
132127 }
133128
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 ;
139156 }
140157
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+ }
143168 }
144169}
145170
0 commit comments