auto merge of #20972 : FlaPer87/rust/oibit-send-and-friends, r=nikomatsakis
This PR adds rules for negative implementations. It follows pretty much what the [RFC](https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md) says with 1 main difference: Instead of positive implementations override negative implementations, this have been implemented in a way that a negative implementation of `Trait` for `T` will overlap with a positive implementation, causing a coherence error. @nikomatsakis r? cc #13231 [breaking-change]
This commit is contained in:
commit
ee2bfae011
src
liballoc
libcore
librustc
librustc_typeck
libstd
test
compile-fail
coherence-conflicting-negative-trait-impl.rscoherence-negative-impls-safe.rscoherence-orphan.rsissue-17718-static-sync.rsissue-7013.rskindck-nonsendable-1.rsmutable-enum-indirect.rsno-send-res-ports.rsno_send-enum.rsno_send-rc.rsno_send-struct.rsno_share-enum.rsno_share-rc.rsno_share-struct.rstask-rng-isnt-sendable.rstraits-negative-impls.rstypeck-negative-impls-builtin.rstypeck-unsafe-always-share.rsunique-unique-kind.rsunsendable-class.rs
pretty
run-pass
@ -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]
|
||||
|
@ -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
|
||||
@ -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> {}
|
||||
|
||||
impl<T> Rc<T> {
|
||||
/// Constructs a new `Rc<T>`.
|
||||
///
|
||||
@ -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 {
|
||||
@ -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
|
||||
@ -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();
|
||||
@ -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.
|
||||
@ -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]
|
||||
@ -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
|
||||
@ -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.
|
||||
@ -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
|
||||
@ -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]
|
||||
@ -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."]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
@ -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>,
|
||||
|
@ -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();
|
||||
@ -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>)
|
||||
|
@ -611,6 +611,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
||||
// If there are *NO* candidates, that there are no impls --
|
||||
// that we know of, anyway. Note that in the case where there
|
||||
// are unbound type variables within the obligation, it might
|
||||
@ -626,6 +627,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
// Just one candidate left.
|
||||
let candidate = candidates.pop().unwrap();
|
||||
|
||||
match candidate {
|
||||
ImplCandidate(def_id) => {
|
||||
match ty::trait_impl_polarity(self.tcx(), def_id) {
|
||||
Some(ast::ImplPolarity::Negative) => return Err(Unimplemented),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(Some(candidate))
|
||||
}
|
||||
|
||||
@ -714,7 +726,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
debug!("obligation self ty is {}",
|
||||
obligation.predicate.0.self_ty().repr(self.tcx()));
|
||||
|
||||
try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
|
||||
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
|
||||
|
||||
try!(self.assemble_builtin_bound_candidates(ty::BoundCopy,
|
||||
stack,
|
||||
@ -722,10 +734,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
Some(bound @ ty::BoundSend) |
|
||||
Some(bound @ ty::BoundSync) => {
|
||||
try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
|
||||
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
|
||||
|
||||
// No explicit impls were declared for this type, consider the fallback rules.
|
||||
if candidates.vec.is_empty() {
|
||||
if candidates.vec.is_empty() && !candidates.ambiguous {
|
||||
try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates));
|
||||
}
|
||||
}
|
||||
@ -741,7 +753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// (And unboxed candidates only apply to the Fn/FnMut/etc traits.)
|
||||
try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates));
|
||||
try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
|
||||
try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
|
||||
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
|
||||
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
|
||||
}
|
||||
}
|
||||
@ -1013,9 +1025,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// Search for impls that might apply to `obligation`.
|
||||
fn assemble_candidates_from_impls(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidate_vec: &mut Vec<SelectionCandidate<'tcx>>)
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(), SelectionError<'tcx>>
|
||||
{
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
|
||||
debug!("assemble_candidates_from_impls(self_ty={})", self_ty.repr(self.tcx()));
|
||||
|
||||
let all_impls = self.all_impls(obligation.predicate.def_id());
|
||||
for &impl_def_id in all_impls.iter() {
|
||||
self.infcx.probe(|snapshot| {
|
||||
@ -1024,7 +1039,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
match self.match_impl(impl_def_id, obligation, snapshot,
|
||||
&skol_map, skol_obligation_trait_pred.trait_ref.clone()) {
|
||||
Ok(_) => {
|
||||
candidate_vec.push(ImplCandidate(impl_def_id));
|
||||
candidates.vec.push(ImplCandidate(impl_def_id));
|
||||
}
|
||||
Err(()) => { }
|
||||
}
|
||||
@ -2214,8 +2229,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
/// Returns set of all impls for a given trait.
|
||||
fn all_impls(&self, trait_def_id: ast::DefId) -> Vec<ast::DefId> {
|
||||
ty::populate_implementations_for_trait_if_necessary(self.tcx(),
|
||||
trait_def_id);
|
||||
ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_def_id);
|
||||
|
||||
match self.tcx().trait_impls.borrow().get(&trait_def_id) {
|
||||
None => Vec::new(),
|
||||
Some(impls) => impls.borrow().clone()
|
||||
|
@ -1891,7 +1891,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::R
|
||||
/// normal trait predicate (`T : TraitRef<...>`) and one of these
|
||||
/// predicates. Form #2 is a broader form in that it also permits
|
||||
/// equality between arbitrary types. Processing an instance of Form
|
||||
/// \#2 eventually yields one of these `ProjectionPredicate`
|
||||
/// #2 eventually yields one of these `ProjectionPredicate`
|
||||
/// instances to normalize the LHS.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Show)]
|
||||
pub struct ProjectionPredicate<'tcx> {
|
||||
@ -5035,6 +5035,23 @@ pub fn trait_items<'tcx>(cx: &ctxt<'tcx>, trait_did: ast::DefId)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_impl_polarity<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
|
||||
-> Option<ast::ImplPolarity> {
|
||||
if id.krate == ast::LOCAL_CRATE {
|
||||
match cx.map.find(id.node) {
|
||||
Some(ast_map::NodeItem(item)) => {
|
||||
match item.node {
|
||||
ast::ItemImpl(_, polarity, _, _, _, _) => Some(polarity),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
csearch::get_impl_polarity(cx, id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn impl_or_trait_item<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
|
||||
-> ImplOrTraitItem<'tcx> {
|
||||
lookup_locally_or_in_crate_store("impl_or_trait_items",
|
||||
@ -5984,6 +6001,7 @@ pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
|
||||
pub fn record_trait_implementation(tcx: &ctxt,
|
||||
trait_def_id: DefId,
|
||||
impl_def_id: DefId) {
|
||||
|
||||
match tcx.trait_impls.borrow().get(&trait_def_id) {
|
||||
Some(impls_for_trait) => {
|
||||
impls_for_trait.borrow_mut().push(impl_def_id);
|
||||
@ -5991,6 +6009,7 @@ pub fn record_trait_implementation(tcx: &ctxt,
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
tcx.trait_impls.borrow_mut().insert(trait_def_id, Rc::new(RefCell::new(vec!(impl_def_id))));
|
||||
}
|
||||
|
||||
|
@ -1597,7 +1597,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
{
|
||||
debug!("register_predicate({})",
|
||||
obligation.repr(self.tcx()));
|
||||
|
||||
self.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.register_predicate_obligation(self.infcx(), obligation);
|
||||
|
@ -56,9 +56,38 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||
ty::item_path_str(ccx.tcx, local_def(item.id)));
|
||||
|
||||
match item.node {
|
||||
ast::ItemImpl(..) => {
|
||||
/// Right now we check that every default trait implementation
|
||||
/// has an implementation of itself. Basically, a case like:
|
||||
///
|
||||
/// `impl Trait for T {}`
|
||||
///
|
||||
/// has a requirement of `T: Trait` which was required for default
|
||||
/// method implementations. Although this could be improved now that
|
||||
/// there's a better infrastructure in place for this, it's being left
|
||||
/// for a follow-up work.
|
||||
///
|
||||
/// Since there's such a requirement, we need to check *just* positive
|
||||
/// implementations, otherwise things like:
|
||||
///
|
||||
/// impl !Send for T {}
|
||||
///
|
||||
/// won't be allowed unless there's an *explicit* implementation of `Send`
|
||||
/// for `T`
|
||||
ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => {
|
||||
self.check_impl(item);
|
||||
}
|
||||
ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(ref tref), _, _) => {
|
||||
let trait_ref = ty::node_id_to_trait_ref(ccx.tcx, tref.ref_id);
|
||||
match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
|
||||
Some(ty::BoundSend) | Some(ty::BoundSync) => {}
|
||||
Some(_) | None => {
|
||||
ccx.tcx.sess.span_err(
|
||||
item.span,
|
||||
format!("negative impls are currently \
|
||||
allowed just for `Send` and `Sync`").as_slice())
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ItemFn(..) => {
|
||||
self.check_item_type(item);
|
||||
}
|
||||
|
@ -38,36 +38,34 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||
// check_for_overlapping_impls_of_trait() check, since that
|
||||
// check can populate this table further with impls from other
|
||||
// crates.
|
||||
let trait_def_ids: Vec<ast::DefId> =
|
||||
self.tcx.trait_impls.borrow().keys().map(|&d| d).collect();
|
||||
let trait_def_ids: Vec<(ast::DefId, Vec<ast::DefId>)> =
|
||||
self.tcx.trait_impls.borrow().iter().map(|(&k, v)| {
|
||||
// FIXME -- it seems like this method actually pushes
|
||||
// duplicate impls onto the list
|
||||
ty::populate_implementations_for_trait_if_necessary(self.tcx, k);
|
||||
(k, v.borrow().clone())
|
||||
}).collect();
|
||||
|
||||
for trait_def_id in trait_def_ids.iter() {
|
||||
self.check_for_overlapping_impls_of_trait(*trait_def_id);
|
||||
for &(trait_def_id, ref impls) in trait_def_ids.iter() {
|
||||
self.check_for_overlapping_impls_of_trait(trait_def_id, impls);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_overlapping_impls_of_trait(&self,
|
||||
trait_def_id: ast::DefId)
|
||||
trait_def_id: ast::DefId,
|
||||
trait_impls: &Vec<ast::DefId>)
|
||||
{
|
||||
debug!("check_for_overlapping_impls_of_trait(trait_def_id={})",
|
||||
trait_def_id.repr(self.tcx));
|
||||
|
||||
// FIXME -- it seems like this method actually pushes
|
||||
// duplicate impls onto the list
|
||||
ty::populate_implementations_for_trait_if_necessary(self.tcx,
|
||||
trait_def_id);
|
||||
|
||||
let mut impls = Vec::new();
|
||||
self.push_impls_of_trait(trait_def_id, &mut impls);
|
||||
|
||||
for (i, &impl1_def_id) in impls.iter().enumerate() {
|
||||
for (i, &impl1_def_id) in trait_impls.iter().enumerate() {
|
||||
if impl1_def_id.krate != ast::LOCAL_CRATE {
|
||||
// we don't need to check impls if both are external;
|
||||
// that's the other crate's job.
|
||||
continue;
|
||||
}
|
||||
|
||||
for &impl2_def_id in impls.slice_from(i+1).iter() {
|
||||
for &impl2_def_id in trait_impls.slice_from(i+1).iter() {
|
||||
self.check_if_impls_overlap(trait_def_id,
|
||||
impl1_def_id,
|
||||
impl2_def_id);
|
||||
@ -108,15 +106,6 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn push_impls_of_trait(&self,
|
||||
trait_def_id: ast::DefId,
|
||||
out: &mut Vec<ast::DefId>) {
|
||||
match self.tcx.trait_impls.borrow().get(&trait_def_id) {
|
||||
Some(impls) => { out.push_all(impls.borrow().as_slice()); }
|
||||
None => { /* no impls */ }
|
||||
}
|
||||
}
|
||||
|
||||
fn span_of_impl(&self, impl_did: ast::DefId) -> Span {
|
||||
assert_eq!(impl_did.krate, ast::LOCAL_CRATE);
|
||||
self.tcx.map.span(impl_did.node)
|
||||
|
@ -30,7 +30,7 @@ struct UnsafetyChecker<'cx, 'tcx:'cx> {
|
||||
impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
||||
fn visit_item(&mut self, item: &'v ast::Item) {
|
||||
match item.node {
|
||||
ast::ItemImpl(unsafety, _, _, _, _, _) => {
|
||||
ast::ItemImpl(unsafety, polarity, _, _, _, _) => {
|
||||
match ty::impl_trait_ref(self.tcx, ast_util::local_def(item.id)) {
|
||||
None => {
|
||||
// Inherent impl.
|
||||
@ -46,23 +46,34 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
||||
|
||||
Some(trait_ref) => {
|
||||
let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
|
||||
match (trait_def.unsafety, unsafety) {
|
||||
(ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
|
||||
match (trait_def.unsafety, unsafety, polarity) {
|
||||
(ast::Unsafety::Unsafe,
|
||||
ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => {
|
||||
self.tcx.sess.span_err(
|
||||
item.span,
|
||||
format!("negative implementations are not unsafe").as_slice());
|
||||
}
|
||||
|
||||
(ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
|
||||
self.tcx.sess.span_err(
|
||||
item.span,
|
||||
format!("implementing the trait `{}` is not unsafe",
|
||||
trait_ref.user_string(self.tcx)).as_slice());
|
||||
}
|
||||
|
||||
(ast::Unsafety::Unsafe, ast::Unsafety::Normal) => {
|
||||
(ast::Unsafety::Unsafe,
|
||||
ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
|
||||
self.tcx.sess.span_err(
|
||||
item.span,
|
||||
format!("the trait `{}` requires an `unsafe impl` declaration",
|
||||
trait_ref.user_string(self.tcx)).as_slice());
|
||||
}
|
||||
|
||||
(ast::Unsafety::Unsafe, ast::Unsafety::Unsafe) |
|
||||
(ast::Unsafety::Normal, ast::Unsafety::Normal) => {
|
||||
(ast::Unsafety::Unsafe,
|
||||
ast::Unsafety::Normal, ast::ImplPolarity::Negative) |
|
||||
(ast::Unsafety::Unsafe,
|
||||
ast::Unsafety::Unsafe, ast::ImplPolarity::Positive) |
|
||||
(ast::Unsafety::Normal, ast::Unsafety::Normal, _) => {
|
||||
/* OK */
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,7 @@
|
||||
#![feature(slicing_syntax, unboxed_closures)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(old_impl_check)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
|
||||
// Don't link to std. We are std.
|
||||
|
@ -14,6 +14,7 @@ use thread::Thread;
|
||||
use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
||||
use sync::Arc;
|
||||
use marker::{Sync, Send};
|
||||
#[cfg(stage0)] // NOTE remove use after next snapshot
|
||||
use marker::{NoSend, NoSync};
|
||||
use mem;
|
||||
use clone::Clone;
|
||||
@ -31,12 +32,25 @@ pub struct SignalToken {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub struct WaitToken {
|
||||
inner: Arc<Inner>,
|
||||
no_send: NoSend,
|
||||
no_sync: NoSync,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub struct WaitToken {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl !Send for WaitToken {}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl !Sync for WaitToken {}
|
||||
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub fn tokens() -> (WaitToken, SignalToken) {
|
||||
let inner = Arc::new(Inner {
|
||||
thread: Thread::current(),
|
||||
@ -53,6 +67,21 @@ pub fn tokens() -> (WaitToken, SignalToken) {
|
||||
(wait_token, signal_token)
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub fn tokens() -> (WaitToken, SignalToken) {
|
||||
let inner = Arc::new(Inner {
|
||||
thread: Thread::current(),
|
||||
woken: ATOMIC_BOOL_INIT,
|
||||
});
|
||||
let wait_token = WaitToken {
|
||||
inner: inner.clone(),
|
||||
};
|
||||
let signal_token = SignalToken {
|
||||
inner: inner
|
||||
};
|
||||
(wait_token, signal_token)
|
||||
}
|
||||
|
||||
impl SignalToken {
|
||||
pub fn signal(&self) -> bool {
|
||||
let wake = !self.inner.woken.compare_and_swap(false, true, Ordering::SeqCst);
|
||||
|
@ -370,12 +370,24 @@ unsafe impl<T:Send> Send for Sender<T> { }
|
||||
/// The sending-half of Rust's synchronous channel type. This half can only be
|
||||
/// owned by one task, but it can be cloned to send to other tasks.
|
||||
#[stable]
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub struct SyncSender<T> {
|
||||
inner: Arc<RacyCell<sync::Packet<T>>>,
|
||||
// can't share in an arc
|
||||
_marker: marker::NoSync,
|
||||
}
|
||||
|
||||
/// The sending-half of Rust's synchronous channel type. This half can only be
|
||||
/// owned by one task, but it can be cloned to send to other tasks.
|
||||
#[stable]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub struct SyncSender<T> {
|
||||
inner: Arc<RacyCell<sync::Packet<T>>>,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl<T> !marker::Sync for SyncSender<T> {}
|
||||
|
||||
/// An error returned from the `send` function on channels.
|
||||
///
|
||||
/// A `send` operation can only fail if the receiving end of a channel is
|
||||
@ -677,10 +689,16 @@ impl<T: Send> Drop for Sender<T> {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T: Send> SyncSender<T> {
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
fn new(inner: Arc<RacyCell<sync::Packet<T>>>) -> SyncSender<T> {
|
||||
SyncSender { inner: inner, _marker: marker::NoSync }
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
fn new(inner: Arc<RacyCell<sync::Packet<T>>>) -> SyncSender<T> {
|
||||
SyncSender { inner: inner }
|
||||
}
|
||||
|
||||
/// Sends a value on this synchronous channel.
|
||||
///
|
||||
/// This function will *block* until space in the internal buffer becomes
|
||||
|
@ -66,6 +66,7 @@ use sync::mpsc::blocking::{self, SignalToken};
|
||||
|
||||
/// The "receiver set" of the select interface. This structure is used to manage
|
||||
/// a set of receivers which are being selected over.
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub struct Select {
|
||||
head: *mut Handle<'static, ()>,
|
||||
tail: *mut Handle<'static, ()>,
|
||||
@ -73,6 +74,18 @@ pub struct Select {
|
||||
marker1: marker::NoSend,
|
||||
}
|
||||
|
||||
/// The "receiver set" of the select interface. This structure is used to manage
|
||||
/// a set of receivers which are being selected over.
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub struct Select {
|
||||
head: *mut Handle<'static, ()>,
|
||||
tail: *mut Handle<'static, ()>,
|
||||
next_id: Cell<uint>,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl !marker::Send for Select {}
|
||||
|
||||
/// A handle to a receiver which is currently a member of a `Select` set of
|
||||
/// receivers. This handle is used to keep the receiver in the set as well as
|
||||
/// interact with the underlying receiver.
|
||||
@ -113,6 +126,7 @@ impl Select {
|
||||
///
|
||||
/// Usage of this struct directly can sometimes be burdensome, and usage is
|
||||
/// rather much easier through the `select!` macro.
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub fn new() -> Select {
|
||||
Select {
|
||||
marker1: marker::NoSend,
|
||||
@ -122,6 +136,20 @@ impl Select {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new selection structure. This set is initially empty and
|
||||
/// `wait` will panic!() if called.
|
||||
///
|
||||
/// Usage of this struct directly can sometimes be burdensome, and usage is
|
||||
/// rather much easier through the `select!` macro.
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub fn new() -> Select {
|
||||
Select {
|
||||
head: 0 as *mut Handle<'static, ()>,
|
||||
tail: 0 as *mut Handle<'static, ()>,
|
||||
next_id: Cell::new(1),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new handle into this receiver set for a new receiver. Note
|
||||
/// that this does *not* add the receiver to the receiver set, for that you
|
||||
/// must call the `add` method on the handle itself.
|
||||
|
@ -160,6 +160,7 @@ unsafe impl Sync for StaticMutex {}
|
||||
/// Deref and DerefMut implementations
|
||||
#[must_use]
|
||||
#[stable]
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub struct MutexGuard<'a, T: 'a> {
|
||||
// funny underscores due to how Deref/DerefMut currently work (they
|
||||
// disregard field privacy).
|
||||
@ -169,6 +170,25 @@ pub struct MutexGuard<'a, T: 'a> {
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
|
||||
/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
|
||||
/// dropped (falls out of scope), the lock will be unlocked.
|
||||
///
|
||||
/// The data protected by the mutex can be access through this guard via its
|
||||
/// Deref and DerefMut implementations
|
||||
#[must_use]
|
||||
#[stable]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub struct MutexGuard<'a, T: 'a> {
|
||||
// funny underscores due to how Deref/DerefMut currently work (they
|
||||
// disregard field privacy).
|
||||
__lock: &'a StaticMutex,
|
||||
__data: &'a UnsafeCell<T>,
|
||||
__poison: poison::Guard,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl<'a, T> !marker::Send for MutexGuard<'a, T> {}
|
||||
|
||||
/// Static initialization of a mutex. This constant can be used to initialize
|
||||
/// other mutex constants.
|
||||
#[unstable = "may be merged with Mutex in the future"]
|
||||
@ -279,6 +299,7 @@ impl StaticMutex {
|
||||
}
|
||||
|
||||
impl<'mutex, T> MutexGuard<'mutex, T> {
|
||||
#[cfg(stage0)] // NOTE remove afte next snapshot
|
||||
fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
|
||||
-> LockResult<MutexGuard<'mutex, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |guard| {
|
||||
@ -290,6 +311,18 @@ impl<'mutex, T> MutexGuard<'mutex, T> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg afte next snapshot
|
||||
fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
|
||||
-> LockResult<MutexGuard<'mutex, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |guard| {
|
||||
MutexGuard {
|
||||
__lock: lock,
|
||||
__data: data,
|
||||
__poison: guard,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
|
@ -110,23 +110,52 @@ pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock {
|
||||
/// dropped.
|
||||
#[must_use]
|
||||
#[stable]
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub struct RwLockReadGuard<'a, T: 'a> {
|
||||
__lock: &'a StaticRwLock,
|
||||
__data: &'a UnsafeCell<T>,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
|
||||
/// RAII structure used to release the shared read access of a lock when
|
||||
/// dropped.
|
||||
#[must_use]
|
||||
#[stable]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub struct RwLockReadGuard<'a, T: 'a> {
|
||||
__lock: &'a StaticRwLock,
|
||||
__data: &'a UnsafeCell<T>,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl<'a, T> !marker::Send for RwLockReadGuard<'a, T> {}
|
||||
|
||||
/// RAII structure used to release the exclusive write access of a lock when
|
||||
/// dropped.
|
||||
#[must_use]
|
||||
#[stable]
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub struct RwLockWriteGuard<'a, T: 'a> {
|
||||
__lock: &'a StaticRwLock,
|
||||
__data: &'a UnsafeCell<T>,
|
||||
__poison: poison::Guard,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
|
||||
/// RAII structure used to release the exclusive write access of a lock when
|
||||
/// dropped.
|
||||
#[must_use]
|
||||
#[stable]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub struct RwLockWriteGuard<'a, T: 'a> {
|
||||
__lock: &'a StaticRwLock,
|
||||
__data: &'a UnsafeCell<T>,
|
||||
__poison: poison::Guard,
|
||||
__marker: marker::NoSend,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl<'a, T> !marker::Send for RwLockWriteGuard<'a, T> {}
|
||||
|
||||
impl<T: Send + Sync> RwLock<T> {
|
||||
/// Creates a new instance of an RwLock which is unlocked and read to go.
|
||||
#[stable]
|
||||
@ -303,6 +332,7 @@ impl StaticRwLock {
|
||||
}
|
||||
|
||||
impl<'rwlock, T> RwLockReadGuard<'rwlock, T> {
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
|
||||
-> LockResult<RwLockReadGuard<'rwlock, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |_| {
|
||||
@ -313,8 +343,20 @@ impl<'rwlock, T> RwLockReadGuard<'rwlock, T> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
|
||||
-> LockResult<RwLockReadGuard<'rwlock, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |_| {
|
||||
RwLockReadGuard {
|
||||
__lock: lock,
|
||||
__data: data,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> {
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
|
||||
-> LockResult<RwLockWriteGuard<'rwlock, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |guard| {
|
||||
@ -326,6 +368,18 @@ impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
|
||||
-> LockResult<RwLockWriteGuard<'rwlock, T>> {
|
||||
poison::map_result(lock.poison.borrow(), |guard| {
|
||||
RwLockWriteGuard {
|
||||
__lock: lock,
|
||||
__data: data,
|
||||
__poison: guard,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
|
@ -0,0 +1,29 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
trait MyTrait {}
|
||||
|
||||
struct TestType<T>;
|
||||
|
||||
unsafe impl<T: MyTrait> Send for TestType<T> {}
|
||||
//~^ ERROR conflicting implementations for trait `core::marker::Send`
|
||||
//~^^ ERROR conflicting implementations for trait `core::marker::Send`
|
||||
|
||||
impl<T: MyTrait> !Send for TestType<T> {}
|
||||
//~^ ERROR conflicting implementations for trait `core::marker::Send`
|
||||
|
||||
unsafe impl<T> Send for TestType<T> {}
|
||||
//~^ ERROR error: conflicting implementations for trait `core::marker::Send`
|
||||
|
||||
impl !Send for TestType<i32> {}
|
||||
|
||||
fn main() {}
|
16
src/test/compile-fail/marker-no-share.rs → src/test/compile-fail/coherence-negative-impls-safe.rs
16
src/test/compile-fail/marker-no-share.rs → src/test/compile-fail/coherence-negative-impls-safe.rs
@ -1,4 +1,4 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -8,11 +8,13 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker;
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
fn foo<P: Sync>(p: P) { }
|
||||
use std::marker::Send;
|
||||
|
||||
fn main()
|
||||
{
|
||||
foo(marker::NoSync); //~ ERROR the trait `core::marker::Sync` is not implemented
|
||||
}
|
||||
struct TestType;
|
||||
|
||||
unsafe impl !Send for TestType {}
|
||||
//~^ ERROR negative implementations are not unsafe
|
||||
|
||||
fn main() {}
|
@ -8,8 +8,11 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
// aux-build:coherence-orphan-lib.rs
|
||||
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
extern crate "coherence-orphan-lib" as lib;
|
||||
|
||||
use lib::TheTrait;
|
||||
@ -22,4 +25,7 @@ impl TheTrait<TheType> for isize { } //~ ERROR E0117
|
||||
|
||||
impl TheTrait<isize> for TheType { }
|
||||
|
||||
impl !Send for Vec<isize> { } //~ ERROR E0117
|
||||
//~^ ERROR conflicting
|
||||
|
||||
fn main() { }
|
||||
|
@ -8,12 +8,15 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker;
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
struct Foo { marker: marker::NoSync }
|
||||
use std::marker::Sync;
|
||||
|
||||
struct Foo;
|
||||
impl !Sync for Foo {}
|
||||
|
||||
static FOO: usize = 3;
|
||||
static BAR: Foo = Foo { marker: marker::NoSync };
|
||||
static BAR: Foo = Foo;
|
||||
//~^ ERROR: the trait `core::marker::Sync` is not implemented
|
||||
|
||||
fn main() {}
|
||||
|
@ -35,5 +35,4 @@ struct A {
|
||||
fn main() {
|
||||
let a = A {v: box B{v: None} as Box<Foo+Send>};
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented
|
||||
//~^^ ERROR the trait `core::marker::Send` is not implemented
|
||||
}
|
||||
|
@ -19,6 +19,5 @@ fn main() {
|
||||
let x = Rc::new(3us);
|
||||
bar(move|| foo(x));
|
||||
//~^ ERROR `core::marker::Send` is not implemented
|
||||
//~^^ ERROR `core::marker::Send` is not implemented
|
||||
}
|
||||
|
||||
|
@ -11,13 +11,18 @@
|
||||
// Tests that an `&` pointer to something inherently mutable is itself
|
||||
// to be considered mutable.
|
||||
|
||||
use std::marker;
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
enum Foo { A(marker::NoSync) }
|
||||
use std::marker::Sync;
|
||||
|
||||
struct NoSync;
|
||||
impl !Sync for NoSync {}
|
||||
|
||||
enum Foo { A(NoSync) }
|
||||
|
||||
fn bar<T: Sync>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
let x = Foo::A(marker::NoSync);
|
||||
let x = Foo::A(NoSync);
|
||||
bar(&x); //~ ERROR the trait `core::marker::Sync` is not implemented
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ fn main() {
|
||||
|
||||
Thread::spawn(move|| {
|
||||
//~^ ERROR `core::marker::Send` is not implemented
|
||||
//~^^ ERROR `core::marker::Send` is not implemented
|
||||
let y = x;
|
||||
println!("{:?}", y);
|
||||
});
|
||||
|
@ -8,16 +8,21 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker;
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
use std::marker::Send;
|
||||
|
||||
struct NoSend;
|
||||
impl !Send for NoSend {}
|
||||
|
||||
enum Foo {
|
||||
A(marker::NoSend)
|
||||
A(NoSend)
|
||||
}
|
||||
|
||||
fn bar<T: Send>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
let x = Foo::A(marker::NoSend);
|
||||
let x = Foo::A(NoSend);
|
||||
bar(x);
|
||||
//~^ ERROR `core::marker::Send` is not implemented
|
||||
}
|
||||
|
@ -16,5 +16,4 @@ fn main() {
|
||||
let x = Rc::new(5is);
|
||||
bar(x);
|
||||
//~^ ERROR `core::marker::Send` is not implemented
|
||||
//~^^ ERROR `core::marker::Send` is not implemented
|
||||
}
|
||||
|
@ -8,17 +8,20 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker;
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
use std::marker::Send;
|
||||
|
||||
struct Foo {
|
||||
a: isize,
|
||||
ns: marker::NoSend
|
||||
}
|
||||
|
||||
impl !Send for Foo {}
|
||||
|
||||
fn bar<T: Send>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
let x = Foo { a: 5, ns: marker::NoSend };
|
||||
let x = Foo { a: 5 };
|
||||
bar(x);
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented
|
||||
}
|
||||
|
@ -8,14 +8,19 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker;
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
enum Foo { A(marker::NoSync) }
|
||||
use std::marker::Sync;
|
||||
|
||||
struct NoSync;
|
||||
impl !Sync for NoSync {}
|
||||
|
||||
enum Foo { A(NoSync) }
|
||||
|
||||
fn bar<T: Sync>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
let x = Foo::A(marker::NoSync);
|
||||
let x = Foo::A(NoSync);
|
||||
bar(x);
|
||||
//~^ ERROR the trait `core::marker::Sync` is not implemented
|
||||
}
|
||||
|
@ -17,5 +17,4 @@ fn main() {
|
||||
let x = Rc::new(RefCell::new(5is));
|
||||
bar(x);
|
||||
//~^ ERROR the trait `core::marker::Sync` is not implemented
|
||||
//~^^ ERROR the trait `core::marker::Sync` is not implemented
|
||||
}
|
||||
|
@ -8,14 +8,17 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker;
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
struct Foo { a: isize, m: marker::NoSync }
|
||||
use std::marker::Sync;
|
||||
|
||||
struct Foo { a: isize }
|
||||
impl !Sync for Foo {}
|
||||
|
||||
fn bar<T: Sync>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
let x = Foo { a: 5, m: marker::NoSync };
|
||||
let x = Foo { a: 5 };
|
||||
bar(x);
|
||||
//~^ ERROR the trait `core::marker::Sync` is not implemented
|
||||
}
|
||||
|
@ -17,5 +17,4 @@ fn test_send<S: Send>() {}
|
||||
pub fn main() {
|
||||
test_send::<rand::ThreadRng>();
|
||||
//~^ ERROR `core::marker::Send` is not implemented
|
||||
//~^^ ERROR `core::marker::Send` is not implemented
|
||||
}
|
||||
|
58
src/test/compile-fail/traits-negative-impls.rs
Normal file
58
src/test/compile-fail/traits-negative-impls.rs
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// The dummy functions are used to avoid adding new cfail files.
|
||||
// What happens is that the compiler attempts to squash duplicates and some
|
||||
// errors are not reported. This way, we make sure that, for each function, different
|
||||
// typeck phases are involved and all errors are reported.
|
||||
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
use std::marker::Send;
|
||||
|
||||
struct Outer<T: Send>(T);
|
||||
|
||||
struct TestType;
|
||||
impl !Send for TestType {}
|
||||
|
||||
struct Outer2<T>(T);
|
||||
|
||||
unsafe impl<T: Send> Sync for Outer2<T> {}
|
||||
|
||||
fn is_send<T: Send>(_: T) {}
|
||||
fn is_sync<T: Sync>(_: T) {}
|
||||
|
||||
fn dummy() {
|
||||
Outer(TestType);
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
|
||||
|
||||
is_send(TestType);
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
|
||||
|
||||
is_send((8, TestType));
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
|
||||
}
|
||||
|
||||
fn dummy2() {
|
||||
is_send(Box::new(TestType));
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
|
||||
}
|
||||
|
||||
fn dummy3() {
|
||||
is_send(Box::new(Outer2(TestType)));
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// This will complain about a missing Send impl because `Sync` is implement *just*
|
||||
// for T that are `Send`. Look at #20366 and #19950
|
||||
is_sync(Outer2(TestType));
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
|
||||
}
|
20
src/test/compile-fail/typeck-negative-impls-builtin.rs
Normal file
20
src/test/compile-fail/typeck-negative-impls-builtin.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
struct TestType;
|
||||
|
||||
trait TestTrait {}
|
||||
|
||||
impl !TestTrait for TestType {}
|
||||
//~^ ERROR negative impls are currently allowed just for `Send` and `Sync`
|
||||
|
||||
fn main() {}
|
@ -10,29 +10,26 @@
|
||||
|
||||
// Verify that UnsafeCell is *always* sync regardless if `T` is sync.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::marker;
|
||||
use std::marker::Sync;
|
||||
|
||||
struct MySync<T> {
|
||||
u: UnsafeCell<T>
|
||||
}
|
||||
|
||||
struct NoSync {
|
||||
m: marker::NoSync
|
||||
}
|
||||
struct NoSync;
|
||||
impl !Sync for NoSync {}
|
||||
|
||||
fn test<T: Sync>(s: T){
|
||||
|
||||
}
|
||||
fn test<T: Sync>(s: T) {}
|
||||
|
||||
fn main() {
|
||||
let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0is)});
|
||||
test(us);
|
||||
//~^ ERROR `core::marker::Sync` is not implemented
|
||||
|
||||
let uns = UnsafeCell::new(NoSync{m: marker::NoSync});
|
||||
let uns = UnsafeCell::new(NoSync);
|
||||
test(uns);
|
||||
//~^ ERROR `core::marker::Sync` is not implemented
|
||||
|
||||
@ -40,7 +37,6 @@ fn main() {
|
||||
test(ms);
|
||||
//~^ ERROR `core::marker::Sync` is not implemented
|
||||
|
||||
let ns = NoSync{m: marker::NoSync};
|
||||
test(ns);
|
||||
test(NoSync);
|
||||
//~^ ERROR `core::marker::Sync` is not implemented
|
||||
}
|
||||
|
@ -19,5 +19,4 @@ fn main() {
|
||||
let i = box Rc::new(100is);
|
||||
f(i);
|
||||
//~^ ERROR `core::marker::Send` is not implemented
|
||||
//~^^ ERROR `core::marker::Send` is not implemented
|
||||
}
|
||||
|
@ -31,6 +31,5 @@ fn main() {
|
||||
let cat = "kitty".to_string();
|
||||
let (tx, _) = channel();
|
||||
//~^ ERROR `core::marker::Send` is not implemented
|
||||
//~^^ ERROR `core::marker::Send` is not implemented
|
||||
tx.send(foo(42, Rc::new(cat)));
|
||||
}
|
||||
|
@ -12,12 +12,8 @@
|
||||
|
||||
// pp-exact
|
||||
|
||||
trait UnsafeTrait {
|
||||
fn foo(&self);
|
||||
}
|
||||
struct Test;
|
||||
|
||||
impl !UnsafeTrait for int {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
impl !Send for Test { }
|
||||
|
||||
pub fn main() { }
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -8,11 +8,12 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker;
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
fn foo<P:Send>(p: P) { }
|
||||
use std::marker::Send;
|
||||
|
||||
fn main()
|
||||
{
|
||||
foo(marker::NoSend); //~ ERROR the trait `core::marker::Send` is not implemented
|
||||
}
|
||||
struct TestType;
|
||||
|
||||
impl !Send for TestType {}
|
||||
|
||||
fn main() {}
|
@ -18,14 +18,12 @@ impl TestType {}
|
||||
|
||||
trait TestTrait {}
|
||||
|
||||
unsafe impl !Send for TestType {}
|
||||
impl !TestTrait for TestType {}
|
||||
impl !Send for TestType {}
|
||||
|
||||
struct TestType2<T>;
|
||||
|
||||
impl<T> TestType2<T> {}
|
||||
|
||||
unsafe impl<T> !Send for TestType2<T> {}
|
||||
impl<T> !TestTrait for TestType2<T> {}
|
||||
impl<T> !Send for TestType2<T> {}
|
||||
|
||||
fn main() {}
|
||||
|
29
src/test/run-pass/traits-negative-impls.rs
Normal file
29
src/test/run-pass/traits-negative-impls.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
use std::marker::Send;
|
||||
|
||||
pub struct WaitToken;
|
||||
impl !Send for WaitToken {}
|
||||
|
||||
pub struct Test<T>(T);
|
||||
unsafe impl<T: 'static> Send for Test<T> {}
|
||||
|
||||
pub fn spawn<F>(_: F) -> () where F: FnOnce(), F: Send + 'static {}
|
||||
|
||||
fn main() {
|
||||
let wt = Test(WaitToken);
|
||||
spawn(move || {
|
||||
let x = wt;
|
||||
println!("Hello, World!");
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user