diff --git a/src/ref_cnt.rs b/src/ref_cnt.rs index 4c31739..b46070b 100644 --- a/src/ref_cnt.rs +++ b/src/ref_cnt.rs @@ -128,9 +128,29 @@ unsafe impl RefCnt for Rc { Rc::into_raw(me) as *mut T } fn as_ptr(me: &Rc) -> *mut T { + // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same + // intention as + // + // me as &T as *const T as *mut T + // + // We first create a "shallow copy" of me - one that doesn't really own its ref count + // (that's OK, me _does_ own it, so it can't be destroyed in the meantime). + // Then we can use into_raw (which preserves not having the ref count). + // + // We need to "revert" the changes we did. In current std implementation, the combination + // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw + // and that read shall be paired with forget to properly "close the brackets". In future + // versions of STD, these may become something else that's not really no-op (unlikely, but + // possible), so we future-proof it a bit. + // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads let ptr = Rc::into_raw(unsafe { std::ptr::read(me) }); - ptr as *mut T + let ptr = ptr as *mut T; + + // SAFETY: We got the pointer from into_raw just above + mem::forget(unsafe { Rc::from_raw(ptr) }); + + ptr } unsafe fn from_ptr(ptr: *const T) -> Rc { Rc::from_raw(ptr)