Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[r+] Add rules for negative implementations #20972

Merged
merged 18 commits into from
Jan 16, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#![allow(unknown_features)]
#![feature(lang_items, unsafe_destructor)]
#![feature(box_syntax)]
#![feature(optin_builtin_traits)]
#![allow(unknown_features)] #![feature(int_uint)]

#[macro_use]
Expand Down
159 changes: 159 additions & 0 deletions src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ struct RcBox<T> {
/// See the [module level documentation](../index.html) for more details.
#[unsafe_no_drop_flag]
#[stable]
#[cfg(stage0)] // NOTE remove impl after next snapshot
pub struct Rc<T> {
// FIXME #12808: strange names to try to avoid interfering with field accesses of the contained
// type via Deref
Expand All @@ -182,6 +183,24 @@ pub struct Rc<T> {
_noshare: marker::NoSync
}

/// An immutable reference-counted pointer type.
///
/// See the [module level documentation](../index.html) for more details.
#[unsafe_no_drop_flag]
#[stable]
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
pub struct Rc<T> {
// FIXME #12808: strange names to try to avoid interfering with field accesses of the contained
// type via Deref
_ptr: NonZero<*mut RcBox<T>>,
}

#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
impl<T> !marker::Send for Rc<T> {}

#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
impl<T> !marker::Sync for Rc<T> {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this redundant with raw pointers no longer being Send?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's redundant unless, for some reason, NonZero ends up implementing Send. It doesn't now and I don't think it will so we could probably remove it. Although, the extra negative impl is harmless.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's good practice though to be explicit; it serves as documentation. It'd be good to add some comments to the impls though saying why Rc is not sendable/sync. something like

/// `Rc` instances cannot be sent to other threads because they contain a shared reference count which is modified without atomic instructions.
impl<T> !marker::Send for Rc<T> { }

/// `Rc` instances cannot be sent to other threads because they contain a shared reference count which is modified without atomic instructions.
impl<T> !marker::Sync for Rc<T> { }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative, if we had such a thing, would be the equivalent of compile-fail unit tests though.


impl<T> Rc<T> {
/// Constructs a new `Rc<T>`.
///
Expand All @@ -193,6 +212,7 @@ impl<T> Rc<T> {
/// let five = Rc::new(5i);
/// ```
#[stable]
#[cfg(stage0)] // NOTE remove after next snapshot
pub fn new(value: T) -> Rc<T> {
unsafe {
Rc {
Expand All @@ -210,6 +230,32 @@ impl<T> Rc<T> {
}
}

/// Constructs a new `Rc<T>`.
///
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let five = Rc::new(5i);
/// ```
#[stable]
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
pub fn new(value: T) -> Rc<T> {
unsafe {
Rc {
// there is an implicit weak pointer owned by all the strong pointers, which
// ensures that the weak destructor never frees the allocation while the strong
// destructor is running, even if the weak pointer is stored inside the strong one.
_ptr: NonZero::new(transmute(box RcBox {
value: value,
strong: Cell::new(1),
weak: Cell::new(1)
})),
}
}
}

/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
///
/// # Examples
Expand All @@ -221,6 +267,7 @@ impl<T> Rc<T> {
///
/// let weak_five = five.downgrade();
/// ```
#[cfg(stage0)] // NOTE remove after next snapshot
#[unstable = "Weak pointers may not belong in this module"]
pub fn downgrade(&self) -> Weak<T> {
self.inc_weak();
Expand All @@ -230,6 +277,24 @@ impl<T> Rc<T> {
_noshare: marker::NoSync
}
}

/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
///
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let five = Rc::new(5i);
///
/// let weak_five = five.downgrade();
/// ```
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
#[unstable = "Weak pointers may not belong in this module"]
pub fn downgrade(&self) -> Weak<T> {
self.inc_weak();
Weak { _ptr: self._ptr }
}
}

/// Get the number of weak references to this value.
Expand Down Expand Up @@ -432,10 +497,31 @@ impl<T> Clone for Rc<T> {
/// five.clone();
/// ```
#[inline]
#[cfg(stage0)] // NOTE remove after next snapshot
fn clone(&self) -> Rc<T> {
self.inc_strong();
Rc { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync }
}

/// Makes a clone of the `Rc<T>`.
///
/// This increases the strong reference count.
///
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let five = Rc::new(5i);
///
/// five.clone();
/// ```
#[inline]
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
fn clone(&self) -> Rc<T> {
self.inc_strong();
Rc { _ptr: self._ptr }
}
}

#[stable]
Expand Down Expand Up @@ -636,6 +722,7 @@ impl<T: fmt::String> fmt::String for Rc<T> {
/// See the [module level documentation](../index.html) for more.
#[unsafe_no_drop_flag]
#[unstable = "Weak pointers may not belong in this module."]
#[cfg(stage0)] // NOTE remove impl after next snapshot
pub struct Weak<T> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref
Expand All @@ -644,6 +731,29 @@ pub struct Weak<T> {
_noshare: marker::NoSync
}

/// A weak version of `Rc<T>`.
///
/// Weak references do not count when determining if the inner value should be dropped.
///
/// See the [module level documentation](../index.html) for more.
#[unsafe_no_drop_flag]
#[unstable = "Weak pointers may not belong in this module."]
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
pub struct Weak<T> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref
_ptr: NonZero<*mut RcBox<T>>,
}

#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
#[allow(unstable)]
impl<T> !marker::Send for Weak<T> {}

#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
#[allow(unstable)]
impl<T> !marker::Sync for Weak<T> {}


#[unstable = "Weak pointers may not belong in this module."]
impl<T> Weak<T> {
/// Upgrades a weak reference to a strong reference.
Expand All @@ -663,6 +773,7 @@ impl<T> Weak<T> {
///
/// let strong_five: Option<Rc<_>> = weak_five.upgrade();
/// ```
#[cfg(stage0)] // NOTE remove after next snapshot
pub fn upgrade(&self) -> Option<Rc<T>> {
if self.strong() == 0 {
None
Expand All @@ -671,6 +782,33 @@ impl<T> Weak<T> {
Some(Rc { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync })
}
}

/// Upgrades a weak reference to a strong reference.
///
/// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
///
/// Returns `None` if there were no strong references and the data was destroyed.
///
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let five = Rc::new(5i);
///
/// let weak_five = five.downgrade();
///
/// let strong_five: Option<Rc<_>> = weak_five.upgrade();
/// ```
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
pub fn upgrade(&self) -> Option<Rc<T>> {
if self.strong() == 0 {
None
} else {
self.inc_strong();
Some(Rc { _ptr: self._ptr })
}
}
}

#[unsafe_destructor]
Expand Down Expand Up @@ -733,10 +871,31 @@ impl<T> Clone for Weak<T> {
/// weak_five.clone();
/// ```
#[inline]
#[cfg(stage0)] // NOTE remove after next snapshot
fn clone(&self) -> Weak<T> {
self.inc_weak();
Weak { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync }
}

/// Makes a clone of the `Weak<T>`.
///
/// This increases the weak reference count.
///
/// # Examples
///
/// ```
/// use std::rc::Rc;
///
/// let weak_five = Rc::new(5i).downgrade();
///
/// weak_five.clone();
/// ```
#[inline]
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
fn clone(&self) -> Weak<T> {
self.inc_weak();
Weak { _ptr: self._ptr }
}
}

#[unstable = "Show is experimental."]
Expand Down
5 changes: 3 additions & 2 deletions src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,12 +509,13 @@ impl<'b, T> DerefMut for RefMut<'b, T> {
///
/// ```rust
/// use std::cell::UnsafeCell;
/// use std::marker;
/// use std::marker::Sync;
///
/// struct NotThreadSafe<T> {
/// value: UnsafeCell<T>,
/// marker: marker::NoSync
/// }
///
/// unsafe impl<T> Sync for NotThreadSafe<T> {}
/// ```
///
/// **NOTE:** `UnsafeCell<T>` fields are public to allow static initializers. It
Expand Down
2 changes: 2 additions & 0 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ pub struct InvariantLifetime<'a>;
#[unstable = "likely to change with new variance strategy"]
#[lang="no_send_bound"]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg(stage0)] // NOTE remove impl after next snapshot
pub struct NoSend;

/// A type which is considered "not POD", meaning that it is not
Expand All @@ -303,6 +304,7 @@ pub struct NoCopy;
#[unstable = "likely to change with new variance strategy"]
#[lang="no_sync_bound"]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg(stage0)] // NOTE remove impl after next snapshot
pub struct NoSync;

/// A type which is considered managed by the GC. This is typically
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,15 @@ pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
}
}

pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>,
def: ast::DefId)
-> Option<ast::ImplPolarity>
{
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
decoder::get_impl_polarity(&*cdata, def.node)
}

// Given a def_id for an impl, return the trait it implements,
// if there is one.
pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
Expand Down
23 changes: 23 additions & 0 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,15 @@ fn parse_unsafety(item_doc: rbml::Doc) -> ast::Unsafety {
}
}

fn parse_polarity(item_doc: rbml::Doc) -> ast::ImplPolarity {
let polarity_doc = reader::get_doc(item_doc, tag_polarity);
if reader::doc_as_u8(polarity_doc) != 0 {
ast::ImplPolarity::Negative
} else {
ast::ImplPolarity::Positive
}
}

fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
let mut names = Vec::new();
Expand Down Expand Up @@ -436,6 +445,20 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec<attr::ReprAttr> {
}
}

pub fn get_impl_polarity<'tcx>(cdata: Cmd,
id: ast::NodeId)
-> Option<ast::ImplPolarity>
{
let item_doc = lookup_item(id, cdata.data());
let fam = item_family(item_doc);
match fam {
Family::Impl => {
Some(parse_polarity(item_doc))
}
_ => None
}
}

pub fn get_impl_trait<'tcx>(cdata: Cmd,
id: ast::NodeId,
tcx: &ty::ctxt<'tcx>)
Expand Down
Loading