@@ -40,7 +40,9 @@ pub struct IntoIter<
4040 // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
4141 pub ( super ) alloc : ManuallyDrop < A > ,
4242 pub ( super ) ptr : * const T ,
43- pub ( super ) end : * const T ,
43+ pub ( super ) end : * const T , // If T is a ZST, this is actually ptr+len. This encoding is picked so that
44+ // ptr == end is a quick test for the Iterator being empty, that works
45+ // for both ZST and non-ZST.
4446}
4547
4648#[ stable( feature = "vec_intoiter_debug" , since = "1.13.0" ) ]
@@ -132,7 +134,9 @@ impl<T, A: Allocator> IntoIter<T, A> {
132134
133135 /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
134136 pub ( crate ) fn forget_remaining_elements ( & mut self ) {
135- self . ptr = self . end ;
137+ // For th ZST case, it is crucial that we mutate `end` here, not `ptr`.
138+ // `ptr` must stay aligned, while `end` may be unaligned.
139+ self . end = self . ptr ;
136140 }
137141
138142 #[ cfg( not( no_global_oom_handling) ) ]
@@ -184,10 +188,9 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
184188 if self . ptr == self . end {
185189 None
186190 } else if T :: IS_ZST {
187- // purposefully don't use 'ptr.offset' because for
188- // vectors with 0-size elements this would return the
189- // same pointer.
190- self . ptr = self . ptr . wrapping_byte_add ( 1 ) ;
191+ // `ptr` has to stay where it is to remain aligned, so we reduce the length by 1 by
192+ // reducing the `end`.
193+ self . end = self . end . wrapping_byte_sub ( 1 ) ;
191194
192195 // Make up a value of this ZST.
193196 Some ( unsafe { mem:: zeroed ( ) } )
@@ -214,10 +217,8 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
214217 let step_size = self . len ( ) . min ( n) ;
215218 let to_drop = ptr:: slice_from_raw_parts_mut ( self . ptr as * mut T , step_size) ;
216219 if T :: IS_ZST {
217- // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound
218- // effectively results in unsigned pointers representing positions 0..usize::MAX,
219- // which is valid for ZSTs.
220- self . ptr = self . ptr . wrapping_byte_add ( step_size) ;
220+ // See `next` for why we sub `end` here.
221+ self . end = self . end . wrapping_byte_sub ( step_size) ;
221222 } else {
222223 // SAFETY: the min() above ensures that step_size is in bounds
223224 self . ptr = unsafe { self . ptr . add ( step_size) } ;
0 commit comments