about summary refs log tree commit diff
path: root/library/alloc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-12 00:34:22 +0000
committerbors <bors@rust-lang.org>2024-02-12 00:34:22 +0000
commit084ce5bdb5f7dc1c725f6770a8de281165ba3b0a (patch)
tree19b02783a13bce0a281f7d29274a102afde2c629 /library/alloc
parent520b0b20aa8c218f84cefc6260f52406b84fa55f (diff)
parent9bd630af97e609cd9579703777a2d8d67f8fc2da (diff)
Auto merge of #120951 - matthiaskrgr:rollup-0nnm7dv, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #110483 (Create try_new function for ThinBox)
 - #120740 (Make cmath.rs a single file)
 - #120872 (hir: Refactor getters for HIR parents)
 - #120880 (add note on comparing vtables / function pointers)
 - #120885 (interpret/visitor: ensure we only see normalized types)
 - #120888 (assert_unsafe_precondition cleanup)
 - #120897 (Encode `coroutine_for_closure` for foreign crates)
 - #120937 ([docs] Update armv6k-nintendo-3ds platform docs for outdated info)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'library/alloc')
-rw-r--r--library/alloc/src/boxed/thin.rs64
1 files changed, 64 insertions, 0 deletions
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index f83c8f83cc9..3b29c144a89 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -67,6 +67,26 @@ impl<T> ThinBox<T> {
         let ptr = WithOpaqueHeader::new(meta, value);
         ThinBox { ptr, _marker: PhantomData }
     }
+
+    /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
+    /// the stack. Returns an error if allocation fails, instead of aborting.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    /// #![feature(thin_box)]
+    /// use std::boxed::ThinBox;
+    ///
+    /// let five = ThinBox::try_new(5)?;
+    /// # Ok::<(), std::alloc::AllocError>(())
+    /// ```
+    ///
+    /// [`Metadata`]: core::ptr::Pointee::Metadata
+    pub fn try_new(value: T) -> Result<Self, core::alloc::AllocError> {
+        let meta = ptr::metadata(&value);
+        WithOpaqueHeader::try_new(meta, value).map(|ptr| ThinBox { ptr, _marker: PhantomData })
+    }
 }
 
 #[unstable(feature = "thin_box", issue = "92791")]
@@ -179,6 +199,10 @@ impl WithOpaqueHeader {
         let ptr = WithHeader::new(header, value);
         Self(ptr.0)
     }
+
+    fn try_new<H, T>(header: H, value: T) -> Result<Self, core::alloc::AllocError> {
+        WithHeader::try_new(header, value).map(|ptr| Self(ptr.0))
+    }
 }
 
 impl<H> WithHeader<H> {
@@ -224,6 +248,46 @@ impl<H> WithHeader<H> {
         }
     }
 
+    /// Non-panicking version of `new`.
+    /// Any error is returned as `Err(core::alloc::AllocError)`.
+    fn try_new<T>(header: H, value: T) -> Result<WithHeader<H>, core::alloc::AllocError> {
+        let value_layout = Layout::new::<T>();
+        let Ok((layout, value_offset)) = Self::alloc_layout(value_layout) else {
+            return Err(core::alloc::AllocError);
+        };
+
+        unsafe {
+            // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
+            // we use `layout.dangling()` for this case, which should have a valid
+            // alignment for both `T` and `H`.
+            let ptr = if layout.size() == 0 {
+                // Some paranoia checking, mostly so that the ThinBox tests are
+                // more able to catch issues.
+                debug_assert!(
+                    value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
+                );
+                layout.dangling()
+            } else {
+                let ptr = alloc::alloc(layout);
+                if ptr.is_null() {
+                    return Err(core::alloc::AllocError);
+                }
+
+                // Safety:
+                // - The size is at least `aligned_header_size`.
+                let ptr = ptr.add(value_offset) as *mut _;
+
+                NonNull::new_unchecked(ptr)
+            };
+
+            let result = WithHeader(ptr, PhantomData);
+            ptr::write(result.header(), header);
+            ptr::write(result.value().cast(), value);
+
+            Ok(result)
+        }
+    }
+
     // Safety:
     // - Assumes that either `value` can be dereferenced, or is the
     //   `NonNull::dangling()` we use when both `T` and `H` are ZSTs.