@@ -15,7 +15,6 @@ pub(crate) mod ptr {
1515 use core:: {
1616 fmt:: { Debug , Formatter } ,
1717 marker:: PhantomData ,
18- mem,
1918 ptr:: NonNull ,
2019 } ;
2120
@@ -42,31 +41,14 @@ pub(crate) mod ptr {
4241 // INVARIANTS:
4342 // - `ptr` is derived from some valid Rust allocation, `A`
4443 // - `ptr` has the same provenance as `A`
45- // - `ptr` addresses a byte range of length `bytes_len` which is
46- // entirely contained in `A`
47- // - `bytes_len <= isize::MAX`
44+ // - `ptr` addresses a byte range which is entirely contained in `A`
45+ // - `ptr` addresses a byte range whose length fits in an `isize`
4846 // - `ptr` addresses a byte range which does not wrap around the address
4947 // space
5048 // - `ptr` is validly-aligned for `T`
5149 // - `A` is guaranteed to live for at least `'a`
5250 // - `T: 'a`
5351 ptr : NonNull < T > ,
54- // TODO(https://github.com/rust-lang/reference/pull/1417): Once the
55- // behavior of slice DST-to-slice DST raw pointer casts is guaranteed,
56- // we can use it to calculate the length of the memory region from
57- // `ptr`, and we don't need to store in separately. We can do it like
58- // this:
59- //
60- // let slc = ptr.as_ptr() as *const [()];
61- // // SAFETY:
62- // // - `()` has alignment 1, so `slc` is trivially aligned
63- // // - `slc` was derived from a non-null pointer
64- // // - the size is 0 regardless of the length, so it is sound to
65- // // materialize a reference regardless of location
66- // // - pointer provenance may be an issue, but we never dereference
67- // let slc = unsafe { &*slc };
68- // slc.len()
69- _bytes_len : usize ,
7052 _lifetime : PhantomData < & ' a ( ) > ,
7153 }
7254
@@ -170,34 +152,30 @@ pub(crate) mod ptr {
170152 // panic.
171153 let ( elems, split_at) = U :: LAYOUT . _validate_cast_and_convert_metadata (
172154 AsAddress :: addr ( self . ptr . as_ptr ( ) ) ,
173- self . _bytes_len ,
155+ self . _len ( ) ,
174156 cast_type,
175157 ) ?;
176- let ( offset, ret_len) = match cast_type {
177- _CastType:: _Prefix => ( 0 , split_at) ,
178- // Guaranteed not to underflow:
179- // `validate_cast_and_convert_metadata` promises that `split_at`
180- // is in the range `[0, bytes_len]`.
181- #[ allow( clippy:: arithmetic_side_effects) ]
182- _CastType:: _Suffix => ( split_at, self . _bytes_len - split_at) ,
158+ let offset = match cast_type {
159+ _CastType:: _Prefix => 0 ,
160+ _CastType:: _Suffix => split_at,
183161 } ;
184162
185163 let ptr = self . ptr . cast :: < u8 > ( ) . as_ptr ( ) ;
186164 // SAFETY: `offset` is either `0` or `split_at`.
187165 // `validate_cast_and_convert_metadata` promises that `split_at` is
188- // in the range `[0, bytes_len ]`. Thus, in both cases, `offset` is
189- // in `[0, bytes_len ]`. Thus:
166+ // in the range `[0, self.len() ]`. Thus, in both cases, `offset` is
167+ // in `[0, self.len() ]`. Thus:
190168 // - The resulting pointer is in or one byte past the end of the
191169 // same byte range as `self.ptr`. Since, by invariant, `self.ptr`
192170 // addresses a byte range entirely contained within a single
193171 // allocation, the pointer resulting from this operation is within
194172 // or one byte past the end of that same allocation.
195- // - By invariant, `bytes_len <= isize::MAX`. Since `offset <=
196- // bytes_len `, `offset <= isize::MAX`.
173+ // - By invariant, `self.len() <= isize::MAX`. Since `offset <=
174+ // self.len() `, `offset <= isize::MAX`.
197175 // - By invariant, `self.ptr` addresses a byte range which does not
198176 // wrap around the address space. This means that the base pointer
199- // plus the `bytes_len ` does not overflow `usize`. Since `offset
200- // <= bytes_len `, this addition does not overflow `usize`.
177+ // plus the `self.len() ` does not overflow `usize`. Since `offset
178+ // <= self.len() `, this addition does not overflow `usize`.
201179 let base = unsafe { ptr. add ( offset) } ;
202180 // SAFETY: Since `add` is not allowed to wrap around, the preceding line
203181 // produces a pointer whose address is greater than or equal to that of
@@ -216,21 +194,16 @@ pub(crate) mod ptr {
216194 // is a subset of the input byte range. Thus:
217195 // - Since, by invariant, `self.ptr` addresses a byte range
218196 // entirely contained in `A`, so does `ptr`.
219- // - Since, by invariant, `self.ptr` addresses a range of length
220- // `self.bytes_len`, which is not longer than `isize::MAX`
221- // bytes, so does `ptr`.
222- // - `ret_len` is either `split_at` or `self.bytes_len -
223- // split_at`. `validate_cast_and_convert_metadata` promises that
224- // `split_at` is in the range `[0, self.bytes_len]`. Thus, in
225- // both cases, `ret_len <= self.bytes_len <= isize::MAX`.
197+ // - Since, by invariant, `self.ptr` addresses a range whose
198+ // length is not longer than `isize::MAX` bytes, so does `ptr`.
226199 // - Since, by invariant, `self.ptr` addresses a range which does
227200 // not wrap around the address space, so does `ptr`.
228201 // - `validate_cast_and_convert_metadata` promises that the object
229202 // described by `split_at` is validly-aligned for `U`.
230203 // - By invariant on `self`, `A` is guaranteed to live for at least
231204 // `'a`.
232205 // - `U: 'a` by trait bound.
233- Some ( ( Ptr { ptr, _bytes_len : ret_len , _lifetime : PhantomData } , split_at) )
206+ Some ( ( Ptr { ptr, _lifetime : PhantomData } , split_at) )
234207 }
235208
236209 /// Attempts to cast `self` into a `U`, failing if all of the bytes of
@@ -252,12 +225,47 @@ pub(crate) mod ptr {
252225 // details.
253226 #[ allow( unstable_name_collisions) ]
254227 match self . _try_cast_into ( _CastType:: _Prefix) {
255- Some ( ( slf, split_at) ) if split_at == self . _bytes_len => Some ( slf) ,
228+ Some ( ( slf, split_at) ) if split_at == self . _len ( ) => Some ( slf) ,
256229 Some ( _) | None => None ,
257230 }
258231 }
259232 }
260233
234+ impl < ' a , T > Ptr < ' a , [ T ] > {
235+ /// The number of slice elements referenced by `self`.
236+ fn _len ( & self ) -> usize {
237+ #[ allow( clippy:: as_conversions) ]
238+ let slc = self . ptr . as_ptr ( ) as * const [ ( ) ] ;
239+ // SAFETY:
240+ // - `()` has alignment 1, so `slc` is trivially aligned.
241+ // - `slc` was derived from a non-null pointer.
242+ // - The size is 0 regardless of the length, so it is sound to
243+ // materialize a reference regardless of location.
244+ // - By invariant, `self.ptr` has valid provenance.
245+ let slc = unsafe { & * slc } ;
246+ // This is correct because the preceding `as` cast preserves the
247+ // number of slice elements. Per
248+ // https://doc.rust-lang.org/nightly/reference/expressions/operator-expr.html#slice-dst-pointer-to-pointer-cast:
249+ //
250+ // For slice types like `[T]` and `[U]`, the raw pointer types
251+ // `*const [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode
252+ // the number of elements in this slice. Casts between these raw
253+ // pointer types preserve the number of elements. Note that, as a
254+ // consequence, such casts do *not* necessarily preserve the size
255+ // of the pointer's referent (e.g., casting `*const [u16]` to
256+ // `*const [u8]` will result in a raw pointer which refers to an
257+ // object of half the size of the original). The same holds for
258+ // `str` and any compound type whose unsized tail is a slice type,
259+ // such as struct `Foo(i32, [u8])` or `(u64, Foo)`.
260+ //
261+ // TODO(#429),
262+ // TODO(https://github.com/rust-lang/reference/pull/1417): Once this
263+ // text is available on the Stable docs, cite those instead of the
264+ // Nightly docs.
265+ slc. len ( )
266+ }
267+ }
268+
261269 impl < ' a , T : ' a + ?Sized > From < & ' a T > for Ptr < ' a , T > {
262270 #[ inline( always) ]
263271 fn from ( t : & ' a T ) -> Ptr < ' a , T > {
@@ -268,8 +276,7 @@ pub(crate) mod ptr {
268276 // has the same provenance as `A`
269277 // - Since `NonNull::from` creates a pointer which addresses the
270278 // same bytes as `t`, `ptr` addresses a byte range entirely
271- // contained in (in this case, identical to) `A` of length
272- // `mem::size_of_val(t)`
279+ // contained in (in this case, identical to) `A`
273280 // - Since `t: &T`, it addresses no more than `isize::MAX` bytes [1]
274281 // - Since `t: &T`, it addresses a byte range which does not wrap
275282 // around the address space [2]
@@ -290,7 +297,7 @@ pub(crate) mod ptr {
290297 // `isize`?
291298 // - [2] Where does the reference document that allocations don't
292299 // wrap around the address space?
293- Ptr { ptr : NonNull :: from ( t) , _bytes_len : mem :: size_of_val ( t ) , _lifetime : PhantomData }
300+ Ptr { ptr : NonNull :: from ( t) , _lifetime : PhantomData }
294301 }
295302 }
296303
@@ -303,7 +310,7 @@ pub(crate) mod ptr {
303310
304311 #[ cfg( test) ]
305312 mod tests {
306- use core:: mem:: MaybeUninit ;
313+ use core:: mem:: { self , MaybeUninit } ;
307314
308315 use super :: * ;
309316 use crate :: { util:: testutil:: AU64 , FromBytes } ;
0 commit comments