Rollup merge of #120449 - udoprog:document-unsized-rc-arc-from-raw, r=m-ou-se
Document requirements for unsized {Rc,Arc}::from_raw This seems to be implied due to these types supporting operation-less unsized coercions. Taken together with the [established behavior of a wide to thin pointer cast](https://github.com/rust-lang/reference/pull/1451) it would enable unsafe downcasting of these containers. Note that the term "data pointer" is adopted from https://github.com/rust-lang/rfcs/pull/3559 See also this [internals thread](https://internals.rust-lang.org/t/can-unsafe-smart-pointer-downcasts-be-correct/20229/2).
This commit is contained in:
commit
9fdab38877
2 changed files with 122 additions and 26 deletions
|
@ -1184,12 +1184,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
|
||||
/// 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
|
||||
///
|
||||
|
@ -1201,6 +1208,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
|
||||
///
|
||||
|
@ -1220,6 +1228,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 {
|
||||
|
@ -1344,13 +1366,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`
|
||||
///
|
||||
|
@ -1361,6 +1390,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
|
||||
///
|
||||
|
@ -1383,6 +1414,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) };
|
||||
|
|
|
@ -1333,12 +1333,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.
|
||||
|
@ -1348,6 +1355,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
|
||||
///
|
||||
|
@ -1367,6 +1375,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 {
|
||||
|
@ -1496,13 +1518,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`
|
||||
///
|
||||
|
@ -1513,6 +1542,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
|
||||
///
|
||||
|
@ -1535,6 +1566,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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue