@@ -15,7 +15,6 @@ pub(crate) mod ptr {
15
15
use core:: {
16
16
fmt:: { Debug , Formatter } ,
17
17
marker:: PhantomData ,
18
- mem,
19
18
ptr:: NonNull ,
20
19
} ;
21
20
@@ -42,31 +41,14 @@ pub(crate) mod ptr {
42
41
// INVARIANTS:
43
42
// - `ptr` is derived from some valid Rust allocation, `A`
44
43
// - `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`
48
46
// - `ptr` addresses a byte range which does not wrap around the address
49
47
// space
50
48
// - `ptr` is validly-aligned for `T`
51
49
// - `A` is guaranteed to live for at least `'a`
52
50
// - `T: 'a`
53
51
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 ,
70
52
_lifetime : PhantomData < & ' a ( ) > ,
71
53
}
72
54
@@ -170,34 +152,30 @@ pub(crate) mod ptr {
170
152
// panic.
171
153
let ( elems, split_at) = U :: LAYOUT . _validate_cast_and_convert_metadata (
172
154
AsAddress :: addr ( self . ptr . as_ptr ( ) ) ,
173
- self . _bytes_len ,
155
+ self . _len ( ) ,
174
156
cast_type,
175
157
) ?;
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,
183
161
} ;
184
162
185
163
let ptr = self . ptr . cast :: < u8 > ( ) . as_ptr ( ) ;
186
164
// SAFETY: `offset` is either `0` or `split_at`.
187
165
// `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:
190
168
// - The resulting pointer is in or one byte past the end of the
191
169
// same byte range as `self.ptr`. Since, by invariant, `self.ptr`
192
170
// addresses a byte range entirely contained within a single
193
171
// allocation, the pointer resulting from this operation is within
194
172
// 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`.
197
175
// - By invariant, `self.ptr` addresses a byte range which does not
198
176
// 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`.
201
179
let base = unsafe { ptr. add ( offset) } ;
202
180
// SAFETY: Since `add` is not allowed to wrap around, the preceding line
203
181
// produces a pointer whose address is greater than or equal to that of
@@ -216,21 +194,16 @@ pub(crate) mod ptr {
216
194
// is a subset of the input byte range. Thus:
217
195
// - Since, by invariant, `self.ptr` addresses a byte range
218
196
// 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`.
226
199
// - Since, by invariant, `self.ptr` addresses a range which does
227
200
// not wrap around the address space, so does `ptr`.
228
201
// - `validate_cast_and_convert_metadata` promises that the object
229
202
// described by `split_at` is validly-aligned for `U`.
230
203
// - By invariant on `self`, `A` is guaranteed to live for at least
231
204
// `'a`.
232
205
// - `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) )
234
207
}
235
208
236
209
/// Attempts to cast `self` into a `U`, failing if all of the bytes of
@@ -252,12 +225,47 @@ pub(crate) mod ptr {
252
225
// details.
253
226
#[ allow( unstable_name_collisions) ]
254
227
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) ,
256
229
Some ( _) | None => None ,
257
230
}
258
231
}
259
232
}
260
233
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
+ // - Pointer provenance may be an issue, but we never dereference.
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
+
261
269
impl < ' a , T : ' a + ?Sized > From < & ' a T > for Ptr < ' a , T > {
262
270
#[ inline( always) ]
263
271
fn from ( t : & ' a T ) -> Ptr < ' a , T > {
@@ -268,8 +276,7 @@ pub(crate) mod ptr {
268
276
// has the same provenance as `A`
269
277
// - Since `NonNull::from` creates a pointer which addresses the
270
278
// 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`
273
280
// - Since `t: &T`, it addresses no more than `isize::MAX` bytes [1]
274
281
// - Since `t: &T`, it addresses a byte range which does not wrap
275
282
// around the address space [2]
@@ -290,7 +297,7 @@ pub(crate) mod ptr {
290
297
// `isize`?
291
298
// - [2] Where does the reference document that allocations don't
292
299
// 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 }
294
301
}
295
302
}
296
303
@@ -303,7 +310,7 @@ pub(crate) mod ptr {
303
310
304
311
#[ cfg( test) ]
305
312
mod tests {
306
- use core:: mem:: MaybeUninit ;
313
+ use core:: mem:: { self , MaybeUninit } ;
307
314
308
315
use super :: * ;
309
316
use crate :: { util:: testutil:: AU64 , FromBytes } ;
0 commit comments