@@ -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 > {
@@ -333,7 +372,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
333372 // There are in fact no remaining elements to forget, but by doing this we can avoid
334373 // potentially generating a needless loop to drop the elements that cannot exist at
335374 // this point.
336- self . forget_remaining_elements ( ) ;
375+ self . forget_remaining_elements_and_dealloc ( ) ;
337376
338377 accum
339378 }
@@ -502,10 +541,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
502541 impl < T , A : Allocator > Drop for DropGuard < ' _ , T , A > {
503542 fn drop ( & mut self ) {
504543 unsafe {
505- // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec
506- let alloc = ManuallyDrop :: take ( & mut self . 0 . alloc ) ;
507- // RawVec handles deallocation
508- let _ = RawVec :: from_nonnull_in ( self . 0 . buf , self . 0 . cap , alloc) ;
544+ self . 0 . dealloc_only ( ) ;
509545 }
510546 }
511547 }
0 commit comments