@@ -160,12 +160,51 @@ impl<T, A: Allocator> IntoIter<T, A> {
160160 }
161161
162162 /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
163+ ///
164+ /// This method does not consume `self`, and leaves deallocation to `impl Drop for IntoIter`.
165+ /// If consuming `self` is possible, consider calling
166+ /// [`Self::forget_remaining_elements_and_dealloc()`] instead.
163167 pub ( crate ) fn forget_remaining_elements ( & mut self ) {
164168 // For the ZST case, it is crucial that we mutate `end` here, not `ptr`.
165169 // `ptr` must stay aligned, while `end` may be unaligned.
166170 self . end = self . ptr . as_ptr ( ) ;
167171 }
168172
173+ /// Forgets to Drop the remaining elements and frees the backing allocation.
174+ /// Consuming version of [`Self::forget_remaining_elements()`].
175+ ///
176+ /// This can be used in place of `drop(self)` when `self` is known to be exhausted,
177+ /// to avoid producing a needless `drop_in_place::<[T]>()`.
178+ #[ inline]
179+ pub ( crate ) fn forget_remaining_elements_and_dealloc ( self ) {
180+ let mut this = ManuallyDrop :: new ( self ) ;
181+ // SAFETY: `this` is in ManuallyDrop, so it will not be double-freed.
182+ unsafe {
183+ this. dealloc_only ( ) ;
184+ }
185+ }
186+
187+ /// Frees the allocation, without checking or dropping anything else.
188+ ///
189+ /// The safe version of this method is [`Self::forget_remaining_elements_and_dealloc()`].
190+ /// This function exists only to share code between that method and the `impl Drop`.
191+ ///
192+ /// # Safety
193+ ///
194+ /// This function must only be called with an [`IntoIter`] that is not going to be dropped
195+ /// or otherwise used in any way, either because it is being forgotten or because its `Drop`
196+ /// is already executing; otherwise a double-free will occur, and possibly a read from freed
197+ /// memory if there are any remaining elements.
198+ #[ inline]
199+ unsafe fn dealloc_only ( & mut self ) {
200+ unsafe {
201+ // SAFETY: our caller promises not to touch `*self` again
202+ let alloc = ManuallyDrop :: take ( & mut self . alloc ) ;
203+ // RawVec handles deallocation
204+ let _ = RawVec :: from_nonnull_in ( self . buf , self . cap , alloc) ;
205+ }
206+ }
207+
169208 #[ cfg( not( no_global_oom_handling) ) ]
170209 #[ inline]
171210 pub ( crate ) fn into_vecdeque ( self ) -> VecDeque < T , A > {
@@ -329,6 +368,12 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
329368 accum = f ( accum, tmp) ;
330369 }
331370 }
371+
372+ // There are in fact no remaining elements to forget, but by doing this we can avoid
373+ // potentially generating a needless loop to drop the elements that cannot exist at
374+ // this point.
375+ self . forget_remaining_elements_and_dealloc ( ) ;
376+
332377 accum
333378 }
334379
@@ -496,10 +541,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
496541 impl < T , A : Allocator > Drop for DropGuard < ' _ , T , A > {
497542 fn drop ( & mut self ) {
498543 unsafe {
499- // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec
500- let alloc = ManuallyDrop :: take ( & mut self . 0 . alloc ) ;
501- // RawVec handles deallocation
502- let _ = RawVec :: from_nonnull_in ( self . 0 . buf , self . 0 . cap , alloc) ;
544+ self . 0 . dealloc_only ( ) ;
503545 }
504546 }
505547 }
0 commit comments