Skip to content

Commit 34732e8

Browse files
committedJul 20, 2023
Get !nonnull metadata consistently in slice iterators, without needing assumes
1 parent 06a53dd commit 34732e8

12 files changed

+170
-93
lines changed
 

‎library/core/src/ptr/non_null.rs

+24
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,30 @@ impl<T: ?Sized> NonNull<T> {
462462
// And the caller promised the `delta` is sound to add.
463463
unsafe { NonNull { pointer: self.pointer.add(delta) } }
464464
}
465+
466+
/// See [`pointer::sub`] for semantics and safety requirements.
467+
#[inline]
468+
pub(crate) const unsafe fn sub(self, delta: usize) -> Self
469+
where
470+
T: Sized,
471+
{
472+
// SAFETY: We require that the delta stays in-bounds of the object, and
473+
// thus it cannot become null, as no legal objects can be allocated
474+
// in such as way that the null address is part of them.
475+
// And the caller promised the `delta` is sound to subtract.
476+
unsafe { NonNull { pointer: self.pointer.sub(delta) } }
477+
}
478+
479+
/// See [`pointer::sub_ptr`] for semantics and safety requirements.
480+
#[inline]
481+
pub(crate) const unsafe fn sub_ptr(self, subtrahend: Self) -> usize
482+
where
483+
T: Sized,
484+
{
485+
// SAFETY: The caller promised that this is safe to do, and
486+
// the non-nullness is irrelevant to the operation.
487+
unsafe { self.pointer.sub_ptr(subtrahend.pointer) }
488+
}
465489
}
466490

467491
impl<T> NonNull<[T]> {

‎library/core/src/slice/iter.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::iter::{
1313
use crate::marker::{PhantomData, Send, Sized, Sync};
1414
use crate::mem::{self, SizedTypeProperties};
1515
use crate::num::NonZeroUsize;
16-
use crate::ptr::{invalid, invalid_mut, NonNull};
16+
use crate::ptr::{self, invalid, invalid_mut, NonNull};
1717

1818
use super::{from_raw_parts, from_raw_parts_mut};
1919

@@ -68,7 +68,7 @@ pub struct Iter<'a, T: 'a> {
6868
/// For non-ZSTs, the non-null pointer to the past-the-end element.
6969
///
7070
/// For ZSTs, this is `ptr::invalid(len)`.
71-
end: *const T,
71+
end_or_len: *const T,
7272
_marker: PhantomData<&'a T>,
7373
}
7474

@@ -90,9 +90,9 @@ impl<'a, T> Iter<'a, T> {
9090
let ptr = slice.as_ptr();
9191
// SAFETY: Similar to `IterMut::new`.
9292
unsafe {
93-
let end = if T::IS_ZST { invalid(slice.len()) } else { ptr.add(slice.len()) };
93+
let end_or_len = if T::IS_ZST { invalid(slice.len()) } else { ptr.add(slice.len()) };
9494

95-
Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData }
95+
Self { ptr: NonNull::new_unchecked(ptr as *mut T), end_or_len, _marker: PhantomData }
9696
}
9797
}
9898

@@ -128,7 +128,7 @@ impl<'a, T> Iter<'a, T> {
128128
}
129129
}
130130

131-
iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
131+
iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, as_ref, {
132132
fn is_sorted_by<F>(self, mut compare: F) -> bool
133133
where
134134
Self: Sized,
@@ -142,7 +142,7 @@ iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
142142
impl<T> Clone for Iter<'_, T> {
143143
#[inline]
144144
fn clone(&self) -> Self {
145-
Iter { ptr: self.ptr, end: self.end, _marker: self._marker }
145+
Iter { ptr: self.ptr, end_or_len: self.end_or_len, _marker: self._marker }
146146
}
147147
}
148148

@@ -189,7 +189,7 @@ pub struct IterMut<'a, T: 'a> {
189189
/// For non-ZSTs, the non-null pointer to the past-the-end element.
190190
///
191191
/// For ZSTs, this is `ptr::invalid_mut(len)`.
192-
end: *mut T,
192+
end_or_len: *mut T,
193193
_marker: PhantomData<&'a mut T>,
194194
}
195195

