Skip to content

Commit dd973d1

Browse files
committed
Allow calculating the layout behind a pointer
Let align/size_of_of_val intrinsics work on ptrs
1 parent 564758c commit dd973d1

File tree

4 files changed

+142
-8
lines changed

4 files changed

+142
-8
lines changed

src/libcore/alloc.rs

+36
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,42 @@ impl Layout {
140140
unsafe { Layout::from_size_align_unchecked(size, align) }
141141
}
142142

143+
/// Produces layout describing a record that could be used to
144+
/// allocate backing structure for `T` (which could be a trait
145+
/// or other unsized type like a slice).
146+
///
147+
/// # Safety
148+
///
149+
/// This function is only safe to call if the following conditions hold:
150+
///
151+
/// - If `T` is `Sized`, this function is always safe to call.
152+
/// - If the unsized tail of `T` is:
153+
/// - a [slice], then the length of the slice tail must be an intialized
154+
/// integer, and the size of the *entire value*
155+
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
156+
/// - a [trait object], then the vtable part of the pointer must point
157+
/// to a valid vtable acquired by an unsizing coersion, and the size
158+
/// of the *entire value* (dynamic tail length + statically sized prefix)
159+
/// must fit in `isize`.
160+
/// - an (unstable) [extern type], then this function is always safe to
161+
/// call, but may panic or otherwise return the wrong value, as the
162+
/// extern type's layout is not known. This is the same behavior as
163+
/// [`Layout::for_value`] on a reference to an extern type tail.
164+
/// - otherwise, it is conservatively not allowed to call this function.
165+
///
166+
/// [slice]: ../../std/primitive.slice.html
167+
/// [trait object]: ../../book/ch17-02-trait-objects.html
168+
/// [extern type]: ../../unstable-book/language-features/extern-types.html
169+
#[inline]
170+
#[cfg(not(bootstrap))]
171+
#[unstable(feature = "layout_for_ptr", issue = "69835")]
172+
pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
173+
let (size, align) = (mem::size_of_val_raw(t), mem::align_of_val_raw(t));
174+
// See rationale in `new` for why this is using an unsafe variant below
175+
debug_assert!(Layout::from_size_align(size, align).is_ok());
176+
Layout::from_size_align_unchecked(size, align)
177+
}
178+
143179
/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
144180
///
145181
/// Note that the pointer value may potentially represent a valid pointer,

src/libcore/intrinsics.rs

+11
Original file line numberDiff line numberDiff line change
@@ -980,13 +980,24 @@ extern "rust-intrinsic" {
980980
///
981981
/// The stabilized version of this intrinsic is
982982
/// [`std::mem::size_of_val`](../../std/mem/fn.size_of_val.html).
983+
#[cfg(bootstrap)]
983984
pub fn size_of_val<T: ?Sized>(_: &T) -> usize;
984985
/// The minimum alignment of the type of the value that `val` points to.
985986
///
986987
/// The stabilized version of this intrinsic is
987988
/// [`std::mem::min_align_of_val`](../../std/mem/fn.min_align_of_val.html).
989+
#[cfg(bootstrap)]
988990
pub fn min_align_of_val<T: ?Sized>(_: &T) -> usize;
989991

992+
/// The size of the referenced value in bytes.
993+
///
994+
/// The stabilized version of this intrinsic is
995+
/// [`std::mem::size_of_val`](../../std/mem/fn.size_of_val.html).
996+
#[cfg(not(bootstrap))]
997+
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
998+
#[cfg(not(bootstrap))]
999+
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
1000+
9901001
/// Gets a static string slice containing the name of a type.
9911002
///
9921003
/// The stabilized version of this intrinsic is

src/libcore/mem/mod.rs

+92
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,54 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
303303
intrinsics::size_of_val(val)
304304
}
305305

