Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow calculating the layout behind a pointer #69079

Merged
merged 1 commit into from
Mar 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/libcore/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,42 @@ impl Layout {
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.
CAD97 marked this conversation as resolved.
Show resolved Hide resolved
///
/// [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: ?Sized>(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,
Expand Down
11 changes: 11 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -980,13 +980,24 @@ extern "rust-intrinsic" {
///
/// 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: ?Sized>(_: &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: ?Sized>(_: &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<T: ?Sized>(_: *const T) -> usize;
#[cfg(not(bootstrap))]
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;

/// Gets a static string slice containing the name of a type.
///
/// The stabilized version of this intrinsic is
Expand Down
92 changes: 92 additions & 0 deletions src/libcore/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,54 @@ pub fn size_of_val<T: ?Sized>(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::<T>()`. 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
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
/// 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
///
/// ```
CAD97 marked this conversation as resolved.
Show resolved Hide resolved
/// #![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<T: ?Sized>(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.
Expand Down Expand Up @@ -390,6 +438,50 @@ pub fn align_of_val<T: ?Sized>(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
CAD97 marked this conversation as resolved.
Show resolved Hide resolved
/// 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
///
/// ```
CAD97 marked this conversation as resolved.
Show resolved Hide resolved
/// #![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<T: ?Sized>(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:
Expand Down
11 changes: 3 additions & 8 deletions src/librustc_typeck/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
Expand Down