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:
bors 2015-01-16 13:10:59 +00:00
commit ee2bfae011
42 changed files with 676 additions and 105 deletions

View File

@ -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]

View File

@ -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."]

View File

@ -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

View File

@ -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

View File

@ -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>,

View File

@ -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>)

View File

@ -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()

View File

@ -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))));
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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)

View File

@ -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 */
}
}

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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.

View File

@ -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]

View File

@ -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]

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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() { }

View File

@ -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() {}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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);
});

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View 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`
}

View 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() {}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)));
}

View File

@ -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() { }

View File

@ -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() {}

View File

@ -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() {}

View 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!");
});
}