Rollup merge of #73845 - CAD97:weak-as-unsized-ptr, r=RalfJung
Use &raw in A|Rc::as_ptr This PR uses `&raw` for offsetting `*mut [A]RcInner<T> -> *mut T`. Additionally, this updates the implementation of `Weak::as_ptr` to support unsized `T`, though it does not yet relax the bounds of `Weak::as_ptr`/`into_raw`/`from_raw` to accept unsized `T`.
This commit is contained in:
commit
9a659c54e5
@ -100,6 +100,7 @@
|
||||
#![feature(fundamental)]
|
||||
#![feature(internal_uninit_const)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(layout_for_ptr)]
|
||||
#![feature(libc)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(new_uninit)]
|
||||
@ -109,6 +110,7 @@
|
||||
#![feature(pattern)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(ptr_offset_from)]
|
||||
#![feature(raw_ref_op)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(receiver_trait)]
|
||||
#![feature(min_specialization)]
|
||||
|
@ -245,7 +245,7 @@ use core::hash::{Hash, Hasher};
|
||||
use core::intrinsics::abort;
|
||||
use core::iter;
|
||||
use core::marker::{self, PhantomData, Unpin, Unsize};
|
||||
use core::mem::{self, align_of, align_of_val, forget, size_of_val};
|
||||
use core::mem::{self, align_of_val_raw, forget, size_of_val};
|
||||
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
|
||||
use core::pin::Pin;
|
||||
use core::ptr::{self, NonNull};
|
||||
@ -591,17 +591,11 @@ impl<T: ?Sized> Rc<T> {
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn as_ptr(this: &Self) -> *const T {
|
||||
let ptr: *mut RcBox<T> = NonNull::as_ptr(this.ptr);
|
||||
let fake_ptr = ptr as *mut T;
|
||||
|
||||
// SAFETY: This cannot go through Deref::deref.
|
||||
// Instead, we manually offset the pointer rather than manifesting a reference.
|
||||
// This is so that the returned pointer retains the same provenance as our pointer.
|
||||
// This is required so that e.g. `get_mut` can write through the pointer
|
||||
// after the Rc is recovered through `from_raw`.
|
||||
unsafe {
|
||||
let offset = data_offset(&(*ptr).value);
|
||||
set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset))
|
||||
}
|
||||
// SAFETY: This cannot go through Deref::deref or Rc::inner because
|
||||
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
|
||||
// write through the pointer after the Rc is recovered through `from_raw`.
|
||||
unsafe { &raw const (*ptr).value }
|
||||
}
|
||||
|
||||
/// Constructs an `Rc<T>` from a raw pointer.
|
||||
@ -1647,6 +1641,7 @@ pub struct Weak<T: ?Sized> {
|
||||
// `Weak::new` sets this to `usize::MAX` so that it doesn’t need
|
||||
// to allocate space on the heap. That's not a value a real pointer
|
||||
// will ever have because RcBox has alignment at least 2.
|
||||
// This is only possible when `T: Sized`; unsized `T` never dangle.
|
||||
ptr: NonNull<RcBox<T>>,
|
||||
}
|
||||
|
||||
@ -1708,9 +1703,18 @@ impl<T> Weak<T> {
|
||||
/// [`null`]: ../../std/ptr/fn.null.html
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
let offset = data_offset_sized::<T>();
|
||||
let ptr = self.ptr.cast::<u8>().as_ptr().wrapping_offset(offset);
|
||||
ptr as *const T
|
||||
let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
|
||||
|
||||
// SAFETY: we must offset the pointer manually, and said pointer may be
|
||||
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
|
||||
// because we know that a pointer to unsized T was derived from a real
|
||||
// unsized T, as dangling weaks are only created for sized T. wrapping_offset
|
||||
// is used so that we can use the same code path for the non-dangling
|
||||
// unsized case and the potentially dangling sized case.
|
||||
unsafe {
|
||||
let offset = data_offset(ptr as *mut T);
|
||||
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the `Weak<T>` and turns it into a raw pointer.
|
||||
@ -2113,19 +2117,22 @@ impl<T: ?Sized> AsRef<T> for Rc<T> {
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
impl<T: ?Sized> Unpin for Rc<T> {}
|
||||
|
||||
/// Get the offset within an `ArcInner` for
|
||||
/// a payload of type described by a pointer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This has the same safety requirements as `align_of_val_raw`. In effect:
|
||||
///
|
||||
/// - This function is safe for any argument if `T` is sized, and
|
||||
/// - if `T` is unsized, the pointer must have appropriate pointer metadata
|
||||
/// aquired from the real instance that you are getting this offset for.
|
||||
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
|
||||
// Align the unsized value to the end of the `RcBox`.
|
||||
// Because it is ?Sized, it will always be the last field in memory.
|
||||
// Note: This is a detail of the current implementation of the compiler,
|
||||
// and is not a guaranteed language detail. Do not rely on it outside of std.
|
||||
unsafe { data_offset_align(align_of_val(&*ptr)) }
|
||||
}
|
||||
|
||||
/// Computes the offset of the data field within `RcBox`.
|
||||
///
|
||||
/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`.
|
||||
fn data_offset_sized<T>() -> isize {
|
||||
data_offset_align(align_of::<T>())
|
||||
unsafe { data_offset_align(align_of_val_raw(ptr)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -16,7 +16,7 @@ use core::hash::{Hash, Hasher};
|
||||
use core::intrinsics::abort;
|
||||
use core::iter;
|
||||
use core::marker::{PhantomData, Unpin, Unsize};
|
||||
use core::mem::{self, align_of, align_of_val, size_of_val};
|
||||
use core::mem::{self, align_of_val, size_of_val};
|
||||
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
|
||||
use core::pin::Pin;
|
||||
use core::ptr::{self, NonNull};
|
||||
@ -267,6 +267,7 @@ pub struct Weak<T: ?Sized> {
|
||||
// `Weak::new` sets this to `usize::MAX` so that it doesn’t need
|
||||
// to allocate space on the heap. That's not a value a real pointer
|
||||
// will ever have because RcBox has alignment at least 2.
|
||||
// This is only possible when `T: Sized`; unsized `T` never dangle.
|
||||
ptr: NonNull<ArcInner<T>>,
|
||||
}
|
||||
|
||||
@ -590,17 +591,11 @@ impl<T: ?Sized> Arc<T> {
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn as_ptr(this: &Self) -> *const T {
|
||||
let ptr: *mut ArcInner<T> = NonNull::as_ptr(this.ptr);
|
||||
let fake_ptr = ptr as *mut T;
|
||||
|
||||
// SAFETY: This cannot go through Deref::deref.
|
||||
// Instead, we manually offset the pointer rather than manifesting a reference.
|
||||
// This is so that the returned pointer retains the same provenance as our pointer.
|
||||
// This is required so that e.g. `get_mut` can write through the pointer
|
||||
// after the Arc is recovered through `from_raw`.
|
||||
unsafe {
|
||||
let offset = data_offset(&(*ptr).data);
|
||||
set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset))
|
||||
}
|
||||
// SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because
|
||||
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
|
||||
// write through the pointer after the Rc is recovered through `from_raw`.
|
||||
unsafe { &raw const (*ptr).data }
|
||||
}
|
||||
|
||||
/// Constructs an `Arc<T>` from a raw pointer.
|
||||
@ -1476,9 +1471,18 @@ impl<T> Weak<T> {
|
||||
/// [`null`]: ../../std/ptr/fn.null.html
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
let offset = data_offset_sized::<T>();
|
||||
let ptr = self.ptr.cast::<u8>().as_ptr().wrapping_offset(offset);
|
||||
ptr as *const T
|
||||
let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
|
||||
|
||||
// SAFETY: we must offset the pointer manually, and said pointer may be
|
||||
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
|
||||
// because we know that a pointer to unsized T was derived from a real
|
||||
// unsized T, as dangling weaks are only created for sized T. wrapping_offset
|
||||
// is used so that we can use the same code path for the non-dangling
|
||||
// unsized case and the potentially dangling sized case.
|
||||
unsafe {
|
||||
let offset = data_offset(ptr as *mut T);
|
||||
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the `Weak<T>` and turns it into a raw pointer.
|
||||
@ -2270,7 +2274,16 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
impl<T: ?Sized> Unpin for Arc<T> {}
|
||||
|
||||
/// Computes the offset of the data field within `ArcInner`.
|
||||
/// Get the offset within an `ArcInner` for
|
||||
/// a payload of type described by a pointer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This has the same safety requirements as `align_of_val_raw`. In effect:
|
||||
///
|
||||
/// - This function is safe for any argument if `T` is sized, and
|
||||
/// - if `T` is unsized, the pointer must have appropriate pointer metadata
|
||||
/// aquired from the real instance that you are getting this offset for.
|
||||
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
|
||||
// Align the unsized value to the end of the `ArcInner`.
|
||||
// Because it is `?Sized`, it will always be the last field in memory.
|
||||
@ -2279,13 +2292,6 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
|
||||
unsafe { data_offset_align(align_of_val(&*ptr)) }
|
||||
}
|
||||
|
||||
/// Computes the offset of the data field within `ArcInner`.
|
||||
///
|
||||
/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`.
|
||||
fn data_offset_sized<T>() -> isize {
|
||||
data_offset_align(align_of::<T>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn data_offset_align(align: usize) -> isize {
|
||||
let layout = Layout::new::<ArcInner<()>>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user