306+
/// Returns the size of the pointed-to value in bytes.
307+
///
308+
/// This is usually the same as `size_of::<T>()`. However, when `T` *has* no
309+
/// statically-known size, e.g., a slice [`[T]`][slice] or a [trait object],
310+
/// then `size_of_val_raw` can be used to get the dynamically-known size.
311+
///
312+
/// # Safety
313+
///
314+
/// This function is only safe to call if the following conditions hold:
315+
///
316+
/// - If `T` is `Sized`, this function is always safe to call.
317+
/// - If the unsized tail of `T` is:
318+
/// - a [slice], then the length of the slice tail must be an intialized
319+
/// integer, and the size of the *entire value*
320+
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
321+
/// - a [trait object], then the vtable part of the pointer must point
322+
/// to a valid vtable acquired by an unsizing coersion, and the size
323+
/// of the *entire value* (dynamic tail length + statically sized prefix)
324+
/// must fit in `isize`.
325+
/// - an (unstable) [extern type], then this function is always safe to
326+
/// call, but may panic or otherwise return the wrong value, as the
327+
/// extern type's layout is not known. This is the same behavior as
328+
/// [`size_of_val`] on a reference to an extern type tail.
329+
/// - otherwise, it is conservatively not allowed to call this function.
330+
///
331+
/// [slice]: ../../std/primitive.slice.html
332+
/// [trait object]: ../../book/ch17-02-trait-objects.html
333+
/// [extern type]: ../../unstable-book/language-features/extern-types.html
334+
///
335+
/// # Examples
336+
///
337+
/// ```
338+
/// #![feature(layout_for_ptr)]
339+
/// use std::mem;
340+
///
341+
/// assert_eq!(4, mem::size_of_val(&5i32));
342+
///
343+
/// let x: [u8; 13] = [0; 13];
344+
/// let y: &[u8] = &x;
345+
/// assert_eq!(13, unsafe { mem::size_of_val_raw(y) });
346+
/// ```
347+
#[inline]
348+
#[cfg(not(bootstrap))]
349+
#[unstable(feature = "layout_for_ptr", issue = "69835")]
350+
pub unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
351+
intrinsics::size_of_val(val)
352+
}
353+
306354
/// Returns the [ABI]-required minimum alignment of a type.
307355
///
308356
/// Every reference to a value of the type `T` must be a multiple of this number.
@@ -390,6 +438,50 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
390438
min_align_of_val(val)
391439
}
392440

441+
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
442+
///
443+
/// Every reference to a value of the type `T` must be a multiple of this number.
444+
///
445+
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
446+
///
447+
/// # Safety
448+
///
449+
/// This function is only safe to call if the following conditions hold:
450+
///
451+
/// - If `T` is `Sized`, this function is always safe to call.
452+
/// - If the unsized tail of `T` is:
453+
/// - a [slice], then the length of the slice tail must be an intialized
454+
/// integer, and the size of the *entire value*
455+
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
456+
/// - a [trait object], then the vtable part of the pointer must point
457+
/// to a valid vtable acquired by an unsizing coersion, and the size
458+
/// of the *entire value* (dynamic tail length + statically sized prefix)
459+
/// must fit in `isize`.
460+
/// - an (unstable) [extern type], then this function is always safe to
461+
/// call, but may panic or otherwise return the wrong value, as the
462+
/// extern type's layout is not known. This is the same behavior as
463+
/// [`align_of_val`] on a reference to an extern type tail.
464+
/// - otherwise, it is conservatively not allowed to call this function.
465+
///
466+
/// [slice]: ../../std/primitive.slice.html
467+
/// [trait object]: ../../book/ch17-02-trait-objects.html
468+
/// [extern type]: ../../unstable-book/language-features/extern-types.html
469+
///
470+
/// # Examples
471+
///
472+
/// ```
473+
/// #![feature(layout_for_ptr)]
474+
/// use std::mem;
475+
///
476+
/// assert_eq!(4, unsafe { mem::align_of_val_raw(&5i32) });
477+
/// ```
478+
#[inline]
479+
#[cfg(not(bootstrap))]
480+
#[unstable(feature = "layout_for_ptr", issue = "69835")]
481+
pub unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
482+
intrinsics::min_align_of_val(val)
483+
}
484+
393485
/// Returns `true` if dropping values of type `T` matters.
394486
///
395487
/// This is purely an optimization hint, and may be implemented conservatively:

src/librustc_typeck/check/intrinsic.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
137137
let (n_tps, inputs, output) = match &name[..] {
138138
"breakpoint" => (0, Vec::new(), tcx.mk_unit()),
139139
"size_of" | "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
140-
"size_of_val" | "min_align_of_val" => (
141-
1,
142-
vec![tcx.mk_imm_ref(
143-
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))),
144-
param(0),
145-
)],
146-
tcx.types.usize,
147-
),
140+
"size_of_val" | "min_align_of_val" => {
141+
(1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize)
142+
}
148143
"rustc_peek" => (1, vec![param(0)], param(0)),
149144
"caller_location" => (0, vec![], tcx.caller_location_ty()),
150145
"panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),

0 commit comments

Comments
 (0)