about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorCAD97 <cad97@cad97.com>2020-06-28 14:30:35 -0400
committerCAD97 <cad97@cad97.com>2020-06-28 14:33:18 -0400
commitd8a9c61e1a23b73c04d3058a11d1b8b2a46d635e (patch)
tree195ca4652812df625e854155e1fc34a0fbba1033 /src/liballoc
parente4bdf47f4c0773bba93f50900612242b929eca0b (diff)
downloadrust-d8a9c61e1a23b73c04d3058a11d1b8b2a46d635e.tar.gz
rust-d8a9c61e1a23b73c04d3058a11d1b8b2a46d635e.zip
Use impl for Weak::as_ptr that works for unsized T
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/rc.rs24
-rw-r--r--src/liballoc/sync.rs24
2 files changed, 26 insertions, 22 deletions
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 408278d5b61..423122a6900 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -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_raw, 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};
@@ -1704,9 +1704,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);
+        let fake_ptr = ptr as *mut T;
+
+        // SAFETY: we must offset the pointer manually, and said pointer may be
+        // a dangling weak (usize::MAX). data_offset is safe to call, because we
+        // know a pointer to unsized T must be derived from a real unsized T,
+        // because dangling weaks are only created for sized T. wrapping_offset
+        // is used so that we can use the same code path for dangling weak refs.
+        unsafe {
+            let offset = data_offset(&raw const (*ptr).value);
+            set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset))
+        }
     }
 
     /// Consumes the `Weak<T>` and turns it into a raw pointer.
@@ -2117,13 +2126,6 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
     unsafe { data_offset_align(align_of_val_raw(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>())
-}
-
 #[inline]
 fn data_offset_align(align: usize) -> isize {
     let layout = Layout::new::<RcBox<()>>();
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 5a9ab24562a..289aea3afcc 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -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};
@@ -1472,9 +1472,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);
+        let fake_ptr = ptr as *mut T;
+
+        // SAFETY: we must offset the pointer manually, and said pointer may be
+        // a dangling weak (usize::MAX). data_offset is safe to call, because we
+        // know a pointer to unsized T must be derived from a real unsized T,
+        // because dangling weaks are only created for sized T. wrapping_offset
+        // is used so that we can use the same code path for dangling weak refs.
+        unsafe {
+            let offset = data_offset(&raw const (*ptr).data);
+            set_data_ptr(fake_ptr, (ptr as *mut u8).wrapping_offset(offset))
+        }
     }
 
     /// Consumes the `Weak<T>` and turns it into a raw pointer.
@@ -2275,13 +2284,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<()>>();