From dd973d1b1235813c5e38a092272f2231800b1e53 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 11 Feb 2020 14:10:49 -0500 Subject: [PATCH] Allow calculating the layout behind a pointer Let align/size_of_of_val intrinsics work on ptrs --- src/libcore/alloc.rs | 36 ++++++++++ src/libcore/intrinsics.rs | 11 +++ src/libcore/mem/mod.rs | 92 ++++++++++++++++++++++++++ src/librustc_typeck/check/intrinsic.rs | 11 +-- 4 files changed, 142 insertions(+), 8 deletions(-) diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 0a7a8ab266a..a86f53af509 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -140,6 +140,42 @@ pub fn for_value(t: &T) -> Self { unsafe { Layout::from_size_align_unchecked(size, align) } } + /// Produces layout describing a record that could be used to + /// allocate backing structure for `T` (which could be a trait + /// or other unsized type like a slice). + /// + /// # Safety + /// + /// This function is only safe to call if the following conditions hold: + /// + /// - If `T` is `Sized`, this function is always safe to call. + /// - If the unsized tail of `T` is: + /// - a [slice], then the length of the slice tail must be an intialized + /// integer, and the size of the *entire value* + /// (dynamic tail length + statically sized prefix) must fit in `isize`. + /// - a [trait object], then the vtable part of the pointer must point + /// to a valid vtable acquired by an unsizing coersion, and the size + /// of the *entire value* (dynamic tail length + statically sized prefix) + /// must fit in `isize`. + /// - an (unstable) [extern type], then this function is always safe to + /// call, but may panic or otherwise return the wrong value, as the + /// extern type's layout is not known. This is the same behavior as + /// [`Layout::for_value`] on a reference to an extern type tail. + /// - otherwise, it is conservatively not allowed to call this function. + /// + /// [slice]: ../../std/primitive.slice.html + /// [trait object]: ../../book/ch17-02-trait-objects.html + /// [extern type]: ../../unstable-book/language-features/extern-types.html + #[inline] + #[cfg(not(bootstrap))] + #[unstable(feature = "layout_for_ptr", issue = "69835")] + pub unsafe fn for_value_raw(t: *const T) -> Self { + let (size, align) = (mem::size_of_val_raw(t), mem::align_of_val_raw(t)); + // See rationale in `new` for why this is using an unsafe variant below + debug_assert!(Layout::from_size_align(size, align).is_ok()); + Layout::from_size_align_unchecked(size, align) + } + /// Creates a `NonNull` that is dangling, but well-aligned for this Layout. /// /// Note that the pointer value may potentially represent a valid pointer, diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a889eff75c0..56bace02691 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -980,13 +980,24 @@ /// /// The stabilized version of this intrinsic is /// [`std::mem::size_of_val`](../../std/mem/fn.size_of_val.html). + #[cfg(bootstrap)] pub fn size_of_val(_: &T) -> usize; /// The minimum alignment of the type of the value that `val` points to. /// /// The stabilized version of this intrinsic is /// [`std::mem::min_align_of_val`](../../std/mem/fn.min_align_of_val.html). + #[cfg(bootstrap)] pub fn min_align_of_val(_: &T) -> usize; + /// The size of the referenced value in bytes. + /// + /// The stabilized version of this intrinsic is + /// [`std::mem::size_of_val`](../../std/mem/fn.size_of_val.html). + #[cfg(not(bootstrap))] + pub fn size_of_val(_: *const T) -> usize; + #[cfg(not(bootstrap))] + pub fn min_align_of_val(_: *const T) -> usize; + /// Gets a static string slice containing the name of a type. /// /// The stabilized version of this intrinsic is diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 90144d11dc9..6fad9f43d22 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -303,6 +303,54 @@ pub fn size_of_val(val: &T) -> usize { intrinsics::size_of_val(val) } +/// Returns the size of the pointed-to value in bytes. +/// +/// This is usually the same as `size_of::()`. However, when `T` *has* no +/// statically-known size, e.g., a slice [`[T]`][slice] or a [trait object], +/// then `size_of_val_raw` can be used to get the dynamically-known size. +/// +/// # Safety +/// +/// This function is only safe to call if the following conditions hold: +/// +/// - If `T` is `Sized`, this function is always safe to call. +/// - If the unsized tail of `T` is: +/// - a [slice], then the length of the slice tail must be an intialized +/// integer, and the size of the *entire value* +/// (dynamic tail length + statically sized prefix) must fit in `isize`. +/// - a [trait object], then the vtable part of the pointer must point +/// to a valid vtable acquired by an unsizing coersion, and the size +/// of the *entire value* (dynamic tail length + statically sized prefix) +/// must fit in `isize`. +/// - an (unstable) [extern type], then this function is always safe to +/// call, but may panic or otherwise return the wrong value, as the +/// extern type's layout is not known. This is the same behavior as +/// [`size_of_val`] on a reference to an extern type tail. +/// - otherwise, it is conservatively not allowed to call this function. +/// +/// [slice]: ../../std/primitive.slice.html +/// [trait object]: ../../book/ch17-02-trait-objects.html +/// [extern type]: ../../unstable-book/language-features/extern-types.html +/// +/// # Examples +/// +/// ``` +/// #![feature(layout_for_ptr)] +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of_val(&5i32)); +/// +/// let x: [u8; 13] = [0; 13]; +/// let y: &[u8] = &x; +/// assert_eq!(13, unsafe { mem::size_of_val_raw(y) }); +/// ``` +#[inline] +#[cfg(not(bootstrap))] +#[unstable(feature = "layout_for_ptr", issue = "69835")] +pub unsafe fn size_of_val_raw(val: *const T) -> usize { + intrinsics::size_of_val(val) +} + /// Returns the [ABI]-required minimum alignment of a type. /// /// 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(val: &T) -> usize { min_align_of_val(val) } +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Safety +/// +/// This function is only safe to call if the following conditions hold: +/// +/// - If `T` is `Sized`, this function is always safe to call. +/// - If the unsized tail of `T` is: +/// - a [slice], then the length of the slice tail must be an intialized +/// integer, and the size of the *entire value* +/// (dynamic tail length + statically sized prefix) must fit in `isize`. +/// - a [trait object], then the vtable part of the pointer must point +/// to a valid vtable acquired by an unsizing coersion, and the size +/// of the *entire value* (dynamic tail length + statically sized prefix) +/// must fit in `isize`. +/// - an (unstable) [extern type], then this function is always safe to +/// call, but may panic or otherwise return the wrong value, as the +/// extern type's layout is not known. This is the same behavior as +/// [`align_of_val`] on a reference to an extern type tail. +/// - otherwise, it is conservatively not allowed to call this function. +/// +/// [slice]: ../../std/primitive.slice.html +/// [trait object]: ../../book/ch17-02-trait-objects.html +/// [extern type]: ../../unstable-book/language-features/extern-types.html +/// +/// # Examples +/// +/// ``` +/// #![feature(layout_for_ptr)] +/// use std::mem; +/// +/// assert_eq!(4, unsafe { mem::align_of_val_raw(&5i32) }); +/// ``` +#[inline] +#[cfg(not(bootstrap))] +#[unstable(feature = "layout_for_ptr", issue = "69835")] +pub unsafe fn align_of_val_raw(val: *const T) -> usize { + intrinsics::min_align_of_val(val) +} + /// Returns `true` if dropping values of type `T` matters. /// /// This is purely an optimization hint, and may be implemented conservatively: diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3572eda5c13..da263cec53f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -137,14 +137,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let (n_tps, inputs, output) = match &name[..] { "breakpoint" => (0, Vec::new(), tcx.mk_unit()), "size_of" | "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize), - "size_of_val" | "min_align_of_val" => ( - 1, - vec![tcx.mk_imm_ref( - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))), - param(0), - )], - tcx.types.usize, - ), + "size_of_val" | "min_align_of_val" => { + (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize) + } "rustc_peek" => (1, vec![param(0)], param(0)), "caller_location" => (0, vec![], tcx.caller_location_ty()), "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),