@@ -220,15 +220,16 @@ impl<'a, T> IterMut<'a, T> {
220220
// for direct pointer equality with `ptr` to check if the iterator is
221221
// done.
222222
//
223-
// In the case of a ZST, the end pointer is just the start pointer plus
224-
// the length, to also allows for the fast `ptr == end` check.
223+
// In the case of a ZST, the end pointer is just the length. It's never
224+
// used as a pointer at all, and thus it's fine to have no provenance.
225225
//
226226
// See the `next_unchecked!` and `is_empty!` macros as well as the
227227
// `post_inc_start` method for more information.
228228
unsafe {
229-
let end = if T::IS_ZST { invalid_mut(slice.len()) } else { ptr.add(slice.len()) };
229+
let end_or_len =
230+
if T::IS_ZST { invalid_mut(slice.len()) } else { ptr.add(slice.len()) };
230231

231-
Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData }
232+
Self { ptr: NonNull::new_unchecked(ptr), end_or_len, _marker: PhantomData }
232233
}
233234
}
234235

@@ -360,7 +361,7 @@ impl<T> AsRef<[T]> for IterMut<'_, T> {
360361
// }
361362
// }
362363

363-
iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
364+
iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, as_mut, {}}
364365

365366
/// An internal abstraction over the splitting iterators, so that
366367
/// splitn, splitn_mut etc can be implemented once.

‎library/core/src/slice/iter/macros.rs

