about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorAndrew Paseltiner <apaseltiner@gmail.com>2015-10-16 11:54:05 -0400
committerAndrew Paseltiner <apaseltiner@gmail.com>2015-10-16 18:35:31 -0400
commitd6bd8d8491e89277edbfc9a4e0f8953847abbdd6 (patch)
tree41bc1358ed0b4712768d308ea3e0df04e25eddf5 /src/libcore
parent05cfd72ed1934c92af08dbcb66fd1af6b1298721 (diff)
downloadrust-d6bd8d8491e89277edbfc9a4e0f8953847abbdd6.tar.gz
rust-d6bd8d8491e89277edbfc9a4e0f8953847abbdd6.zip
Add `Shared` pointer and have `{Arc, Rc}` use it
This change has two consequences:

1. It makes `Arc<T>` and `Rc<T>` covariant in `T`.

2. It causes the compiler to reject code that was unsound with respect
to dropck. See compile-fail/issue-29106.rs for an example of code that
no longer compiles. Because of this, this is a [breaking-change].

Fixes #29037.
Fixes #29106.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/ptr.rs69
1 files changed, 67 insertions, 2 deletions
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 960240d7f5f..8adbaf56f14 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -18,11 +18,11 @@
 
 use clone::Clone;
 use intrinsics;
-use ops::Deref;
+use ops::{CoerceUnsized, Deref};
 use fmt;
 use hash;
 use option::Option::{self, Some, None};
-use marker::{PhantomData, Send, Sized, Sync};
+use marker::{Copy, PhantomData, Send, Sized, Sync, Unsize};
 use mem;
 use nonzero::NonZero;
 
@@ -532,3 +532,68 @@ impl<T> fmt::Pointer for Unique<T> {
         fmt::Pointer::fmt(&*self.pointer, f)
     }
 }
+
+/// A wrapper around a raw `*mut T` that indicates that the possessor
+/// of this wrapper has shared ownership of the referent. Useful for
+/// building abstractions like `Rc<T>` or `Arc<T>`, which internally
+/// use raw pointers to manage the memory that they own.
+#[unstable(feature = "shared", reason = "needs an RFC to flesh out design",
+           issue = "0")]
+pub struct Shared<T: ?Sized> {
+    pointer: NonZero<*const T>,
+    // NOTE: this marker has no consequences for variance, but is necessary
+    // for dropck to understand that we logically own a `T`.
+    //
+    // For details, see:
+    // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
+    _marker: PhantomData<T>,
+}
+
+/// `Shared` pointers are not `Send` because the data they reference may be aliased.
+// NB: This impl is unnecessary, but should provide better error messages.
+#[unstable(feature = "shared", issue = "0")]
+impl<T: ?Sized> !Send for Shared<T> { }
+
+/// `Shared` pointers are not `Sync` because the data they reference may be aliased.
+// NB: This impl is unnecessary, but should provide better error messages.
+#[unstable(feature = "shared", issue = "0")]
+impl<T: ?Sized> !Sync for Shared<T> { }
+
+#[unstable(feature = "shared", issue = "0")]
+impl<T: ?Sized> Shared<T> {
+    /// Creates a new `Shared`.
+    pub unsafe fn new(ptr: *mut T) -> Self {
+        Shared { pointer: NonZero::new(ptr), _marker: PhantomData }
+    }
+}
+
+#[unstable(feature = "shared", issue = "0")]
+impl<T: ?Sized> Clone for Shared<T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+#[unstable(feature = "shared", issue = "0")]
+impl<T: ?Sized> Copy for Shared<T> { }
+
+#[cfg(not(stage0))] // remove cfg after new snapshot
+#[unstable(feature = "shared", issue = "0")]
+impl<T: ?Sized, U: ?Sized> CoerceUnsized<Shared<U>> for Shared<T> where T: Unsize<U> { }
+
+#[unstable(feature = "shared", issue = "0")]
+impl<T: ?Sized> Deref for Shared<T> {
+    type Target = *mut T;
+
+    #[inline]
+    fn deref(&self) -> &*mut T {
+        unsafe { mem::transmute(&*self.pointer) }
+    }
+}
+
+#[unstable(feature = "shared", issue = "0")]
+impl<T> fmt::Pointer for Shared<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Pointer::fmt(&*self.pointer, f)
+    }
+}