diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2024-02-15 14:32:59 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-15 14:32:59 +0100 |
| commit | 9fdab38877a510ec1c64915ccb4455356ee8e67b (patch) | |
| tree | 54e0487cf6d8b500f9348ca0929e430601047951 /library/alloc/src | |
| parent | 6a4222b5119bce8c24e74dd3ad44006ce0c803e6 (diff) | |
| parent | bdbbf04a03311a79a193196f7ac64e5fd164af44 (diff) | |
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).
Diffstat (limited to 'library/alloc/src')
| -rw-r--r-- | library/alloc/src/rc.rs | 74 | ||||
| -rw-r--r-- | library/alloc/src/sync.rs | 74 |
2 files changed, 122 insertions, 26 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0338565980c..2cc38d90ffe 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -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) }; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index e16574f3d80..e1211da4c61 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -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 { |
