Does this mean that my (A
)RcBorrow::upgrade
is unsound? It's a not too uncommon pattern to allow upgrading from &T
where the T
is statically known to be behind an (A
)Rc
to an (A
)Rc<T>
, and that's what that library is providing a type for.
The implementation currently uses
pub struct $RcBorrow<'a, T: ?Sized> {
raw: ptr::NonNull<T>,
marker: PhantomData<&'a $Rc<T>>
}
impl<'a, T: ?Sized> From<&'a $Rc<T>> for $RcBorrow<'a, T> {
fn from(v: &'a $Rc<T>) -> $RcBorrow<'a, T> {
$RcBorrow {
raw: (&**v).into(),
marker: PhantomData,
}
}
}
impl<'a, T: ?Sized> $RcBorrow<'a, T> {
/// Convert this borrowed pointer into an owned pointer.
pub fn upgrade(this: Self) -> $Rc<T> {
unsafe { $Rc::clone(&ManuallyDrop::new($Rc::from_raw(this.raw.as_ptr()))) }
}
/// Convert this borrowed pointer into a standard reference.
pub fn downgrade(this: Self) -> &'a T {
unsafe { &*this.raw.as_ptr() }
}
}
As I understand it, we've determined that this way of implementing into_raw
is incorrect when using the current Stacked Borrows rules, so my "as_raw
" implementation would also be unsound to turn into a &$Rc<T>
to clone, as it's lost write provenance over the location of T
. (And a unique $Rc<T>
can be used to write.)
If I understand correctly, the way to make this sound would be to
- Provide a
$Rc::<T>::as_raw(&self) -> *const T
function that uses pointer manipulation instead ofDeref
, - Use that in the implementation of
$RcBorrow<'_, T>
, and - Say that the implicit case of
&T
->$Rc<T>
whereT
is known statically to only be allocated behind$Rc
is actually unsound (unsafe when used to write).
I'm ok with that for this library, but I know &T
-> $Rc<T>
is used in the wild.