+79-67
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,62 @@
11
//! Macros used by iterators of slice.
22
3-
// Shrinks the iterator when T is a ZST, setting the length to `new_len`.
4-
// `new_len` must not exceed `self.len()`.
5-
macro_rules! zst_set_len {
6-
($self: ident, $new_len: expr) => {{
3+
/// Convenience & performance macro for consuming the `end_or_len` field, by
4+
/// giving a `(&mut) usize` or `(&mut) NonNull<T>` depending whether `T` is
5+
/// or is not a ZST respectively.
6+
///
7+
/// Internally, this reads the `end` through a pointer-to-`NonNull` so that
8+
/// it'll get the appropriate non-null metadata in the backend without needing
9+
/// to call `assume` manually.
10+
macro_rules! if_zst {
11+
(mut $this:ident, $len:ident => $zst_body:expr, $end:ident => $other_body:expr,) => {{
712
#![allow(unused_unsafe)] // we're sometimes used within an unsafe block
813

9-
// SAFETY: same as `invalid(_mut)`, but the macro doesn't know
10-
// which versions of that function to call, so open-code it.
11-
$self.end = unsafe { mem::transmute::<usize, _>($new_len) };
14+
if T::IS_ZST {
15+
// SAFETY: for ZSTs, the pointer is storing a provenance-free length,
16+
// so consuming and updating it as a `usize` is fine.
17+
let $len = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::<usize>() };
18+
$zst_body
19+
} else {
20+
// SAFETY: for non-ZSTs, the type invariant ensures it cannot be null
21+
let $end = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::<NonNull<T>>() };
22+
$other_body
23+
}
1224
}};
13-
}
25+
($this:ident, $len:ident => $zst_body:expr, $end:ident => $other_body:expr,) => {{
26+
#![allow(unused_unsafe)] // we're sometimes used within an unsafe block
1427

15-
// Shrinks the iterator when T is a ZST, reducing the length by `n`.
16-
// `n` must not exceed `self.len()`.
17-
macro_rules! zst_shrink {
18-
($self: ident, $n: ident) => {
19-
let new_len = $self.end.addr() - $n;
20-
zst_set_len!($self, new_len);
21-
};
28+
if T::IS_ZST {
29+
let $len = $this.end_or_len.addr();
30+
$zst_body
31+
} else {
32+
// SAFETY: for non-ZSTs, the type invariant ensures it cannot be null
33+
let $end = unsafe { *ptr::addr_of!($this.end_or_len).cast::<NonNull<T>>() };
34+
$other_body
35+
}
36+
}};
2237
}
2338

2439
// Inlining is_empty and len makes a huge performance difference
2540
macro_rules! is_empty {
2641
($self: ident) => {
27-
if T::IS_ZST { $self.end.addr() == 0 } else { $self.ptr.as_ptr() as *const _ == $self.end }
42+
if_zst!($self,
43+
len => len == 0,
44+
end => $self.ptr == end,
45+
)
2846
};
2947
}
3048

3149
macro_rules! len {
3250
($self: ident) => {{
33-
#![allow(unused_unsafe)] // we're sometimes used within an unsafe block
34-
35-
if T::IS_ZST {
36-
$self.end.addr()
37-
} else {
38-
// To get rid of some bounds checks (see `position`), we use ptr_sub instead of
39-
// offset_from (Tested by `codegen/slice-position-bounds-check`.)
40-
// SAFETY: by the type invariant pointers are aligned and `start <= end`
41-
unsafe { $self.end.sub_ptr($self.ptr.as_ptr()) }
42-
}
51+
if_zst!($self,
52+
len => len,
53+
end => {
54+
// To get rid of some bounds checks (see `position`), we use ptr_sub instead of
55+
// offset_from (Tested by `codegen/slice-position-bounds-check`.)
56+
// SAFETY: by the type invariant pointers are aligned and `start <= end`
57+
unsafe { end.sub_ptr($self.ptr) }
58+
},
59+
)
4360
}};
4461
}
4562

@@ -50,20 +67,21 @@ macro_rules! iterator {
5067
$elem:ty,
5168
$raw_mut:tt,
5269
{$( $mut_:tt )?},
70+
$into_ref:ident,
5371
{$($extra:tt)*}
5472
) => {
5573
// Returns the first element and moves the start of the iterator forwards by 1.
5674
// Greatly improves performance compared to an inlined function. The iterator
5775
// must not be empty.
5876
macro_rules! next_unchecked {
59-
($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
77+
($self: ident) => { $self.post_inc_start(1).$into_ref() }
6078
}
6179

6280
// Returns the last element and moves the end of the iterator backwards by 1.
6381
// Greatly improves performance compared to an inlined function. The iterator
6482
// must not be empty.
6583
macro_rules! next_back_unchecked {
66-
($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
84+
($self: ident) => { $self.pre_dec_end(1).$into_ref() }
6785
}
6886

6987
impl<'a, T> $name<'a, T> {
@@ -80,33 +98,40 @@ macro_rules! iterator {
8098
// returning the old start.
8199
// Unsafe because the offset must not exceed `self.len()`.
82100
#[inline(always)]
83-
unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T {
101+
unsafe fn post_inc_start(&mut self, offset: usize) -> NonNull<T> {
84102
let old = self.ptr;
85-
if T::IS_ZST {
86-
zst_shrink!(self, offset);
87-
} else {
88-
// SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
89-
// so this new pointer is inside `self` and thus guaranteed to be non-null.
90-
self.ptr = unsafe { self.ptr.add(offset) };
103+
104+
// SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
105+
// so this new pointer is inside `self` and thus guaranteed to be non-null.
106+
unsafe {
107+
if_zst!(mut self,
108+
len => *len = len.unchecked_sub(offset),
109+
_end => self.ptr = self.ptr.add(offset),
110+
);
91111
}
92-
old.as_ptr()
112+
old
93113
}
94114

95115
// Helper function for moving the end of the iterator backwards by `offset` elements,
96116
// returning the new end.
97117
// Unsafe because the offset must not exceed `self.len()`.
98118
#[inline(always)]
99-
unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T {
100-
if T::IS_ZST {
101-
zst_shrink!(self, offset);
102-
self.ptr.as_ptr()
103-
} else {
119+
unsafe fn pre_dec_end(&mut self, offset: usize) -> NonNull<T> {
120+
if_zst!(mut self,
121+
// SAFETY: By our precondition, `offset` can be at most the
122+
// current length, so the subtraction can never overflow.
123+
len => unsafe {
124+
*len = len.unchecked_sub(offset);
125+
self.ptr
126+
},
104127
// SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
105128
// which is guaranteed to not overflow an `isize`. Also, the resulting pointer
106129
// is in bounds of `slice`, which fulfills the other requirements for `offset`.
107-
self.end = unsafe { self.end.sub(offset) };
108-
self.end
109-
}
130+
end => unsafe {
131+
*end = end.sub(offset);
132+
*end
133+
},
134+
)
110135
}
111136
}
112137

@@ -131,13 +156,9 @@ macro_rules! iterator {
131156
fn next(&mut self) -> Option<$elem> {
132157
// could be implemented with slices, but this avoids bounds checks
133158

134-
// SAFETY: `assume` call is safe because slices over non-ZSTs must
135-
// have a non-null end pointer. The call to `next_unchecked!` is
159+
// SAFETY: The call to `next_unchecked!` is
136160
// safe since we check if the iterator is empty first.
137161
unsafe {
138-
if !<T>::IS_ZST {
139-
assume(!self.end.is_null());
140-
}
141162
if is_empty!(self) {
142163
None
143164
} else {
@@ -161,14 +182,10 @@ macro_rules! iterator {
161182
fn nth(&mut self, n: usize) -> Option<$elem> {
162183
if n >= len!(self) {
163184
// This iterator is now empty.
164-
if T::IS_ZST {
165-
zst_set_len!(self, 0);
166-
} else {
167-
// SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
168-
unsafe {
169-
self.ptr = NonNull::new_unchecked(self.end as *mut T);
170-
}
171-
}
185+
if_zst!(mut self,
186+
len => *len = 0,
187+
end => self.ptr = *end,
188+
);
172189
return None;
173190
}
174191
// SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
@@ -375,13 +392,9 @@ macro_rules! iterator {
375392
fn next_back(&mut self) -> Option<$elem> {
376393
// could be implemented with slices, but this avoids bounds checks
377394

378-
// SAFETY: `assume` call is safe because slices over non-ZSTs must
379-
// have a non-null end pointer. The call to `next_back_unchecked!`
395+
// SAFETY: The call to `next_back_unchecked!`
380396
// is safe since we check if the iterator is empty first.
381397
unsafe {
382-
if !<T>::IS_ZST {
383-
assume(!self.end.is_null());
384-
}
385398
if is_empty!(self) {
386399
None
387400
} else {
@@ -394,11 +407,10 @@ macro_rules! iterator {
394407
fn nth_back(&mut self, n: usize) -> Option<$elem> {
395408
if n >= len!(self) {
396409
// This iterator is now empty.
397-
if T::IS_ZST {
398-
zst_set_len!(self, 0);
399-
} else {
400-
self.end = self.ptr.as_ptr();
401-
}
410+
if_zst!(mut self,
411+
len => *len = 0,
412+
end => *end = self.ptr,
413+
);
402414
return None;
403415
}
404416
// SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.

‎tests/codegen/iter-repeat-n-trivial-drop.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCop
3434
// CHECK: [[EMPTY]]:
3535
// CHECK-NOT: br
3636
// CHECK: phi i16
37+
// CHECK-SAME: [ %[[VAL]], %[[NOT_EMPTY]] ]
3738
// CHECK-NOT: br
3839
// CHECK: ret
3940

‎tests/codegen/slice-iter-len-eq-zero.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ type Demo = [u8; 3];
99
#[no_mangle]
1010
pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool {
1111
// CHECK-NOT: sub
12-
// CHECK: %_0 = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}}
13-
// CHECK: ret i1 %_0
12+
// CHECK: %[[RET:.+]] = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}}
13+
// CHECK: ret i1 %[[RET]]
1414
y.len() == 0
1515
}
1616

‎tests/codegen/slice-iter-nonnull.rs

+39
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
// compile-flags: -O
33
// ignore-debug (these add extra checks that make it hard to verify)
44
#![crate_type = "lib"]
5+
#![feature(exact_size_is_empty)]
56

67
// The slice iterator used to `assume` that the `start` pointer was non-null.
78
// That ought to be unneeded, though, since the type is `NonNull`, so this test
89
// confirms that the appropriate metadata is included to denote that.
910

11+
// It also used to `assume` the `end` pointer was non-null, but that's no longer
12+
// needed as the code changed to read it as a `NonNull`, and thus gets the
13+
// appropriate `!nonnull` annotations naturally.
14+
1015
// CHECK-LABEL: @slice_iter_next(
1116
#[no_mangle]
1217
pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> {
@@ -75,3 +80,37 @@ pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> {
7580
// CHECK: }
7681
slice.iter_mut()
7782
}
83+
84+
// CHECK-LABEL: @slice_iter_is_empty
85+
#[no_mangle]
86+
pub fn slice_iter_is_empty(it: &std::slice::Iter<'_, u32>) -> bool {
87+
// CHECK: %[[ENDP:.+]] = getelementptr{{.+}}ptr %it,{{.+}} 1
88+
// CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
89+
// CHECK-SAME: !nonnull
90+
// CHECK-SAME: !noundef
91+
// CHECK: %[[START:.+]] = load ptr, ptr %it,
92+
// CHECK-SAME: !nonnull
93+
// CHECK-SAME: !noundef
94+
95+
// CHECK: %[[RET:.+]] = icmp eq ptr %[[START]], %[[END]]
96+
// CHECK: ret i1 %[[RET]]
97+
it.is_empty()
98+
}
99+
100+
// CHECK-LABEL: @slice_iter_len
101+
#[no_mangle]
102+
pub fn slice_iter_len(it: &std::slice::Iter<'_, u32>) -> usize {
103+
// CHECK: %[[START:.+]] = load ptr, ptr %it,
104+
// CHECK-SAME: !nonnull
105+
// CHECK-SAME: !noundef
106+
// CHECK: %[[ENDP:.+]] = getelementptr{{.+}}ptr %it,{{.+}} 1
107+
// CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]]
108+
// CHECK-SAME: !nonnull
109+
// CHECK-SAME: !noundef
110+
111+
// CHECK: ptrtoint
112+
// CHECK: ptrtoint
113+
// CHECK: sub nuw
114+
// CHECK: lshr exact
115+
it.len()
116+
}

‎tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
3838
scope 6 {
3939
let _7: *const T;
4040
scope 7 {
41-
debug end => _7;
41+
debug end_or_len => _7;
4242
scope 13 (inlined NonNull::<T>::new_unchecked) {
4343
debug ptr => _9;
4444
let mut _10: *const T;
@@ -138,7 +138,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
138138
StorageDead(_9);
139139
StorageLive(_12);
140140
_12 = _7;
141-
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> };
141+
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
142142
StorageDead(_12);
143143
StorageDead(_11);
144144
StorageDead(_7);

‎tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
3838
scope 6 {
3939
let _7: *const T;
4040
scope 7 {
41-
debug end => _7;
41+
debug end_or_len => _7;
4242
scope 13 (inlined NonNull::<T>::new_unchecked) {
4343
debug ptr => _9;
4444
let mut _10: *const T;
@@ -138,7 +138,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
138138
StorageDead(_9);
139139
StorageLive(_12);
140140
_12 = _7;
141-
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> };
141+
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
142142
StorageDead(_12);
143143
StorageDead(_11);
144144
StorageDead(_7);

‎tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
3535
scope 6 {
3636
let _7: *const T;
3737
scope 7 {
38-
debug end => _7;
38+
debug end_or_len => _7;
3939
scope 13 (inlined NonNull::<T>::new_unchecked) {
4040
debug ptr => _9;
4141
let mut _10: *const T;
@@ -128,7 +128,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
128128
StorageDead(_9);
129129
StorageLive(_12);
130130
_12 = _7;
131-
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> };
131+
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
132132
StorageDead(_12);
133133
StorageDead(_11);
134134
StorageDead(_7);

‎tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
3535
scope 6 {
3636
let _7: *const T;
3737
scope 7 {
38-
debug end => _7;
38+
debug end_or_len => _7;
3939
scope 13 (inlined NonNull::<T>::new_unchecked) {
4040
debug ptr => _9;
4141
let mut _10: *const T;
@@ -128,7 +128,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
128128
StorageDead(_9);
129129
StorageLive(_12);
130130
_12 = _7;
131-
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> };
131+
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
132132
StorageDead(_12);
133133
StorageDead(_11);
134134
StorageDead(_7);

‎tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
3939
scope 6 {
4040
let _7: *const T;
4141
scope 7 {
42-
debug end => _7;
42+
debug end_or_len => _7;
4343
scope 13 (inlined NonNull::<T>::new_unchecked) {
4444
debug ptr => _9;
4545
let mut _10: *const T;
@@ -139,7 +139,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
139139
StorageDead(_9);
140140
StorageLive(_12);
141141
_12 = _7;
142-
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> };
142+
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
143143
StorageDead(_12);
144144
StorageDead(_11);
145145
StorageDead(_7);

‎tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
3939
scope 6 {
4040
let _7: *const T;
4141
scope 7 {
42-
debug end => _7;
42+
debug end_or_len => _7;
4343
scope 13 (inlined NonNull::<T>::new_unchecked) {
4444
debug ptr => _9;
4545
let mut _10: *const T;
@@ -139,7 +139,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
139139
StorageDead(_9);
140140
StorageLive(_12);
141141
_12 = _7;
142-
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> };
142+
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
143143
StorageDead(_12);
144144
StorageDead(_11);
145145
StorageDead(_7);

0 commit comments

Comments
 (0)
Please sign in to comment.