11//! Macros used by iterators of slice.
22
3- /// Convenience & performance macro for consuming the `end_or_len` field, by
3+ /// Convenience macro for updating the `end_addr_or_len` field for non-ZSTs.
4+ macro_rules! set_end {
5+ ( $this: ident . end = $new_end: expr) => { {
6+ $this. end_addr_or_len = addr_usize( $new_end) ;
7+ } } ;
8+ }
9+
10+ /// Convenience & performance macro for consuming the `end_addr_or_len` field, by
411/// giving a `(&mut) usize` or `(&mut) NonNull<T>` depending whether `T` is
512/// or is not a ZST respectively.
613///
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.
14+ /// When giving a `NonNull<T>` for the end, it creates it by offsetting from the
15+ /// `ptr` so that the backend knows that both pointers have the same provenance.
1016macro_rules! if_zst {
1117 ( mut $this: ident, $len: ident => $zst_body: expr, $end: ident => $other_body: expr, ) => { {
1218 #![ allow( unused_unsafe) ] // we're sometimes used within an unsafe block
1319
20+ let ptr = $this. ptr;
1421 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 * ( & raw mut $this. end_or_len) . cast:: <usize >( ) } ;
22+ let $len = & mut $this. end_addr_or_len;
1823 $zst_body
1924 } else {
20- // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null
21- let $end = unsafe { & mut * ( & raw mut $this. end_or_len) . cast:: <NonNull <T >>( ) } ;
25+ let $len;
26+ #[ allow( unused_unsafe) ] // we're sometimes used within an unsafe block
27+ // SAFETY: By type invariant `end >= ptr`, and thus the subtraction
28+ // cannot overflow, and the iter represents a single allocated
29+ // object so the `add` will also be in-range.
30+ let $end = unsafe {
31+ // Need to load as `NonNull` to get `!nonnull` metadata
32+ // (Transmuting gets an assume instead)
33+ let end: NonNull <T > = * ptr:: addr_of!( $this. end_addr_or_len) . cast( ) ;
34+ // Not using `with_addr` because we have ordering information that
35+ // we can take advantage of here that `with_addr` cannot.
36+ $len = intrinsics:: ptr_offset_from_unsigned( end. as_ptr( ) , ptr. as_ptr( ) ) ;
37+ ptr. add( $len)
38+ } ;
2239 $other_body
2340 }
2441 } } ;
2542 ( $this: ident, $len: ident => $zst_body: expr, $end: ident => $other_body: expr, ) => { {
26- #![ allow( unused_unsafe) ] // we're sometimes used within an unsafe block
27-
2843 if T :: IS_ZST {
29- let $len = $this. end_or_len . addr ( ) ;
44+ let $len = $this. end_addr_or_len ;
3045 $zst_body
3146 } else {
32- // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null
33- let $end = unsafe { mem:: transmute:: <* const T , NonNull <T >>( $this. end_or_len) } ;
47+ let $len;
48+ #[ allow( unused_unsafe) ] // we're sometimes used within an unsafe block
49+ // SAFETY: By type invariant `end >= ptr`, and thus the subtraction
50+ // cannot overflow, and the iter represents a single allocated
51+ // object so the `add` will also be in-range.
52+ let $end = unsafe {
53+ let ptr = $this. ptr;
54+ // Need to load as `NonNull` to get `!nonnull` metadata
55+ // (Transmuting gets an assume instead)
56+ let end: NonNull <T > = * ptr:: addr_of!( $this. end_addr_or_len) . cast( ) ;
57+ // Not using `with_addr` because we have ordering information that
58+ // we can take advantage of here that `with_addr` cannot.
59+ $len = intrinsics:: ptr_offset_from_unsigned( end. as_ptr( ) , ptr. as_ptr( ) ) ;
60+ ptr. add( $len)
61+ } ;
3462 $other_body
3563 }
3664 } } ;
@@ -50,12 +78,7 @@ macro_rules! len {
5078 ( $self: ident) => { {
5179 if_zst!( $self,
5280 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. offset_from_unsigned( $self. ptr) }
58- } ,
81+ _end => len,
5982 )
6083 } } ;
6184}
@@ -128,8 +151,9 @@ macro_rules! iterator {
128151 // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
129152 // is in bounds of `slice`, which fulfills the other requirements for `offset`.
130153 end => unsafe {
131- * end = end. sub( offset) ;
132- * end
154+ let new_end = end. sub( offset) ;
155+ set_end!( self . end = new_end) ;
156+ new_end
133157 } ,
134158 )
135159 }
@@ -158,25 +182,24 @@ macro_rules! iterator {
158182 // one of the most mono'd things in the library.
159183
160184 let ptr = self . ptr;
161- let end_or_len = self . end_or_len;
162185 // SAFETY: See inner comments. (For some reason having multiple
163186 // block breaks inlining this -- if you can fix that please do!)
164187 unsafe {
165188 if T :: IS_ZST {
166- let len = end_or_len . addr ( ) ;
189+ let len = self . end_addr_or_len ;
167190 if len == 0 {
168191 return None ;
169192 }
170193 // SAFETY: just checked that it's not zero, so subtracting one
171194 // cannot wrap. (Ideally this would be `checked_sub`, which
172195 // does the same thing internally, but as of 2025-02 that
173196 // doesn't optimize quite as small in MIR.)
174- self . end_or_len = without_provenance_mut ( len . unchecked_sub( 1 ) ) ;
197+ self . end_addr_or_len = intrinsics :: unchecked_sub( len , 1 ) ;
175198 } else {
176- // SAFETY: by type invariant, the `end_or_len ` field is always
199+ // SAFETY: by type invariant, the `end_addr_or_len ` field is always
177200 // non-null for a non-ZST pointee. (This transmute ensures we
178201 // get `!nonnull` metadata on the load of the field.)
179- if ptr == crate :: intrinsics :: transmute :: <$ptr , NonNull <T >>( end_or_len ) {
202+ if ptr == * ( & raw const self . end_addr_or_len ) . cast :: < NonNull <T >>( ) {
180203 return None ;
181204 }
182205 // SAFETY: since it's not empty, per the check above, moving
@@ -207,7 +230,7 @@ macro_rules! iterator {
207230 // This iterator is now empty.
208231 if_zst!( mut self ,
209232 len => * len = 0 ,
210- end => self . ptr = * end,
233+ end => self . ptr = end,
211234 ) ;
212235 return None ;
213236 }
@@ -432,7 +455,7 @@ macro_rules! iterator {
432455 // This iterator is now empty.
433456 if_zst!( mut self ,
434457 len => * len = 0 ,
435- end => * end = self . ptr,
458+ _end => set_end! ( self . end = self . ptr) ,
436459 ) ;
437460 return None ;
438461 }
0 commit comments