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

Document requirements for unsized {Rc,Arc}::from_raw #120449

Merged
merged 6 commits into from
Feb 15, 2024
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
74 changes: 61 additions & 13 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1181,12 +1181,19 @@ impl<T: ?Sized> Rc<T> {
/// Constructs an `Rc<T>` from a raw pointer.
///
/// The raw pointer must have been previously returned by a call to
/// [`Rc<U>::into_raw`][into_raw] where `U` must have the same size
/// and alignment as `T`. This is trivially true if `U` is `T`.
/// Note that if `U` is not `T` but has the same size and alignment, this is
/// basically like transmuting references of different types. See
/// [`mem::transmute`][transmute] for more information on what
/// restrictions apply in this case.
/// [`Rc<U>::into_raw`][into_raw] with the following requirements:
///
/// * If `U` is sized, it must have the same size and alignment as `T`. This
/// is trivially true if `U` is `T`.
/// * If `U` is unsized, its data pointer must have the same size and
/// alignment as `T`. This is trivially true if `Rc<U>` was constructed
/// through `Rc<T>` and then converted to `Rc<U>` through an [unsized
/// coercion].
///
/// Note that if `U` or `U`'s data pointer is not `T` but has the same size
/// and alignment, this is basically like transmuting references of
m-ou-se marked this conversation as resolved.
Show resolved Hide resolved
/// different types. See [`mem::transmute`][transmute] for more information
/// on what restrictions apply in this case.
///
/// The raw pointer must point to a block of memory allocated by the global allocator
///
Expand All @@ -1198,6 +1205,7 @@ impl<T: ?Sized> Rc<T> {
///
/// [into_raw]: Rc::into_raw
/// [transmute]: core::mem::transmute
/// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions
///
/// # Examples
///
Expand All @@ -1217,6 +1225,20 @@ impl<T: ?Sized> Rc<T> {
///
/// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
/// ```
///
/// Convert a slice back into its original array:
///
/// ```
/// use std::rc::Rc;
///
/// let x: Rc<[u32]> = Rc::new([1, 2, 3]);
/// let x_ptr: *const [u32] = Rc::into_raw(x);
///
/// unsafe {
/// let x: Rc<[u32; 3]> = Rc::from_raw(x_ptr.cast::<[u32; 3]>());
/// assert_eq!(&*x, &[1, 2, 3]);
/// }
/// ```
#[inline]
#[stable(feature = "rc_raw", since = "1.17.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
Expand Down Expand Up @@ -1341,13 +1363,20 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {

/// Constructs an `Rc<T, A>` from a raw pointer in the provided allocator.
///
/// The raw pointer must have been previously returned by a call to
/// [`Rc<U, A>::into_raw`][into_raw] where `U` must have the same size
/// and alignment as `T`. This is trivially true if `U` is `T`.
/// Note that if `U` is not `T` but has the same size and alignment, this is
/// basically like transmuting references of different types. See
/// [`mem::transmute`] for more information on what
/// restrictions apply in this case.
/// The raw pointer must have been previously returned by a call to [`Rc<U,
/// A>::into_raw`][into_raw] with the following requirements:
///
/// * If `U` is sized, it must have the same size and alignment as `T`. This
/// is trivially true if `U` is `T`.
/// * If `U` is unsized, its data pointer must have the same size and
/// alignment as `T`. This is trivially true if `Rc<U>` was constructed
/// through `Rc<T>` and then converted to `Rc<U>` through an [unsized
/// coercion].
///
/// Note that if `U` or `U`'s data pointer is not `T` but has the same size
/// and alignment, this is basically like transmuting references of
/// different types. See [`mem::transmute`][transmute] for more information
/// on what restrictions apply in this case.
///
/// The raw pointer must point to a block of memory allocated by `alloc`
///
Expand All @@ -1358,6 +1387,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
/// even if the returned `Rc<T>` is never accessed.
///
/// [into_raw]: Rc::into_raw
/// [transmute]: core::mem::transmute
/// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions
///
/// # Examples
///
Expand All @@ -1380,6 +1411,23 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
///
/// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
/// ```
///
/// Convert a slice back into its original array:
///
/// ```
/// #![feature(allocator_api)]
///
/// use std::rc::Rc;
/// use std::alloc::System;
///
/// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System);
/// let x_ptr: *const [u32] = Rc::into_raw(x);
///
/// unsafe {
/// let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System);
/// assert_eq!(&*x, &[1, 2, 3]);
/// }
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self {
let offset = unsafe { data_offset(ptr) };
Expand Down
74 changes: 61 additions & 13 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,12 +1329,19 @@ impl<T: ?Sized> Arc<T> {
/// Constructs an `Arc<T>` from a raw pointer.
///
/// The raw pointer must have been previously returned by a call to
/// [`Arc<U>::into_raw`][into_raw] where `U` must have the same size and
/// alignment as `T`. This is trivially true if `U` is `T`.
/// Note that if `U` is not `T` but has the same size and alignment, this is
/// basically like transmuting references of different types. See
/// [`mem::transmute`][transmute] for more information on what
/// restrictions apply in this case.
/// [`Arc<U>::into_raw`][into_raw] with the following requirements:
///
/// * If `U` is sized, it must have the same size and alignment as `T`. This
/// is trivially true if `U` is `T`.
/// * If `U` is unsized, its data pointer must have the same size and
/// alignment as `T`. This is trivially true if `Arc<U>` was constructed
/// through `Arc<T>` and then converted to `Arc<U>` through an [unsized
/// coercion].
///
/// Note that if `U` or `U`'s data pointer is not `T` but has the same size
/// and alignment, this is basically like transmuting references of
/// different types. See [`mem::transmute`][transmute] for more information
/// on what restrictions apply in this case.
///
/// The user of `from_raw` has to make sure a specific value of `T` is only
/// dropped once.
Expand All @@ -1344,6 +1351,7 @@ impl<T: ?Sized> Arc<T> {
///
/// [into_raw]: Arc::into_raw
/// [transmute]: core::mem::transmute
/// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions
///
/// # Examples
///
Expand All @@ -1363,6 +1371,20 @@ impl<T: ?Sized> Arc<T> {
///
/// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
/// ```
///
/// Convert a slice back into its original array:
///
/// ```
/// use std::sync::Arc;
///
/// let x: Arc<[u32]> = Arc::new([1, 2, 3]);
/// let x_ptr: *const [u32] = Arc::into_raw(x);
///
/// unsafe {
/// let x: Arc<[u32; 3]> = Arc::from_raw(x_ptr.cast::<[u32; 3]>());
/// assert_eq!(&*x, &[1, 2, 3]);
/// }
/// ```
#[inline]
#[stable(feature = "rc_raw", since = "1.17.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
Expand Down Expand Up @@ -1492,13 +1514,20 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {

/// Constructs an `Arc<T, A>` from a raw pointer.
///
/// The raw pointer must have been previously returned by a call to
/// [`Arc<U, A>::into_raw`][into_raw] where `U` must have the same size and
/// alignment as `T`. This is trivially true if `U` is `T`.
/// Note that if `U` is not `T` but has the same size and alignment, this is
/// basically like transmuting references of different types. See
/// [`mem::transmute`] for more information on what
/// restrictions apply in this case.
/// The raw pointer must have been previously returned by a call to [`Arc<U,
/// A>::into_raw`][into_raw] with the following requirements:
///
/// * If `U` is sized, it must have the same size and alignment as `T`. This
/// is trivially true if `U` is `T`.
/// * If `U` is unsized, its data pointer must have the same size and
/// alignment as `T`. This is trivially true if `Arc<U>` was constructed
/// through `Arc<T>` and then converted to `Arc<U>` through an [unsized
/// coercion].
///
/// Note that if `U` or `U`'s data pointer is not `T` but has the same size
/// and alignment, this is basically like transmuting references of
/// different types. See [`mem::transmute`][transmute] for more information
/// on what restrictions apply in this case.
///
/// The raw pointer must point to a block of memory allocated by `alloc`
///
Expand All @@ -1509,6 +1538,8 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
/// even if the returned `Arc<T>` is never accessed.
///
/// [into_raw]: Arc::into_raw
/// [transmute]: core::mem::transmute
/// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions
///
/// # Examples
///
Expand All @@ -1531,6 +1562,23 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
///
/// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
/// ```
///
/// Convert a slice back into its original array:
///
/// ```
/// #![feature(allocator_api)]
///
/// use std::sync::Arc;
/// use std::alloc::System;
///
/// let x: Arc<[u32], _> = Arc::new_in([1, 2, 3], System);
/// let x_ptr: *const [u32] = Arc::into_raw(x);
///
/// unsafe {
/// let x: Arc<[u32; 3], _> = Arc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System);
/// assert_eq!(&*x, &[1, 2, 3]);
/// }
/// ```
#[inline]
#[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self {
Expand Down
Loading