Skip to content

Commit 047ff0b

Browse files
committed
Use NonNull in slice::Iter and slice::IterMut.
`ptr` of `slice::Iter` and `slice::IterMut` can never be null, but this fact wasn't exploited for layout optimizations. By changing `ptr` from `*<mutability> T` to `NonNull<T>`, the compiler can now optimize layout of `Option<Iter<'a, T>>`.
1 parent ed33453 commit 047ff0b

File tree

1 file changed

+25
-22
lines changed

1 file changed

+25
-22
lines changed

src/libcore/slice/mod.rs

+25-22
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::mem;
3434
use crate::ops::{self, FnMut, Range};
3535
use crate::option::Option;
3636
use crate::option::Option::{None, Some};
37-
use crate::ptr;
37+
use crate::ptr::{NonNull, self};
3838
use crate::result::Result;
3939
use crate::result::Result::{Err, Ok};
4040

@@ -628,7 +628,7 @@ impl<T> [T] {
628628
ptr.add(self.len())
629629
};
630630

631-
Iter { ptr, end, _marker: marker::PhantomData }
631+
Iter { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: marker::PhantomData }
632632
}
633633
}
634634

@@ -656,7 +656,7 @@ impl<T> [T] {
656656
ptr.add(self.len())
657657
};
658658

659-
IterMut { ptr, end, _marker: marker::PhantomData }
659+
IterMut { ptr: NonNull::new_unchecked(ptr), end, _marker: marker::PhantomData }
660660
}
661661
}
662662

@@ -3095,7 +3095,7 @@ macro_rules! is_empty {
30953095
// The way we encode the length of a ZST iterator, this works both for ZST
30963096
// and non-ZST.
30973097
($self: ident) => {
3098-
$self.ptr == $self.end
3098+
$self.ptr.as_ptr() as *const T == $self.end
30993099
};
31003100
}
31013101
// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
@@ -3105,17 +3105,17 @@ macro_rules! len {
31053105
#![allow(unused_unsafe)] // we're sometimes used within an unsafe block
31063106

31073107
let start = $self.ptr;
3108-
let size = size_from_ptr(start);
3108+
let size = size_from_ptr(start.as_ptr());
31093109
if size == 0 {
31103110
// This _cannot_ use `unchecked_sub` because we depend on wrapping
31113111
// to represent the length of long ZST slice iterators.
3112-
($self.end as usize).wrapping_sub(start as usize)
3112+
($self.end as usize).wrapping_sub(start.as_ptr() as usize)
31133113
} else {
31143114
// We know that `start <= end`, so can do better than `offset_from`,
31153115
// which needs to deal in signed. By setting appropriate flags here
31163116
// we can tell LLVM this, which helps it remove bounds checks.
31173117
// SAFETY: By the type invariant, `start <= end`
3118-
let diff = unsafe { unchecked_sub($self.end as usize, start as usize) };
3118+
let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
31193119
// By also telling LLVM that the pointers are apart by an exact
31203120
// multiple of the type size, it can optimize `len() == 0` down to
31213121
// `start == end` instead of `(end - start) < size`.
@@ -3161,7 +3161,7 @@ macro_rules! iterator {
31613161
// Helper function for creating a slice from the iterator.
31623162
#[inline(always)]
31633163
fn make_slice(&self) -> &'a [T] {
3164-
unsafe { from_raw_parts(self.ptr, len!(self)) }
3164+
unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
31653165
}
31663166

31673167
// Helper function for moving the start of the iterator forwards by `offset` elements,
@@ -3171,10 +3171,10 @@ macro_rules! iterator {
31713171
unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
31723172
if mem::size_of::<T>() == 0 {
31733173
zst_shrink!(self, offset);
3174-
self.ptr
3174+
self.ptr.as_ptr()
31753175
} else {
3176-
let old = self.ptr;
3177-
self.ptr = self.ptr.offset(offset);
3176+
let old = self.ptr.as_ptr();
3177+
self.ptr = NonNull::new_unchecked(self.ptr.as_ptr().offset(offset));
31783178
old
31793179
}
31803180
}
@@ -3186,7 +3186,7 @@ macro_rules! iterator {
31863186
unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
31873187
if mem::size_of::<T>() == 0 {
31883188
zst_shrink!(self, offset);
3189-
self.ptr
3189+
self.ptr.as_ptr()
31903190
} else {
31913191
self.end = self.end.offset(-offset);
31923192
self.end
@@ -3215,7 +3215,7 @@ macro_rules! iterator {
32153215
fn next(&mut self) -> Option<$elem> {
32163216
// could be implemented with slices, but this avoids bounds checks
32173217
unsafe {
3218-
assume(!self.ptr.is_null());
3218+
assume(!self.ptr.as_ptr().is_null());
32193219
if mem::size_of::<T>() != 0 {
32203220
assume(!self.end.is_null());
32213221
}
@@ -3245,9 +3245,12 @@ macro_rules! iterator {
32453245
if mem::size_of::<T>() == 0 {
32463246
// We have to do it this way as `ptr` may never be 0, but `end`
32473247
// could be (due to wrapping).
3248-
self.end = self.ptr;
3248+
self.end = self.ptr.as_ptr();
32493249
} else {
3250-
self.ptr = self.end;
3250+
unsafe {
3251+
// End can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
3252+
self.ptr = NonNull::new_unchecked(self.end as *mut T);
3253+
}
32513254
}
32523255
return None;
32533256
}
@@ -3308,7 +3311,7 @@ macro_rules! iterator {
33083311
fn next_back(&mut self) -> Option<$elem> {
33093312
// could be implemented with slices, but this avoids bounds checks
33103313
unsafe {
3311-
assume(!self.ptr.is_null());
3314+
assume(!self.ptr.as_ptr().is_null());
33123315
if mem::size_of::<T>() != 0 {
33133316
assume(!self.end.is_null());
33143317
}
@@ -3324,7 +3327,7 @@ macro_rules! iterator {
33243327
fn nth_back(&mut self, n: usize) -> Option<$elem> {
33253328
if n >= len!(self) {
33263329
// This iterator is now empty.
3327-
self.end = self.ptr;
3330+
self.end = self.ptr.as_ptr();
33283331
return None;
33293332
}
33303333
// We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
@@ -3365,7 +3368,7 @@ macro_rules! iterator {
33653368
/// [slices]: ../../std/primitive.slice.html
33663369
#[stable(feature = "rust1", since = "1.0.0")]
33673370
pub struct Iter<'a, T: 'a> {
3368-
ptr: *const T,
3371+
ptr: NonNull<T>,
33693372
end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
33703373
// ptr == end is a quick test for the Iterator being empty, that works
33713374
// for both ZST and non-ZST.
@@ -3467,7 +3470,7 @@ impl<T> AsRef<[T]> for Iter<'_, T> {
34673470
/// [slices]: ../../std/primitive.slice.html
34683471
#[stable(feature = "rust1", since = "1.0.0")]
34693472
pub struct IterMut<'a, T: 'a> {
3470-
ptr: *mut T,
3473+
ptr: NonNull<T>,
34713474
end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
34723475
// ptr == end is a quick test for the Iterator being empty, that works
34733476
// for both ZST and non-ZST.
@@ -3522,7 +3525,7 @@ impl<'a, T> IterMut<'a, T> {
35223525
/// ```
35233526
#[stable(feature = "iter_to_slice", since = "1.4.0")]
35243527
pub fn into_slice(self) -> &'a mut [T] {
3525-
unsafe { from_raw_parts_mut(self.ptr, len!(self)) }
3528+
unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) }
35263529
}
35273530

35283531
/// Views the underlying data as a subslice of the original data.
@@ -5682,7 +5685,7 @@ impl_marker_for!(BytewiseEquality,
56825685
#[doc(hidden)]
56835686
unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {
56845687
unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
5685-
&*self.ptr.add(i)
5688+
&*self.ptr.as_ptr().add(i)
56865689
}
56875690
fn may_have_side_effect() -> bool {
56885691
false
@@ -5692,7 +5695,7 @@ unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {
56925695
#[doc(hidden)]
56935696
unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {
56945697
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
5695-
&mut *self.ptr.add(i)
5698+
&mut *self.ptr.as_ptr().add(i)
56965699
}
56975700
fn may_have_side_effect() -> bool {
56985701
false

0 commit comments

Comments
 (0)