about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-03-22 18:37:19 +0000
committerbors <bors@rust-lang.org>2020-03-22 18:37:19 +0000
commitd1e81ef234ff5c2e0e3a69cb4e8e5f5b0fe1fd83 (patch)
treeca5c3aa589727e4c1845fa6865015841f1d62db9 /src/libcore
parent1902d1e0de179498d0cb7fd4856d1e0ffcd52095 (diff)
parentdd973d1b1235813c5e38a092272f2231800b1e53 (diff)
downloadrust-d1e81ef234ff5c2e0e3a69cb4e8e5f5b0fe1fd83.tar.gz
rust-d1e81ef234ff5c2e0e3a69cb4e8e5f5b0fe1fd83.zip
Auto merge of #69079 - CAD97:layout-of-ptr, r=RalfJung
Allow calculating the layout behind a pointer

There was some discussion around allowing this previously.

This does make the requirement for raw pointers to have valid metadata exposed as part of the std API (as a safety invariant, not validity invariant), though I think this is not strictly necessarily required as of current. cc @rust-lang/wg-unsafe-code-guidelines

Naming is hard; I picked the best "obvious" name I could come up with.

If it's agreed that this is actually a desired API surface, I'll file a tracking issue and update the attributes.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/alloc.rs36
-rw-r--r--src/libcore/intrinsics.rs11
-rw-r--r--src/libcore/mem/mod.rs92
3 files changed, 139 insertions, 0 deletions
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index d2a513451cc..be20a1cde36 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -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.
+    ///
+    /// [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,
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index f7ecbd80cbc..eb71497cc47 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -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
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index dac9ee6a5d9..07f7d28bb75 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -336,6 +336,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
+///       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<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.
@@ -423,6 +471,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
+///       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<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: