diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 893c9d250b7..8d8bbb42932 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -117,6 +117,10 @@ pub struct Arc { _ptr: *mut ArcInner, } +unsafe impl Send for Arc { } +unsafe impl Sync for Arc { } + + /// A weak pointer to an `Arc`. /// /// Weak pointers will not keep the data inside of the `Arc` alive, and can be used to break cycles @@ -129,13 +133,19 @@ pub struct Weak { _ptr: *mut ArcInner, } +unsafe impl Send for Weak { } +unsafe impl Sync for Weak { } + struct ArcInner { strong: atomic::AtomicUint, weak: atomic::AtomicUint, data: T, } -impl Arc { +unsafe impl Send for ArcInner {} +unsafe impl Sync for ArcInner {} + +impl Arc { /// Constructs a new `Arc`. /// /// # Examples @@ -587,6 +597,7 @@ mod tests { use std::str::Str; use std::sync::atomic; use std::task; + use std::kinds::Send; use std::vec::Vec; use super::{Arc, Weak, weak_count, strong_count}; use std::sync::Mutex; diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 5fd234192c5..3c6b2d2cbc0 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -19,6 +19,7 @@ use core::hash::{mod, Hash}; use core::kinds::Sized; use core::mem; use core::option::Option; +use core::ptr::Unique; use core::raw::TraitObject; use core::result::Result; use core::result::Result::{Ok, Err}; @@ -44,7 +45,7 @@ pub static HEAP: () = (); /// A type that represents a uniquely-owned value. #[lang = "owned_box"] #[unstable = "custom allocators will add an additional type parameter (with default)"] -pub struct Box(*mut T); +pub struct Box(Unique); #[stable] impl Default for Box { diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index de2a7307440..ee61004d199 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -43,6 +43,8 @@ struct Rawlink { } impl Copy for Rawlink {} +unsafe impl Send for Rawlink {} +unsafe impl Sync for Rawlink {} struct Node { next: Link, diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index fa0e4a2340e..d700b187e8a 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -58,7 +58,7 @@ use core::kinds::marker::{ContravariantLifetime, InvariantType}; use core::mem; use core::num::{Int, UnsignedInt}; use core::ops; -use core::ptr; +use core::ptr::{mod, Unique}; use core::raw::Slice as RawSlice; use core::uint; @@ -133,7 +133,7 @@ use slice::CloneSliceExt; #[unsafe_no_drop_flag] #[stable] pub struct Vec { - ptr: *mut T, + ptr: Unique, len: uint, cap: uint, } @@ -176,7 +176,7 @@ impl Vec { // non-null value which is fine since we never call deallocate on the ptr // if cap is 0. The reason for this is because the pointer of a slice // being NULL would break the null pointer optimization for enums. - Vec { ptr: EMPTY as *mut T, len: 0, cap: 0 } + Vec { ptr: Unique(EMPTY as *mut T), len: 0, cap: 0 } } /// Constructs a new, empty `Vec` with the specified capacity. @@ -209,7 +209,7 @@ impl Vec { #[stable] pub fn with_capacity(capacity: uint) -> Vec { if mem::size_of::() == 0 { - Vec { ptr: EMPTY as *mut T, len: 0, cap: uint::MAX } + Vec { ptr: Unique(EMPTY as *mut T), len: 0, cap: uint::MAX } } else if capacity == 0 { Vec::new() } else { @@ -217,7 +217,7 @@ impl Vec { .expect("capacity overflow"); let ptr = unsafe { allocate(size, mem::min_align_of::()) }; if ptr.is_null() { ::alloc::oom() } - Vec { ptr: ptr as *mut T, len: 0, cap: capacity } + Vec { ptr: Unique(ptr as *mut T), len: 0, cap: capacity } } } @@ -284,7 +284,7 @@ impl Vec { #[unstable = "needs finalization"] pub unsafe fn from_raw_parts(ptr: *mut T, length: uint, capacity: uint) -> Vec { - Vec { ptr: ptr, len: length, cap: capacity } + Vec { ptr: Unique(ptr), len: length, cap: capacity } } /// Creates a vector by copying the elements from a raw pointer. @@ -795,7 +795,7 @@ impl Vec { if self.len == 0 { if self.cap != 0 { unsafe { - dealloc(self.ptr, self.cap) + dealloc(self.ptr.0, self.cap) } self.cap = 0; } @@ -803,11 +803,11 @@ impl Vec { unsafe { // Overflow check is unnecessary as the vector is already at // least this large. - self.ptr = reallocate(self.ptr as *mut u8, - self.cap * mem::size_of::(), - self.len * mem::size_of::(), - mem::min_align_of::()) as *mut T; - if self.ptr.is_null() { ::alloc::oom() } + self.ptr = Unique(reallocate(self.ptr.0 as *mut u8, + self.cap * mem::size_of::(), + self.len * mem::size_of::(), + mem::min_align_of::()) as *mut T); + if self.ptr.0.is_null() { ::alloc::oom() } } self.cap = self.len; } @@ -867,7 +867,7 @@ impl Vec { pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { unsafe { mem::transmute(RawSlice { - data: self.ptr as *const T, + data: self.ptr.0 as *const T, len: self.len, }) } @@ -890,9 +890,9 @@ impl Vec { #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn into_iter(self) -> IntoIter { unsafe { - let ptr = self.ptr; + let ptr = self.ptr.0; let cap = self.cap; - let begin = self.ptr as *const T; + let begin = self.ptr.0 as *const T; let end = if mem::size_of::() == 0 { (ptr as uint + self.len()) as *const T } else { @@ -1110,14 +1110,14 @@ impl Vec { let size = max(old_size, 2 * mem::size_of::()) * 2; if old_size > size { panic!("capacity overflow") } unsafe { - self.ptr = alloc_or_realloc(self.ptr, old_size, size); - if self.ptr.is_null() { ::alloc::oom() } + self.ptr = Unique(alloc_or_realloc(self.ptr.0, old_size, size)); + if self.ptr.0.is_null() { ::alloc::oom() } } self.cap = max(self.cap, 2) * 2; } unsafe { - let end = (self.ptr as *const T).offset(self.len as int) as *mut T; + let end = self.ptr.0.offset(self.len as int); ptr::write(&mut *end, value); self.len += 1; } @@ -1162,11 +1162,11 @@ impl Vec { #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn drain<'a>(&'a mut self) -> Drain<'a, T> { unsafe { - let begin = self.ptr as *const T; + let begin = self.ptr.0 as *const T; let end = if mem::size_of::() == 0 { - (self.ptr as uint + self.len()) as *const T + (self.ptr.0 as uint + self.len()) as *const T } else { - self.ptr.offset(self.len() as int) as *const T + self.ptr.0.offset(self.len() as int) as *const T }; self.set_len(0); Drain { @@ -1231,8 +1231,10 @@ impl Vec { let size = capacity.checked_mul(mem::size_of::()) .expect("capacity overflow"); unsafe { - self.ptr = alloc_or_realloc(self.ptr, self.cap * mem::size_of::(), size); - if self.ptr.is_null() { ::alloc::oom() } + self.ptr = Unique(alloc_or_realloc(self.ptr.0, + self.cap * mem::size_of::(), + size)); + if self.ptr.0.is_null() { ::alloc::oom() } } self.cap = capacity; } @@ -1355,7 +1357,7 @@ impl AsSlice for Vec { fn as_slice<'a>(&'a self) -> &'a [T] { unsafe { mem::transmute(RawSlice { - data: self.ptr as *const T, + data: self.ptr.0 as *const T, len: self.len }) } @@ -1380,7 +1382,7 @@ impl Drop for Vec { for x in self.iter() { ptr::read(x); } - dealloc(self.ptr, self.cap) + dealloc(self.ptr.0, self.cap) } } } @@ -1418,7 +1420,7 @@ impl IntoIter { for _x in self { } let IntoIter { allocation, cap, ptr: _ptr, end: _end } = self; mem::forget(self); - Vec { ptr: allocation, cap: cap, len: 0 } + Vec { ptr: Unique(allocation), cap: cap, len: 0 } } } diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index f6bc4dbde38..9452d0a64bf 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -14,6 +14,8 @@ pub use self::Ordering::*; +use kinds::Sync; + use intrinsics; use cell::UnsafeCell; @@ -23,24 +25,32 @@ pub struct AtomicBool { v: UnsafeCell, } +unsafe impl Sync for AtomicBool {} + /// A signed integer type which can be safely shared between threads. #[stable] pub struct AtomicInt { v: UnsafeCell, } +unsafe impl Sync for AtomicInt {} + /// An unsigned integer type which can be safely shared between threads. #[stable] pub struct AtomicUint { v: UnsafeCell, } +unsafe impl Sync for AtomicUint {} + /// A raw pointer type which can be safely shared between threads. #[stable] pub struct AtomicPtr { p: UnsafeCell, } +unsafe impl Sync for AtomicPtr {} + /// Atomic memory orderings /// /// Memory orderings limit the ways that both the compiler and CPU may reorder diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index b0f46e3d68c..fb030ea45f3 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -19,7 +19,7 @@ /// Types able to be transferred across task boundaries. #[lang="send"] -pub trait Send for Sized? : 'static { +pub unsafe trait Send for Sized? : 'static { // empty. } @@ -81,7 +81,7 @@ pub trait Copy for Sized? { /// reference; not doing this is undefined behaviour (for example, /// `transmute`-ing from `&T` to `&mut T` is illegal). #[lang="sync"] -pub trait Sync for Sized? { +pub unsafe trait Sync for Sized? { // Empty } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b226d4a6de4..8c9d77a0e9c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -92,6 +92,7 @@ use clone::Clone; use intrinsics; use option::Option; use option::Option::{Some, None}; +use kinds::{Send, Sync}; use cmp::{PartialEq, Eq, Ord, PartialOrd, Equiv}; use cmp::Ordering; @@ -501,3 +502,35 @@ impl PartialOrd for *mut T { #[inline] fn ge(&self, other: &*mut T) -> bool { *self >= *other } } + +/// A wrapper around a raw `*mut T` that indicates that the possessor +/// of this wrapper owns the referent. This in turn implies that the +/// `Unique` is `Send`/`Sync` if `T` is `Send`/`Sync`, unlike a +/// raw `*mut T` (which conveys no particular ownership semantics). +/// Useful for building abstractions like `Vec` or `Box`, which +/// internally use raw pointers to manage the memory that they own. +pub struct Unique(pub *mut T); + +/// `Unique` pointers are `Send` if `T` is `Send` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +unsafe impl Send for Unique { } + +/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +unsafe impl Sync for Unique { } + +impl Unique { + /// Returns a null Unique. + pub fn null() -> Unique { + Unique(RawPtr::null()) + } + + /// Return an (unsafe) pointer into the memory owned by `self`. + pub unsafe fn offset(self, offset: int) -> *mut T { + (self.0 as *const T).offset(offset) as *mut T + } +} diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index 2c8e5638e49..8c4f74027a5 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -27,8 +27,9 @@ extern crate libc; -use std::c_vec::CVec; use libc::{c_void, size_t, c_int}; +use std::c_vec::CVec; +use std::ptr::Unique; #[link(name = "miniz", kind = "static")] extern { @@ -59,7 +60,8 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - Some(CVec::new_with_dtor(res as *mut u8, outsz as uint, move|:| libc::free(res))) + let res = Unique(res); + Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) } else { None } @@ -84,7 +86,8 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - Some(CVec::new_with_dtor(res as *mut u8, outsz as uint, move|:| libc::free(res))) + let res = Unique(res); + Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) } else { None } diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 4c3cb99f64d..1ea79bdf606 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -67,5 +67,6 @@ register_diagnostics! { E0173, E0174, E0177, - E0178 + E0178, + E0179 } diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 6ff34d62500..14f927f5b1e 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -31,6 +31,7 @@ use middle::infer; use middle::traits; use middle::mem_categorization as mc; use middle::expr_use_visitor as euv; +use util::common::ErrorReported; use util::nodemap::NodeSet; use syntax::ast; @@ -119,12 +120,19 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> { let ty = ty::node_id_to_type(self.tcx, e.id); let infcx = infer::new_infer_ctxt(self.tcx); let mut fulfill_cx = traits::FulfillmentContext::new(); - fulfill_cx.register_builtin_bound(self.tcx, ty, ty::BoundSync, - traits::ObligationCause::dummy()); - let env = ty::empty_parameter_environment(); - if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() { - self.tcx.sess.span_err(e.span, "shared static items must have a \ - type which implements Sync"); + match traits::poly_trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) { + Ok(trait_ref) => { + let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic); + fulfill_cx.register_trait_ref(self.tcx, trait_ref, cause); + let env = ty::empty_parameter_environment(); + match fulfill_cx.select_all_or_error(&infcx, &env, self.tcx) { + Ok(()) => { }, + Err(ref errors) => { + traits::report_fulfillment_errors(&infcx, errors); + } + } + } + Err(ErrorReported) => { } } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 9f7472c2c73..87b378d579c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -113,7 +113,7 @@ pub struct Upvar { // different kinds of pointers: #[deriving(Clone, Copy, PartialEq, Eq, Hash, Show)] pub enum PointerKind { - OwnedPtr, + Unique, BorrowedPtr(ty::BorrowKind, ty::Region), Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr. UnsafePtr(ast::Mutability) @@ -199,7 +199,7 @@ pub fn opt_deref_kind(t: Ty) -> Option { match t.sty { ty::ty_uniq(_) | ty::ty_closure(box ty::ClosureTy {store: ty::UniqTraitStore, ..}) => { - Some(deref_ptr(OwnedPtr)) + Some(deref_ptr(Unique)) } ty::ty_rptr(r, mt) => { @@ -316,7 +316,7 @@ impl MutabilityCategory { pub fn from_pointer_kind(base_mutbl: MutabilityCategory, ptr: PointerKind) -> MutabilityCategory { match ptr { - OwnedPtr => { + Unique => { base_mutbl.inherit() } BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => { @@ -1339,7 +1339,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { Implicit(..) => { "dereference (dereference is implicit, due to indexing)".to_string() } - OwnedPtr => format!("dereference of `{}`", ptr_sigil(pk)), + Unique => format!("dereference of `{}`", ptr_sigil(pk)), _ => format!("dereference of `{}`-pointer", ptr_sigil(pk)) } } @@ -1400,7 +1400,7 @@ impl<'tcx> cmt_<'tcx> { } cat_downcast(ref b, _) | cat_interior(ref b, _) | - cat_deref(ref b, _, OwnedPtr) => { + cat_deref(ref b, _, Unique) => { b.guarantor() } } @@ -1419,7 +1419,7 @@ impl<'tcx> cmt_<'tcx> { cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) | cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) | cat_downcast(ref b, _) | - cat_deref(ref b, _, OwnedPtr) | + cat_deref(ref b, _, Unique) | cat_interior(ref b, _) => { // Aliasability depends on base cmt b.freely_aliasable(ctxt) @@ -1511,7 +1511,7 @@ impl<'tcx> Repr<'tcx> for categorization<'tcx> { pub fn ptr_sigil(ptr: PointerKind) -> &'static str { match ptr { - OwnedPtr => "Box", + Unique => "Box", BorrowedPtr(ty::ImmBorrow, _) | Implicit(ty::ImmBorrow, _) => "&", BorrowedPtr(ty::MutBorrow, _) | diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs new file mode 100644 index 00000000000..462857de1d4 --- /dev/null +++ b/src/librustc/middle/traits/error_reporting.rs @@ -0,0 +1,349 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::{FulfillmentError, FulfillmentErrorCode, + ObligationCauseCode, SelectionError, + PredicateObligation, OutputTypeParameterMismatch}; + +use middle::infer::InferCtxt; +use middle::ty::{mod}; +use syntax::codemap::Span; +use util::ppaux::{Repr, UserString}; + +pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + errors: &Vec>) { + for error in errors.iter() { + report_fulfillment_error(infcx, error); + } +} + +fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + error: &FulfillmentError<'tcx>) { + match error.code { + FulfillmentErrorCode::CodeSelectionError(ref e) => { + report_selection_error(infcx, &error.obligation, e); + } + FulfillmentErrorCode::CodeAmbiguity => { + maybe_report_ambiguity(infcx, &error.obligation); + } + } +} + +pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &PredicateObligation<'tcx>, + error: &SelectionError<'tcx>) +{ + match *error { + SelectionError::Overflow => { + // We could track the stack here more precisely if we wanted, I imagine. + match obligation.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + let trait_ref = + infcx.resolve_type_vars_if_possible(&**trait_ref); + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "overflow evaluating the trait `{}` for the type `{}`", + trait_ref.user_string(infcx.tcx), + trait_ref.self_ty().user_string(infcx.tcx))[]); + } + + ty::Predicate::Equate(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.equality_predicate(obligation.cause.span, + &predicate).unwrap_err(); + + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(infcx.tcx), + ty::type_err_to_str(infcx.tcx, &err)).as_slice()); + } + + ty::Predicate::TypeOutlives(..) | + ty::Predicate::RegionOutlives(..) => { + infcx.tcx.sess.span_err( + obligation.cause.span, + format!("overflow evaluating lifetime predicate").as_slice()); + } + } + + let current_limit = infcx.tcx.sess.recursion_limit.get(); + let suggested_limit = current_limit * 2; + infcx.tcx.sess.span_note( + obligation.cause.span, + format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)[]); + + note_obligation_cause(infcx, obligation); + } + SelectionError::Unimplemented => { + match obligation.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + let trait_ref = + infcx.resolve_type_vars_if_possible( + &**trait_ref); + if !ty::type_is_error(trait_ref.self_ty()) { + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "the trait `{}` is not implemented for the type `{}`", + trait_ref.user_string(infcx.tcx), + trait_ref.self_ty().user_string(infcx.tcx)).as_slice()); + note_obligation_cause(infcx, obligation); + } + } + + ty::Predicate::Equate(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.equality_predicate(obligation.cause.span, + &predicate).unwrap_err(); + + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(infcx.tcx), + ty::type_err_to_str(infcx.tcx, &err)).as_slice()); + } + + ty::Predicate::TypeOutlives(..) | + ty::Predicate::RegionOutlives(..) => { + let predicate = infcx.resolve_type_vars_if_possible(&obligation.trait_ref); + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "the requirement `{}` is not satisfied", + predicate.user_string(infcx.tcx)).as_slice()); + } + } + } + OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { + let expected_trait_ref = + infcx.resolve_type_vars_if_possible( + &**expected_trait_ref); + let actual_trait_ref = + infcx.resolve_type_vars_if_possible( + &**actual_trait_ref); + if !ty::type_is_error(actual_trait_ref.self_ty()) { + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + expected_trait_ref.self_ty().user_string(infcx.tcx), + expected_trait_ref.user_string(infcx.tcx), + actual_trait_ref.user_string(infcx.tcx), + ty::type_err_to_str(infcx.tcx, e)).as_slice()); + note_obligation_cause(infcx, obligation); + } + } + } +} + +fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &PredicateObligation<'tcx>) { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + + let trait_ref = match obligation.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + infcx.resolve_type_vars_if_possible(&**trait_ref) + } + _ => { + infcx.tcx.sess.span_bug( + obligation.cause.span, + format!("ambiguity from something other than a trait: {}", + obligation.trait_ref.repr(infcx.tcx)).as_slice()); + } + }; + let self_ty = trait_ref.self_ty(); + + debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})", + trait_ref.repr(infcx.tcx), + self_ty.repr(infcx.tcx), + obligation.repr(infcx.tcx)); + let all_types = &trait_ref.substs().types; + if all_types.iter().any(|&t| ty::type_is_error(t)) { + } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { + // This is kind of a hack: it frequently happens that some earlier + // error prevents types from being fully inferred, and then we get + // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we + // could just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might be an + // inference variable created, registered as an obligation, and + // then never forced by writeback, and hence by skipping here we'd + // be ignoring the fact that we don't KNOW the type works + // out. Though even that would probably be harmless, given that + // we're only talking about builtin traits, which are known to be + // inhabited. But in any case I just threw in this check for + // has_errors() to be sure that compilation isn't happening + // anyway. In that case, why inundate the user. + if !infcx.tcx.sess.has_errors() { + if infcx.tcx.lang_items.sized_trait() + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "unable to infer enough type information about `{}`; type annotations \ + required", + self_ty.user_string(infcx.tcx)).as_slice()); + } else { + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "unable to infer enough type information to \ + locate the impl of the trait `{}` for \ + the type `{}`; type annotations required", + trait_ref.user_string(infcx.tcx), + self_ty.user_string(infcx.tcx))[]); + note_obligation_cause(infcx, obligation); + } + } + } else if !infcx.tcx.sess.has_errors() { + // Ambiguity. Coherence should have reported an error. + infcx.tcx.sess.span_bug( + obligation.cause.span, + format!( + "coherence failed to report ambiguity: \ + cannot locate the impl of the trait `{}` for \ + the type `{}`", + trait_ref.user_string(infcx.tcx), + self_ty.user_string(infcx.tcx))[]); + } +} + +fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &PredicateObligation<'tcx>) +{ + let trait_ref = match obligation.trait_ref { + ty::Predicate::Trait(ref trait_ref) => { + infcx.resolve_type_vars_if_possible(&**trait_ref) + } + _ => { + infcx.tcx.sess.span_bug( + obligation.cause.span, + format!("ambiguity from something other than a trait: {}", + obligation.trait_ref.repr(infcx.tcx)).as_slice()); + } + }; + + note_obligation_cause_code(infcx, + &trait_ref, + obligation.cause.span, + &obligation.cause.code) +} + +fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + cause_span: Span, + cause_code: &ObligationCauseCode<'tcx>) +{ + let tcx = infcx.tcx; + let trait_name = ty::item_path_str(tcx, trait_ref.def_id()); + match *cause_code { + ObligationCauseCode::MiscObligation => { } + ObligationCauseCode::ItemObligation(item_def_id) => { + let item_name = ty::item_path_str(tcx, item_def_id); + tcx.sess.span_note( + cause_span, + format!( + "the trait `{}` must be implemented because it is required by `{}`", + trait_name, + item_name).as_slice()); + } + ObligationCauseCode::ObjectCastObligation(object_ty) => { + tcx.sess.span_note( + cause_span, + format!( + "the trait `{}` must be implemented for the cast \ + to the object type `{}`", + trait_name, + infcx.ty_to_string(object_ty)).as_slice()); + } + ObligationCauseCode::RepeatVec => { + tcx.sess.span_note( + cause_span, + "the `Copy` trait is required because the \ + repeated element will be copied"); + } + ObligationCauseCode::VariableType(_) => { + tcx.sess.span_note( + cause_span, + "all local variables must have a statically known size"); + } + ObligationCauseCode::ReturnType => { + tcx.sess.span_note( + cause_span, + "the return type of a function must have a \ + statically known size"); + } + ObligationCauseCode::AssignmentLhsSized => { + tcx.sess.span_note( + cause_span, + "the left-hand-side of an assignment must have a statically known size"); + } + ObligationCauseCode::StructInitializerSized => { + tcx.sess.span_note( + cause_span, + "structs must have a statically known size to be initialized"); + } + ObligationCauseCode::ClosureCapture(var_id, closure_span, builtin_bound) => { + let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); + let trait_name = ty::item_path_str(tcx, def_id); + let name = ty::local_var_name_str(tcx, var_id); + span_note!(tcx.sess, closure_span, + "the closure that captures `{}` requires that all captured variables \ + implement the trait `{}`", + name, + trait_name); + } + ObligationCauseCode::FieldSized => { + span_note!(tcx.sess, cause_span, + "only the last field of a struct or enum variant \ + may have a dynamically sized type") + } + ObligationCauseCode::ObjectSized => { + span_note!(tcx.sess, cause_span, + "only sized types can be made into objects"); + } + ObligationCauseCode::SharedStatic => { + span_note!(tcx.sess, cause_span, + "shared static variables must have a type that implements `Sync`"); + } + ObligationCauseCode::BuiltinDerivedObligation(ref root_trait_ref, ref root_cause_code) => { + let root_trait_ref = + infcx.resolve_type_vars_if_possible(&**root_trait_ref); + span_note!(tcx.sess, cause_span, + "the type `{}` must implement `{}` because it appears within the type `{}`", + trait_ref.self_ty().user_string(infcx.tcx), + trait_ref.user_string(infcx.tcx), + root_trait_ref.self_ty().user_string(infcx.tcx)); + note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code); + } + ObligationCauseCode::ImplDerivedObligation(ref root_trait_ref, ref root_cause_code) => { + let root_trait_ref = + infcx.resolve_type_vars_if_possible(&**root_trait_ref); + span_note!(tcx.sess, cause_span, + "the type `{}` must implement `{}` due to the requirements \ + on the impl of `{}` for the type `{}`", + trait_ref.self_ty().user_string(infcx.tcx), + trait_ref.user_string(infcx.tcx), + root_trait_ref.user_string(infcx.tcx), + root_trait_ref.self_ty().user_string(infcx.tcx)); + note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code); + } + } +} diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 72e4eb5d1d6..e9e80ed8c18 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -305,7 +305,7 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, let tcx = selcx.tcx(); match predicate.trait_ref { ty::Predicate::Trait(ref trait_ref) => { - let trait_obligation = Obligation { cause: predicate.cause, + let trait_obligation = Obligation { cause: predicate.cause.clone(), recursion_depth: predicate.recursion_depth, trait_ref: trait_ref.clone() }; match selcx.select(&trait_obligation) { @@ -368,7 +368,9 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, CodeSelectionError(Unimplemented))); } else { let ty::OutlivesPredicate(t_a, r_b) = binder.0; - register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + register_region_obligation(tcx, t_a, r_b, + predicate.cause.clone(), + region_obligations); } true } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 8028971a463..6597730846d 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -23,6 +23,7 @@ use std::slice::Iter; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; +pub use self::error_reporting::report_fulfillment_errors; pub use self::fulfill::{FulfillmentContext, RegionObligation}; pub use self::select::SelectionContext; pub use self::select::SelectionCache; @@ -36,6 +37,7 @@ pub use self::util::transitive_bounds; pub use self::util::poly_trait_ref_for_builtin_bound; mod coherence; +mod error_reporting; mod fulfill; mod select; mod util; @@ -57,7 +59,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; /// Why did we incur this obligation? Used for error reporting. -#[deriving(Copy, Clone)] +#[deriving(Clone)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -72,7 +74,7 @@ pub struct ObligationCause<'tcx> { pub code: ObligationCauseCode<'tcx> } -#[deriving(Copy, Clone)] +#[deriving(Clone)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, @@ -84,9 +86,6 @@ pub enum ObligationCauseCode<'tcx> { /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ Ty<'tcx>), - /// To implement drop, type must be sendable. - DropTrait, - /// Various cases where expressions must be sized/copy/etc: AssignmentLhsSized, // L = X implies that L is Sized StructInitializerSized, // S { ... } must be Sized @@ -103,6 +102,13 @@ pub enum ObligationCauseCode<'tcx> { // Only Sized types can be made into objects ObjectSized, + + // static items must have `Sync` type + SharedStatic, + + BuiltinDerivedObligation(Rc>, Rc>), + + ImplDerivedObligation(Rc>, Rc>), } pub type Obligations<'tcx, O> = subst::VecPerParamSpace>; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 5ee6dec7830..42b753927d5 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -18,6 +18,7 @@ use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause}; +use super::{ObligationCauseCode, BuiltinDerivedObligation}; use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; use super::{Selection}; use super::{SelectionResult}; @@ -256,7 +257,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let obligation = util::predicate_for_builtin_bound( self.tcx(), - previous_stack.obligation.cause, + previous_stack.obligation.cause.clone(), bound, previous_stack.obligation.recursion_depth + 1, ty); @@ -416,7 +417,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(substs) => { let vtable_impl = self.vtable_impl(impl_def_id, substs, - obligation.cause, + obligation.cause.clone(), obligation.recursion_depth + 1, skol_map, snapshot); @@ -663,13 +664,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // behavior, ignore user-defined impls here. This will // go away by the time 1.0 is released. if !self.tcx().sess.features.borrow().opt_out_copy { - try!(self.assemble_candidates_from_impls(obligation, &mut candidates)); + try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec)); } try!(self.assemble_builtin_bound_candidates(ty::BoundCopy, stack, &mut candidates)); } + Some(bound @ ty::BoundSend) | + Some(bound @ ty::BoundSync) => { + try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec)); + + // No explicit impls were declared for this type, consider the fallback rules. + if candidates.vec.is_empty() { + try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates)); + } + } + + Some(bound @ ty::BoundSized) => { + // Sized and Copy are always automatically computed. + try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates)); + } None => { // For the time being, we ignore user-defined impls for builtin-bounds, other than @@ -677,11 +692,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)); - } - - Some(bound) => { - try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates)); + try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec)); } } @@ -816,7 +827,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Search for impls that might apply to `obligation`. fn assemble_candidates_from_impls(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut CandidateSet<'tcx>) + candidate_vec: &mut Vec>) -> Result<(), SelectionError<'tcx>> { let all_impls = self.all_impls(obligation.trait_ref.def_id()); @@ -827,7 +838,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.match_impl(impl_def_id, obligation, snapshot, &skol_map, Rc::new(skol_obligation_trait_ref)) { Ok(_) => { - candidates.vec.push(ImplCandidate(impl_def_id)); + candidate_vec.push(ImplCandidate(impl_def_id)); } Err(()) => { } } @@ -1007,7 +1018,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::ty_ptr(ty::mt { ty: referent_ty, .. }) => { // *const T, *mut T + ty::ty_ptr(..) => { // *const T, *mut T match bound { ty::BoundCopy | ty::BoundSized => { @@ -1016,7 +1027,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundSync | ty::BoundSend => { - Ok(If(vec![referent_ty])) + // sync and send are not implemented for *const, *mut + Err(Unimplemented) } } } @@ -1323,16 +1335,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundSync => { if Some(def_id) == tcx.lang_items.no_sync_bound() || - Some(def_id) == tcx.lang_items.managed_bound() - { - return Err(Unimplemented) - } else if + Some(def_id) == tcx.lang_items.managed_bound() || Some(def_id) == tcx.lang_items.unsafe_type() { - // FIXME(#13231) -- we currently consider `UnsafeCell` - // to always be sync. This is allow for types like `Queue` - // and `Mutex`, where `Queue : Sync` is `T : Send`. - return Ok(If(Vec::new())); + return Err(Unimplemented) } } @@ -1407,7 +1413,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // where-clause trait-ref could be unified with the obligation // trait-ref. Repeat that unification now without any // transactional boundary; it should not fail. - match self.confirm_poly_trait_refs(obligation.cause, + match self.confirm_poly_trait_refs(obligation.cause.clone(), obligation.trait_ref.clone(), param.bound.clone()) { Ok(()) => Ok(param), @@ -1446,10 +1452,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested: Vec>) -> VtableBuiltinData> { + let derived_cause = self.derived_cause(obligation, BuiltinDerivedObligation); let obligations = nested.iter().map(|&t| { util::predicate_for_builtin_bound( self.tcx(), - obligation.cause, + derived_cause.clone(), bound, obligation.recursion_depth + 1, t) @@ -1462,7 +1469,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // as a special case, `Send` requires `'static` if bound == ty::BoundSend { obligations.push(Obligation { - cause: obligation.cause, + cause: obligation.cause.clone(), recursion_depth: obligation.recursion_depth+1, trait_ref: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(), ty::ReStatic)).as_predicate(), @@ -1496,7 +1503,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let substs = self.rematch_impl(impl_def_id, obligation, snapshot, &skol_map, Rc::new(skol_obligation_trait_ref)); debug!("confirm_impl_candidate substs={}", substs); - Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, + Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(), obligation.recursion_depth + 1, skol_map, snapshot)) }) } @@ -1570,10 +1577,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs: substs, })); - try!(self.confirm_poly_trait_refs(obligation.cause, + try!(self.confirm_poly_trait_refs(obligation.cause.clone(), obligation.trait_ref.clone(), trait_ref)); - Ok(self_ty) } @@ -1616,7 +1622,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { closure_def_id.repr(self.tcx()), trait_ref.repr(self.tcx())); - self.confirm_poly_trait_refs(obligation.cause, + self.confirm_poly_trait_refs(obligation.cause.clone(), obligation.trait_ref.clone(), trait_ref) } @@ -1808,7 +1814,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// back `Ok(T=int)`. fn match_inherent_impl(&mut self, impl_def_id: ast::DefId, - obligation_cause: ObligationCause, + obligation_cause: &ObligationCause, obligation_self_ty: Ty<'tcx>) -> Result,()> { @@ -1841,7 +1847,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn match_self_types(&mut self, - cause: ObligationCause, + cause: &ObligationCause, // The self type provided by the impl/caller-obligation: provided_self_ty: Ty<'tcx>, @@ -1920,6 +1926,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None } } + + #[allow(unused_comparisons)] + fn derived_cause(&self, + obligation: &TraitObligation<'tcx>, + variant: fn(Rc>>, + Rc>) + -> ObligationCauseCode<'tcx>) + -> ObligationCause<'tcx> + { + /*! + * Creates a cause for obligations that are derived from + * `obligation` by a recursive search (e.g., for a builtin + * bound, or eventually a `impl Foo for ..`). If `obligation` + * is itself a derived obligation, this is just a clone, but + * otherwise we create a "derived obligation" cause so as to + * keep track of the original root obligation for error + * reporting. + */ + + // NOTE(flaper87): As of now, it keeps track of the whole error + // chain. Ideally, we should have a way to configure this either + // by using -Z verbose or just a CLI argument. + if obligation.recursion_depth >= 0 { + ObligationCause::new(obligation.cause.span, + obligation.trait_ref.def_id().node, + variant(obligation.trait_ref.clone(), + Rc::new(obligation.cause.code.clone()))) + } else { + obligation.cause.clone() + } + } } impl<'tcx> Repr<'tcx> for Candidate<'tcx> { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 27824ba5c6e..0864b21870d 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -260,7 +260,7 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, generic_bounds.repr(tcx)); generic_bounds.predicates.map(|predicate| { - Obligation { cause: cause, + Obligation { cause: cause.clone(), recursion_depth: recursion_depth, trait_ref: predicate.clone() } }) diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index a35ea30b217..b7cde762a84 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -439,7 +439,7 @@ impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O> { fn fold_with>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> { traits::Obligation { - cause: self.cause, + cause: self.cause.clone(), recursion_depth: self.recursion_depth, trait_ref: self.trait_ref.fold_with(folder), } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 046b9547cbb..fdb13ecabde 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -31,11 +31,11 @@ use std::rc::Rc; // FIXME (#16118): These functions are intended to allow the borrow checker to // be less precise in its handling of Box while still allowing moves out of a -// Box. They should be removed when OwnedPtr is removed from LoanPath. +// Box. They should be removed when Unique is removed from LoanPath. fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath<'tcx> { - //! Returns the base of the leftmost dereference of an OwnedPtr in - //! `loan_path`. If there is no dereference of an OwnedPtr in `loan_path`, + //! Returns the base of the leftmost dereference of an Unique in + //! `loan_path`. If there is no dereference of an Unique in `loan_path`, //! then it just returns `loan_path` itself. return match helper(loan_path) { @@ -46,7 +46,7 @@ fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath< fn helper<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> Option<&'a LoanPath<'tcx>> { match loan_path.kind { LpVar(_) | LpUpvar(_) => None, - LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) => { + LpExtend(ref lp_base, _, LpDeref(mc::Unique)) => { match helper(&**lp_base) { v @ Some(_) => v, None => Some(&**lp_base) @@ -70,7 +70,7 @@ fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc>) -> Rc(loan_path: &Rc>) -> Option>> { match loan_path.kind { LpVar(_) | LpUpvar(_) => None, - LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) => { + LpExtend(ref lp_base, _, LpDeref(mc::Unique)) => { match helper(lp_base) { v @ Some(_) => v, None => Some(lp_base.clone()) @@ -878,7 +878,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } } - mc::cat_deref(b, _, mc::OwnedPtr) => { + mc::cat_deref(b, _, mc::Unique) => { assert_eq!(cmt.mutbl, mc::McInherited); cmt = b; } diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index dbbc52cf362..ef9130bb607 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -291,9 +291,9 @@ fn add_fragment_siblings<'tcx>(this: &MoveData<'tcx>, add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id); } - // *LV for OwnedPtr consumes the contents of the box (at + // *LV for Unique consumes the contents of the box (at // least when it is non-copy...), so propagate inward. - LpExtend(ref loan_parent, _, LpDeref(mc::OwnedPtr)) => { + LpExtend(ref loan_parent, _, LpDeref(mc::Unique)) => { add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id); } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 85cc691fb9d..6f02f447a15 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -189,7 +189,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, } } - mc::cat_deref(ref b, _, mc::OwnedPtr) => { + mc::cat_deref(ref b, _, mc::Unique) => { check_and_get_illegal_move_origin(bccx, b) } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index d7c96346463..1c57097ae26 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -84,7 +84,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } mc::cat_downcast(ref base, _) | - mc::cat_deref(ref base, _, mc::OwnedPtr) | // L-Deref-Send + mc::cat_deref(ref base, _, mc::Unique) | // L-Deref-Send mc::cat_interior(ref base, _) => { // L-Field self.check(base, discr_scope) } @@ -129,7 +129,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { r } mc::cat_downcast(ref cmt, _) | - mc::cat_deref(ref cmt, _, mc::OwnedPtr) | + mc::cat_deref(ref cmt, _, mc::Unique) | mc::cat_interior(ref cmt, _) => { self.scope(cmt) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index fc15c0eb4ec..b3fb7123ef3 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { mc::cat_deref(cmt_base, _, pk) => { match pk { - mc::OwnedPtr => { + mc::Unique => { // R-Deref-Send-Pointer // // When we borrow the interior of an owned pointer, we diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 5be66d42920..513b955da3f 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -281,6 +281,8 @@ struct ModuleConfig { time_passes: bool, } +unsafe impl Send for ModuleConfig { } + impl ModuleConfig { fn new(tm: TargetMachineRef, passes: Vec) -> ModuleConfig { ModuleConfig { diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index f829a8ec248..640e83469b2 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -216,32 +216,32 @@ use syntax::{ast, codemap, ast_util, ast_map}; use syntax::ast_util::PostExpansionMethod; use syntax::parse::token::{mod, special_idents}; -static DW_LANG_RUST: c_uint = 0x9000; +const DW_LANG_RUST: c_uint = 0x9000; #[allow(non_upper_case_globals)] -static DW_TAG_auto_variable: c_uint = 0x100; +const DW_TAG_auto_variable: c_uint = 0x100; #[allow(non_upper_case_globals)] -static DW_TAG_arg_variable: c_uint = 0x101; +const DW_TAG_arg_variable: c_uint = 0x101; #[allow(non_upper_case_globals)] -static DW_ATE_boolean: c_uint = 0x02; +const DW_ATE_boolean: c_uint = 0x02; #[allow(non_upper_case_globals)] -static DW_ATE_float: c_uint = 0x04; +const DW_ATE_float: c_uint = 0x04; #[allow(non_upper_case_globals)] -static DW_ATE_signed: c_uint = 0x05; +const DW_ATE_signed: c_uint = 0x05; #[allow(non_upper_case_globals)] -static DW_ATE_unsigned: c_uint = 0x07; +const DW_ATE_unsigned: c_uint = 0x07; #[allow(non_upper_case_globals)] -static DW_ATE_unsigned_char: c_uint = 0x08; +const DW_ATE_unsigned_char: c_uint = 0x08; -static UNKNOWN_LINE_NUMBER: c_uint = 0; -static UNKNOWN_COLUMN_NUMBER: c_uint = 0; +const UNKNOWN_LINE_NUMBER: c_uint = 0; +const UNKNOWN_COLUMN_NUMBER: c_uint = 0; // ptr::null() doesn't work :( -static UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile); -static UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope); +const UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile); +const UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope); -static FLAGS_NONE: c_uint = 0; +const FLAGS_NONE: c_uint = 0; //=----------------------------------------------------------------------------- // Public Interface of debuginfo module diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index 4b1b92b552c..c53e164fb07 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -60,6 +60,9 @@ pub struct ModuleTranslation { pub llmod: ModuleRef, } +unsafe impl Send for ModuleTranslation { } +unsafe impl Sync for ModuleTranslation { } + pub struct CrateTranslation { pub modules: Vec, pub metadata_module: ModuleTranslation, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 429eee87026..e17cf81baa8 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1403,7 +1403,7 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, } mc::cat_downcast(cmt_base, _) | - mc::cat_deref(cmt_base, _, mc::OwnedPtr) | + mc::cat_deref(cmt_base, _, mc::Unique) | mc::cat_interior(cmt_base, _) => { // Borrowing interior or owned data requires the base // to be valid and borrowable in the same fashion. @@ -1627,7 +1627,7 @@ fn adjust_upvar_borrow_kind_for_mut<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, cmt.repr(rcx.tcx())); match cmt.cat.clone() { - mc::cat_deref(base, _, mc::OwnedPtr) | + mc::cat_deref(base, _, mc::Unique) | mc::cat_interior(base, _) | mc::cat_downcast(base, _) => { // Interior or owned data is mutable if base is @@ -1674,7 +1674,7 @@ fn adjust_upvar_borrow_kind_for_unique<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, cmt: mc::c cmt.repr(rcx.tcx())); match cmt.cat.clone() { - mc::cat_deref(base, _, mc::OwnedPtr) | + mc::cat_deref(base, _, mc::Unique) | mc::cat_interior(base, _) | mc::cat_downcast(base, _) => { // Interior or owned data is unique if base is diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index e23bf46b564..7ebf39e2e9a 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -11,16 +11,14 @@ use check::{FnCtxt, structurally_resolved_type}; use middle::subst::{FnSpace}; use middle::traits; -use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; use middle::traits::{Obligation, ObligationCause}; -use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity}; -use middle::traits::{PredicateObligation}; +use middle::traits::report_fulfillment_errors; use middle::ty::{mod, Ty}; use middle::infer; use std::rc::Rc; use syntax::ast; use syntax::codemap::Span; -use util::ppaux::{UserString, Repr, ty_to_string}; +use util::ppaux::{Repr, ty_to_string}; pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast_expr: &ast::Expr, @@ -285,199 +283,7 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { fcx); match r { Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx, &errors); } - } -} - -pub fn report_fulfillment_errors<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - errors: &Vec>) { - for error in errors.iter() { - report_fulfillment_error(fcx, error); - } -} - -pub fn report_fulfillment_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - error: &FulfillmentError<'tcx>) { - match error.code { - CodeSelectionError(ref e) => { - report_selection_error(fcx, &error.obligation, e); - } - CodeAmbiguity => { - maybe_report_ambiguity(fcx, &error.obligation); - } - } -} - -pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>) -{ - match *error { - Overflow => { - // We could track the stack here more precisely if we wanted, I imagine. - let predicate = - fcx.infcx().resolve_type_vars_if_possible(&obligation.trait_ref); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow evaluating the requirement `{}`", - predicate.user_string(fcx.tcx())).as_slice()); - - let current_limit = fcx.tcx().sess.recursion_limit.get(); - let suggested_limit = current_limit * 2; - fcx.tcx().sess.span_note( - obligation.cause.span, - format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)[]); - - note_obligation_cause(fcx, obligation); - } - Unimplemented => { - match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = fcx.infcx().resolve_type_vars_if_possible(&**trait_ref); - if !ty::type_is_error(trait_ref.self_ty()) { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "the trait `{}` is not implemented for the type `{}`", - trait_ref.user_string(fcx.tcx()), - trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); - } - } - - ty::Predicate::Equate(ref predicate) => { - let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); - let err = fcx.infcx().equality_predicate(obligation.cause.span, - &predicate).unwrap_err(); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "the requirement `{}` is not satisfied (`{}`)", - predicate.user_string(fcx.tcx()), - ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); - } - - ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); - let err = fcx.infcx().region_outlives_predicate(obligation.cause.span, - &predicate).unwrap_err(); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "the requirement `{}` is not satisfied (`{}`)", - predicate.user_string(fcx.tcx()), - ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); - } - - ty::Predicate::TypeOutlives(ref predicate) => { - let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "the requirement `{}` is not satisfied", - predicate.user_string(fcx.tcx())).as_slice()); - } - } - - note_obligation_cause(fcx, obligation); - } - OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { - let expected_trait_ref = - fcx.infcx().resolve_type_vars_if_possible( - &**expected_trait_ref); - let actual_trait_ref = - fcx.infcx().resolve_type_vars_if_possible( - &**actual_trait_ref); - if !ty::type_is_error(actual_trait_ref.self_ty()) { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - expected_trait_ref.self_ty().user_string(fcx.tcx()), - expected_trait_ref.user_string(fcx.tcx()), - actual_trait_ref.user_string(fcx.tcx()), - ty::type_err_to_str(fcx.tcx(), e)).as_slice()); - note_obligation_cause(fcx, obligation); - } - } - } -} - -pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &PredicateObligation<'tcx>) { - // Unable to successfully determine, probably means - // insufficient type information, but could mean - // ambiguous impls. The latter *ought* to be a - // coherence violation, so we don't report it here. - - let trait_ref = match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - fcx.infcx().resolve_type_vars_if_possible(&**trait_ref) - } - _ => { - fcx.tcx().sess.span_bug( - obligation.cause.span, - format!("ambiguity from something other than a trait: {}", - obligation.trait_ref.repr(fcx.tcx())).as_slice()); - } - }; - let self_ty = trait_ref.self_ty(); - - debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})", - trait_ref.repr(fcx.tcx()), - self_ty.repr(fcx.tcx()), - obligation.repr(fcx.tcx())); - let all_types = &trait_ref.substs().types; - if all_types.iter().any(|&t| ty::type_is_error(t)) { - } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { - // This is kind of a hack: it frequently happens that some earlier - // error prevents types from being fully inferred, and then we get - // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we - // could just skip over all checks where the self-ty is an - // inference variable, but I was afraid that there might be an - // inference variable created, registered as an obligation, and - // then never forced by writeback, and hence by skipping here we'd - // be ignoring the fact that we don't KNOW the type works - // out. Though even that would probably be harmless, given that - // we're only talking about builtin traits, which are known to be - // inhabited. But in any case I just threw in this check for - // has_errors() to be sure that compilation isn't happening - // anyway. In that case, why inundate the user. - if !fcx.tcx().sess.has_errors() { - if fcx.ccx.tcx.lang_items.sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "unable to infer enough type information about `{}`; type annotations \ - required", - self_ty.user_string(fcx.tcx()))[]); - } else { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "unable to infer enough type information to \ - locate the impl of the trait `{}` for \ - the type `{}`; type annotations required", - trait_ref.user_string(fcx.tcx()), - self_ty.user_string(fcx.tcx()))[]); - note_obligation_cause(fcx, obligation); - } - } - } else if !fcx.tcx().sess.has_errors() { - // Ambiguity. Coherence should have reported an error. - fcx.tcx().sess.span_bug( - obligation.cause.span, - format!( - "coherence failed to report ambiguity: \ - cannot locate the impl of the trait `{}` for \ - the type `{}`", - trait_ref.user_string(fcx.tcx()), - self_ty.user_string(fcx.tcx()))[]); + Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } } } @@ -490,7 +296,7 @@ pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) .select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx) { Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx, &errors); } + Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } } } @@ -504,83 +310,6 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) { .select_new_obligations(fcx.infcx(), &fcx.inh.param_env, fcx) { Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx, &errors); } - } -} - -fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - obligation: &PredicateObligation<'tcx>) { - let tcx = fcx.tcx(); - match obligation.cause.code { - traits::MiscObligation => { } - traits::ItemObligation(item_def_id) => { - let item_name = ty::item_path_str(tcx, item_def_id); - tcx.sess.span_note( - obligation.cause.span, - format!( - "required by `{}`", - item_name).as_slice()); - } - traits::ObjectCastObligation(object_ty) => { - tcx.sess.span_note( - obligation.cause.span, - format!( - "required for the cast to the object type `{}`", - fcx.infcx().ty_to_string(object_ty)).as_slice()); - } - traits::RepeatVec => { - tcx.sess.span_note( - obligation.cause.span, - "the `Copy` trait is required because the \ - repeated element will be copied"); - } - traits::VariableType(_) => { - tcx.sess.span_note( - obligation.cause.span, - "all local variables must have a statically known size"); - } - traits::ReturnType => { - tcx.sess.span_note( - obligation.cause.span, - "the return type of a function must have a \ - statically known size"); - } - traits::AssignmentLhsSized => { - tcx.sess.span_note( - obligation.cause.span, - "the left-hand-side of an assignment must have a statically known size"); - } - traits::StructInitializerSized => { - tcx.sess.span_note( - obligation.cause.span, - "structs must have a statically known size to be initialized"); - } - traits::DropTrait => { - span_note!(tcx.sess, obligation.cause.span, - "cannot implement a destructor on a \ - structure or enumeration that does not satisfy Send"); - span_help!(tcx.sess, obligation.cause.span, - "use \"#[unsafe_destructor]\" on the implementation \ - to force the compiler to allow this"); - } - traits::ClosureCapture(var_id, closure_span, builtin_bound) => { - let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); - let trait_name = ty::item_path_str(tcx, def_id); - let name = ty::local_var_name_str(tcx, var_id); - span_note!(tcx.sess, closure_span, - "the closure that captures `{}` requires that all captured variables \" - implement the trait `{}`", - name, - trait_name); - } - traits::FieldSized => { - span_note!(tcx.sess, obligation.cause.span, - "only the last field of a struct or enum variant \ - may have a dynamically sized type") - } - traits::ObjectSized => { - span_note!(tcx.sess, obligation.cause.span, - "only sized types can be made into objects"); - } + Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } } } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index a2fb44fff79..39bcfb354b8 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -188,7 +188,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { match self_ty.sty { ty::ty_struct(def_id, _) | ty::ty_enum(def_id, _) => { - check_struct_safe_for_destructor(fcx, item.span, self_ty, def_id); + check_struct_safe_for_destructor(fcx, item.span, def_id); } _ => { // Coherence already reports an error in this case. @@ -221,7 +221,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let poly_trait_ref = ty::Binder(trait_ref); let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &poly_trait_ref); for predicate in predicates.into_iter() { - fcx.register_predicate(traits::Obligation::new(cause, predicate)); + fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate)); } }); } @@ -460,20 +460,16 @@ fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>) fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, - self_ty: Ty<'tcx>, struct_did: ast::DefId) { let struct_tpt = ty::lookup_item_type(fcx.tcx(), struct_did); - if !struct_tpt.generics.has_type_params(subst::TypeSpace) - && !struct_tpt.generics.has_region_params(subst::TypeSpace) + if struct_tpt.generics.has_type_params(subst::TypeSpace) + || struct_tpt.generics.has_region_params(subst::TypeSpace) { - let cause = traits::ObligationCause::new(span, fcx.body_id, traits::DropTrait); - fcx.register_builtin_bound(self_ty, ty::BoundSend, cause); - } else { span_err!(fcx.tcx().sess, span, E0141, "cannot implement a destructor on a structure \ - with type parameters"); - span_note!(fcx.tcx().sess, span, - "use \"#[unsafe_destructor]\" on the implementation \ - to force the compiler to allow this"); + with type parameters"); + span_note!(fcx.tcx().sess, span, + "use \"#[unsafe_destructor]\" on the implementation \ + to force the compiler to allow this"); } } diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index fb369924c64..ffe19203769 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -72,13 +72,12 @@ use libc; use fmt; use hash; -use kinds::marker; use mem; use ptr; use slice::{mod, ImmutableIntSlice}; use str; use string::String; - +use core::kinds::marker; /// The representation of a C String. /// @@ -90,6 +89,9 @@ pub struct CString { owns_buffer_: bool, } +unsafe impl Send for CString { } +unsafe impl Sync for CString { } + impl Clone for CString { /// Clone this CString into a new, uniquely owned CString. For safety /// reasons, this is always a deep clone with the memory allocated diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs index 44e7291150e..f4338815f75 100644 --- a/src/libstd/c_vec.rs +++ b/src/libstd/c_vec.rs @@ -180,12 +180,12 @@ mod tests { fn malloc(n: uint) -> CVec { unsafe { - let mem = libc::malloc(n as libc::size_t); - if mem.is_null() { ::alloc::oom() } + let mem = ptr::Unique(libc::malloc(n as libc::size_t)); + if mem.0.is_null() { ::alloc::oom() } - CVec::new_with_dtor(mem as *mut u8, + CVec::new_with_dtor(mem.0 as *mut u8, n, - move|| { libc::free(mem as *mut libc::c_void); }) + move|| { libc::free(mem.0 as *mut libc::c_void); }) } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 8f2152c5a9d..3ae3a8ffbad 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -23,7 +23,7 @@ use num::{Int, UnsignedInt}; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{Some, None}; -use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory}; +use ptr::{Unique, RawPtr, copy_nonoverlapping_memory, zero_memory}; use ptr; use rt::heap::{allocate, deallocate}; @@ -69,7 +69,7 @@ const EMPTY_BUCKET: u64 = 0u64; pub struct RawTable { capacity: uint, size: uint, - hashes: *mut u64, + hashes: Unique, // Because K/V do not appear directly in any of the types in the struct, // inform rustc that in fact instances of K and V are reachable from here. marker: marker::CovariantType<(K,V)>, @@ -563,7 +563,7 @@ impl RawTable { return RawTable { size: 0, capacity: 0, - hashes: 0 as *mut u64, + hashes: Unique::null(), marker: marker::CovariantType, }; } @@ -602,7 +602,7 @@ impl RawTable { RawTable { capacity: capacity, size: 0, - hashes: hashes, + hashes: Unique(hashes), marker: marker::CovariantType, } } @@ -611,14 +611,14 @@ impl RawTable { let hashes_size = self.capacity * size_of::(); let keys_size = self.capacity * size_of::(); - let buffer = self.hashes as *mut u8; + let buffer = self.hashes.0 as *mut u8; let (keys_offset, vals_offset) = calculate_offsets(hashes_size, keys_size, min_align_of::(), min_align_of::()); unsafe { RawBucket { - hash: self.hashes, + hash: self.hashes.0, key: buffer.offset(keys_offset as int) as *mut K, val: buffer.offset(vals_offset as int) as *mut V } @@ -631,7 +631,7 @@ impl RawTable { pub fn new(capacity: uint) -> RawTable { unsafe { let ret = RawTable::new_uninitialized(capacity); - zero_memory(ret.hashes, capacity); + zero_memory(ret.hashes.0, capacity); ret } } @@ -651,7 +651,7 @@ impl RawTable { RawBuckets { raw: self.first_bucket_raw(), hashes_end: unsafe { - self.hashes.offset(self.capacity as int) + self.hashes.0.offset(self.capacity as int) }, marker: marker::ContravariantLifetime, } @@ -916,7 +916,7 @@ impl Clone for RawTable { #[unsafe_destructor] impl Drop for RawTable { fn drop(&mut self) { - if self.hashes.is_null() { + if self.hashes.0.is_null() { return; } // This is done in reverse because we've likely partially taken @@ -936,7 +936,7 @@ impl Drop for RawTable { vals_size, min_align_of::()); unsafe { - deallocate(self.hashes as *mut u8, size, align); + deallocate(self.hashes.0 as *mut u8, size, align); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/src/libstd/comm/blocking.rs b/src/libstd/comm/blocking.rs index c477acd70aa..412b7161305 100644 --- a/src/libstd/comm/blocking.rs +++ b/src/libstd/comm/blocking.rs @@ -13,6 +13,7 @@ use thread::Thread; use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Ordering}; use sync::Arc; +use kinds::{Sync, Send}; use kinds::marker::{NoSend, NoSync}; use mem; use clone::Clone; @@ -22,6 +23,9 @@ struct Inner { woken: AtomicBool, } +unsafe impl Send for Inner {} +unsafe impl Sync for Inner {} + #[deriving(Clone)] pub struct SignalToken { inner: Arc, diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index d3bfaab83da..c85bea87218 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -319,6 +319,7 @@ pub use self::TrySendError::*; use self::Flavor::*; use alloc::arc::Arc; +use core::kinds; use core::kinds::marker; use core::mem; use core::cell::UnsafeCell; @@ -357,10 +358,12 @@ mod spsc_queue; #[unstable] pub struct Receiver { inner: UnsafeCell>, - // can't share in an arc - _marker: marker::NoSync, } +// The receiver port can be sent from place to place, so long as it +// is not used to receive non-sendable things. +unsafe impl Send for Receiver { } + /// An iterator over messages on a receiver, this iterator will block /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. @@ -374,15 +377,17 @@ pub struct Messages<'a, T:'a> { #[unstable] pub struct Sender { inner: UnsafeCell>, - // can't share in an arc - _marker: marker::NoSync, } +// The send port can be sent from place to place, so long as it +// is not used to send non-sendable things. +unsafe impl Send for Sender { } + /// 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. #[unstable = "this type may be renamed, but it will always exist"] pub struct SyncSender { - inner: Arc>>, + inner: Arc>>, // can't share in an arc _marker: marker::NoSync, } @@ -418,10 +423,10 @@ pub enum TrySendError { } enum Flavor { - Oneshot(Arc>>), - Stream(Arc>>), - Shared(Arc>>), - Sync(Arc>>), + Oneshot(Arc>>), + Stream(Arc>>), + Shared(Arc>>), + Sync(Arc>>), } #[doc(hidden)] @@ -472,7 +477,7 @@ impl UnsafeFlavor for Receiver { /// ``` #[unstable] pub fn channel() -> (Sender, Receiver) { - let a = Arc::new(UnsafeCell::new(oneshot::Packet::new())); + let a = Arc::new(RacyCell::new(oneshot::Packet::new())); (Sender::new(Oneshot(a.clone())), Receiver::new(Oneshot(a))) } @@ -512,7 +517,7 @@ pub fn channel() -> (Sender, Receiver) { #[unstable = "this function may be renamed to more accurately reflect the type \ of channel that is is creating"] pub fn sync_channel(bound: uint) -> (SyncSender, Receiver) { - let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound))); + let a = Arc::new(RacyCell::new(sync::Packet::new(bound))); (SyncSender::new(a.clone()), Receiver::new(Sync(a))) } @@ -524,7 +529,6 @@ impl Sender { fn new(inner: Flavor) -> Sender { Sender { inner: UnsafeCell::new(inner), - _marker: marker::NoSync, } } @@ -594,7 +598,8 @@ impl Sender { if !(*p).sent() { return (*p).send(t); } else { - let a = Arc::new(UnsafeCell::new(stream::Packet::new())); + let a = + Arc::new(RacyCell::new(stream::Packet::new())); match (*p).upgrade(Receiver::new(Stream(a.clone()))) { oneshot::UpSuccess => { let ret = (*a.get()).send(t); @@ -631,7 +636,7 @@ impl Clone for Sender { fn clone(&self) -> Sender { let (packet, sleeper, guard) = match *unsafe { self.inner() } { Oneshot(ref p) => { - let a = Arc::new(UnsafeCell::new(shared::Packet::new())); + let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) { @@ -642,7 +647,7 @@ impl Clone for Sender { } } Stream(ref p) => { - let a = Arc::new(UnsafeCell::new(shared::Packet::new())); + let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) { @@ -686,7 +691,7 @@ impl Drop for Sender { //////////////////////////////////////////////////////////////////////////////// impl SyncSender { - fn new(inner: Arc>>) -> SyncSender { + fn new(inner: Arc>>) -> SyncSender { SyncSender { inner: inner, _marker: marker::NoSync } } @@ -775,7 +780,7 @@ impl Drop for SyncSender { impl Receiver { fn new(inner: Flavor) -> Receiver { - Receiver { inner: UnsafeCell::new(inner), _marker: marker::NoSync } + Receiver { inner: UnsafeCell::new(inner) } } /// Blocks waiting for a value on this receiver @@ -1018,6 +1023,27 @@ impl Drop for Receiver { } } +/// A version of `UnsafeCell` intended for use in concurrent data +/// structures (for example, you might put it in an `Arc`). +struct RacyCell(pub UnsafeCell); + +impl RacyCell { + + fn new(value: T) -> RacyCell { + RacyCell(UnsafeCell { value: value }) + } + + unsafe fn get(&self) -> *mut T { + self.0.get() + } + +} + +unsafe impl Send for RacyCell { } + +unsafe impl kinds::Sync for RacyCell { } // Oh dear + + #[cfg(test)] mod test { use super::*; diff --git a/src/libstd/comm/mpsc_queue.rs b/src/libstd/comm/mpsc_queue.rs index db4e3eac449..cddef236664 100644 --- a/src/libstd/comm/mpsc_queue.rs +++ b/src/libstd/comm/mpsc_queue.rs @@ -76,6 +76,9 @@ pub struct Queue { tail: UnsafeCell<*mut Node>, } +unsafe impl Send for Queue { } +unsafe impl Sync for Queue { } + impl Node { unsafe fn new(v: Option) -> *mut Node { mem::transmute(box Node { diff --git a/src/libstd/comm/spsc_queue.rs b/src/libstd/comm/spsc_queue.rs index db8fff772a4..becb78063ae 100644 --- a/src/libstd/comm/spsc_queue.rs +++ b/src/libstd/comm/spsc_queue.rs @@ -73,6 +73,10 @@ pub struct Queue { cache_subtractions: AtomicUint, } +unsafe impl Send for Queue { } + +unsafe impl Sync for Queue { } + impl Node { fn new() -> *mut Node { unsafe { diff --git a/src/libstd/comm/sync.rs b/src/libstd/comm/sync.rs index f75186e70e3..88338849965 100644 --- a/src/libstd/comm/sync.rs +++ b/src/libstd/comm/sync.rs @@ -53,6 +53,10 @@ pub struct Packet { lock: Mutex>, } +unsafe impl Send for Packet { } + +unsafe impl Sync for Packet { } + struct State { disconnected: bool, // Is the channel disconnected yet? queue: Queue, // queue of senders waiting to send data @@ -69,6 +73,8 @@ struct State { canceled: Option<&'static mut bool>, } +unsafe impl Send for State {} + /// Possible flavors of threads who can be blocked on this channel. enum Blocker { BlockedSender(SignalToken), @@ -88,6 +94,8 @@ struct Node { next: *mut Node, } +unsafe impl Send for Node {} + /// A simple ring-buffer struct Buffer { buf: Vec>, diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 9d9e8827571..c26450310a9 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -22,6 +22,7 @@ use result::Result::{Ok, Err}; use slice::{SliceExt}; use slice; use vec::Vec; +use kinds::{Send,Sync}; /// Wraps a Reader and buffers input from it /// @@ -51,6 +52,11 @@ pub struct BufferedReader { cap: uint, } + +unsafe impl Send for BufferedReader {} +unsafe impl Sync for BufferedReader {} + + impl BufferedReader { /// Creates a new `BufferedReader` with the specified buffer capacity pub fn with_capacity(cap: uint, inner: R) -> BufferedReader { diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 1c5ceaf2450..b7da57fed27 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -34,7 +34,7 @@ use failure::LOCAL_STDERR; use fmt; use io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer, standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; -use kinds::Send; +use kinds::{Sync, Send}; use libc; use mem; use option::Option; @@ -98,26 +98,34 @@ thread_local! { } } +struct RaceBox(BufferedReader); + +unsafe impl Send for RaceBox {} +unsafe impl Sync for RaceBox {} + /// A synchronized wrapper around a buffered reader from stdin #[deriving(Clone)] pub struct StdinReader { - inner: Arc>>, + inner: Arc>, } +unsafe impl Send for StdinReader {} +unsafe impl Sync for StdinReader {} + /// A guard for exclusive access to `StdinReader`'s internal `BufferedReader`. pub struct StdinReaderGuard<'a> { - inner: MutexGuard<'a, BufferedReader>, + inner: MutexGuard<'a, RaceBox>, } impl<'a> Deref> for StdinReaderGuard<'a> { fn deref(&self) -> &BufferedReader { - &*self.inner + &self.inner.0 } } impl<'a> DerefMut> for StdinReaderGuard<'a> { fn deref_mut(&mut self) -> &mut BufferedReader { - &mut *self.inner + &mut self.inner.0 } } @@ -147,7 +155,7 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_line(&mut self) -> IoResult { - self.inner.lock().read_line() + self.inner.lock().0.read_line() } /// Like `Buffer::read_until`. @@ -155,7 +163,7 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_until(&mut self, byte: u8) -> IoResult> { - self.inner.lock().read_until(byte) + self.inner.lock().0.read_until(byte) } /// Like `Buffer::read_char`. @@ -163,13 +171,13 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_char(&mut self) -> IoResult { - self.inner.lock().read_char() + self.inner.lock().0.read_char() } } impl Reader for StdinReader { fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.lock().read(buf) + self.inner.lock().0.read(buf) } // We have to manually delegate all of these because the default impls call @@ -177,23 +185,23 @@ impl Reader for StdinReader { // incur the costs of repeated locking). fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult { - self.inner.lock().read_at_least(min, buf) + self.inner.lock().0.read_at_least(min, buf) } fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec) -> IoResult { - self.inner.lock().push_at_least(min, len, buf) + self.inner.lock().0.push_at_least(min, len, buf) } fn read_to_end(&mut self) -> IoResult> { - self.inner.lock().read_to_end() + self.inner.lock().0.read_to_end() } fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult { - self.inner.lock().read_le_uint_n(nbytes) + self.inner.lock().0.read_le_uint_n(nbytes) } fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult { - self.inner.lock().read_be_uint_n(nbytes) + self.inner.lock().0.read_be_uint_n(nbytes) } } @@ -221,7 +229,7 @@ pub fn stdin() -> StdinReader { BufferedReader::new(stdin_raw()) }; let stdin = StdinReader { - inner: Arc::new(Mutex::new(stdin)) + inner: Arc::new(Mutex::new(RaceBox(stdin))) }; STDIN = mem::transmute(box stdin); @@ -426,6 +434,9 @@ pub struct StdWriter { inner: StdSource } +unsafe impl Send for StdWriter {} +unsafe impl Sync for StdWriter {} + impl StdWriter { /// Gets the size of this output window, if possible. This is typically used /// when the writer is attached to something like a terminal, this is used diff --git a/src/libstd/rt/exclusive.rs b/src/libstd/rt/exclusive.rs index 1d3082d1b4c..88bdb29caec 100644 --- a/src/libstd/rt/exclusive.rs +++ b/src/libstd/rt/exclusive.rs @@ -26,6 +26,10 @@ pub struct Exclusive { data: UnsafeCell, } +unsafe impl Send for Exclusive { } + +unsafe impl Sync for Exclusive { } + /// An RAII guard returned via `lock` pub struct ExclusiveGuard<'a, T:'a> { // FIXME #12808: strange name to try to avoid interfering with diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index 6573d9273ce..6cdb199819a 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use kinds::{Send, Sync}; use sync::{Mutex, Condvar}; /// A barrier enables multiple tasks to synchronize the beginning @@ -35,12 +36,18 @@ pub struct Barrier { num_threads: uint, } +unsafe impl Send for Barrier {} +unsafe impl Sync for Barrier {} + // The inner state of a double barrier struct BarrierState { count: uint, generation_id: uint, } +unsafe impl Send for BarrierState {} +unsafe impl Sync for BarrierState {} + impl Barrier { /// Create a new barrier that can block a given number of threads. /// diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index be27c06b83c..f1940bfd829 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -58,6 +58,9 @@ use time::Duration; /// ``` pub struct Condvar { inner: Box } +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + /// Statically allocated condition variables. /// /// This structure is identical to `Condvar` except that it is suitable for use @@ -75,6 +78,9 @@ pub struct StaticCondvar { mutex: AtomicUint, } +unsafe impl Send for StaticCondvar {} +unsafe impl Sync for StaticCondvar {} + /// Constant initializer for a statically allocated condition variable. pub const CONDVAR_INIT: StaticCondvar = StaticCondvar { inner: sys::CONDVAR_INIT, diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 4829be569cc..4d2fbfc4055 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -73,6 +73,10 @@ pub struct Mutex { data: UnsafeCell, } +unsafe impl Send for Mutex { } + +unsafe impl Sync for Mutex { } + /// The static mutex type is provided to allow for static allocation of mutexes. /// /// Note that this is a separate type because using a Mutex correctly means that @@ -99,6 +103,8 @@ pub struct StaticMutex { poison: UnsafeCell, } +unsafe impl Sync for StaticMutex {} + /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. /// @@ -278,6 +284,11 @@ mod test { use thread::Thread; use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar}; + struct Packet(Arc<(Mutex, Condvar)>); + + unsafe impl Send for Packet {} + unsafe impl Sync for Packet {} + #[test] fn smoke() { let m = Mutex::new(()); @@ -337,19 +348,19 @@ mod test { #[test] fn test_mutex_arc_condvar() { - let arc = Arc::new((Mutex::new(false), Condvar::new())); - let arc2 = arc.clone(); + let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); + let packet2 = Packet(packet.0.clone()); let (tx, rx) = channel(); spawn(move|| { // wait until parent gets in rx.recv(); - let &(ref lock, ref cvar) = &*arc2; + let &(ref lock, ref cvar) = &*packet2.0; let mut lock = lock.lock(); *lock = true; cvar.notify_one(); }); - let &(ref lock, ref cvar) = &*arc; + let &(ref lock, ref cvar) = &*packet.0; let lock = lock.lock(); tx.send(()); assert!(!*lock); @@ -361,20 +372,20 @@ mod test { #[test] #[should_fail] fn test_arc_condvar_poison() { - let arc = Arc::new((Mutex::new(1i), Condvar::new())); - let arc2 = arc.clone(); + let packet = Packet(Arc::new((Mutex::new(1i), Condvar::new()))); + let packet2 = Packet(packet.0.clone()); let (tx, rx) = channel(); spawn(move|| { rx.recv(); - let &(ref lock, ref cvar) = &*arc2; + let &(ref lock, ref cvar) = &*packet2.0; let _g = lock.lock(); cvar.notify_one(); // Parent should fail when it wakes up. panic!(); }); - let &(ref lock, ref cvar) = &*arc; + let &(ref lock, ref cvar) = &*packet.0; let lock = lock.lock(); tx.send(()); while *lock == 1 { diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index a43f822e351..4d9fbb59908 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -14,6 +14,7 @@ //! example use case would be for initializing an FFI library. use int; +use kinds::Sync; use mem::drop; use ops::FnOnce; use sync::atomic; @@ -41,6 +42,8 @@ pub struct Once { lock_cnt: atomic::AtomicInt, } +unsafe impl Sync for Once {} + /// Initialization value for static `Once` values. pub const ONCE_INIT: Once = Once { mutex: MUTEX_INIT, diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 3f177a42f44..76d05d9bfd4 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -60,6 +60,9 @@ pub struct RWLock { data: UnsafeCell, } +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} + /// Structure representing a statically allocated RWLock. /// /// This structure is intended to be used inside of a `static` and will provide @@ -88,6 +91,9 @@ pub struct StaticRWLock { poison: UnsafeCell, } +unsafe impl Send for StaticRWLock {} +unsafe impl Sync for StaticRWLock {} + /// Constant initialization for a statically-initialized rwlock. pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { inner: sys::RWLOCK_INIT, diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index 421778e2012..a629f035b07 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -59,6 +59,15 @@ pub struct Helper { pub shutdown: UnsafeCell, } +unsafe impl Send for Helper { } + +unsafe impl Sync for Helper { } + +struct RaceBox(helper_signal::signal); + +unsafe impl Send for RaceBox {} +unsafe impl Sync for RaceBox {} + impl Helper { /// Lazily boots a helper thread, becoming a no-op if the helper has already /// been spawned. @@ -81,9 +90,11 @@ impl Helper { let (receive, send) = helper_signal::new(); *self.signal.get() = send as uint; + let receive = RaceBox(receive); + let t = f(); Thread::spawn(move |:| { - helper(receive, rx, t); + helper(receive.0, rx, t); let _g = self.lock.lock(); *self.shutdown.get() = true; self.cond.notify_one() diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 1a8a92a105a..567c26956ef 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys/common/mutex.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use kinds::Sync; use sys::mutex as imp; /// An OS-based mutual exclusion lock. @@ -17,6 +18,8 @@ use sys::mutex as imp; /// at the top level of the crate instead of this type. pub struct Mutex(imp::Mutex); +unsafe impl Sync for Mutex {} + /// Constant initializer for statically allocated mutexes. pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT); diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index e76f2a2b872..a4ebcbd25d0 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -162,6 +162,9 @@ mod signal { sa_restorer: *mut libc::c_void, } + unsafe impl ::kinds::Send for sigaction { } + unsafe impl ::kinds::Sync for sigaction { } + #[repr(C)] #[cfg(target_word_size = "32")] pub struct sigset_t { @@ -211,6 +214,9 @@ mod signal { sa_resv: [libc::c_int, ..1], } + impl ::kinds::Send for sigaction { } + impl ::kinds::Sync for sigaction { } + #[repr(C)] pub struct sigset_t { __val: [libc::c_ulong, ..32], diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 2f01c53cb2c..81f8659d6ae 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -9,6 +9,7 @@ // except according to those terms. use cell::UnsafeCell; +use kinds::Sync; use sys::sync as ffi; use sys_common::mutex; @@ -23,6 +24,8 @@ pub const MUTEX_INIT: Mutex = Mutex { inner: UnsafeCell { value: ffi::PTHREAD_MUTEX_INITIALIZER }, }; +unsafe impl Sync for Mutex {} + impl Mutex { #[inline] pub unsafe fn new() -> Mutex { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 348b7cfad33..f1b078b4e80 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -117,6 +117,9 @@ pub struct UnixStream { write_deadline: u64, } +unsafe impl Send for UnixStream {} +unsafe impl Sync for UnixStream {} + impl UnixStream { pub fn connect(addr: &CString, timeout: Option) -> IoResult { @@ -215,6 +218,9 @@ pub struct UnixListener { path: CString, } +unsafe impl Send for UnixListener {} +unsafe impl Sync for UnixListener {} + impl UnixListener { pub fn bind(addr: &CString) -> IoResult { bind(addr, libc::SOCK_STREAM).map(|fd| { @@ -259,6 +265,9 @@ struct AcceptorInner { closed: atomic::AtomicBool, } +unsafe impl Send for AcceptorInner {} +unsafe impl Sync for AcceptorInner {} + impl UnixAcceptor { pub fn fd(&self) -> fd_t { self.inner.listener.fd() } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 340f9514241..bcbbb8766b7 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -160,7 +160,7 @@ mod imp { pub static SIGSTKSZ: libc::size_t = 8192; - pub static SIG_DFL: sighandler_t = 0i as sighandler_t; + pub const SIG_DFL: sighandler_t = 0i as sighandler_t; // This definition is not as accurate as it could be, {si_addr} is // actually a giant union. Currently we're only interested in that field, diff --git a/src/libstd/sys/unix/tcp.rs b/src/libstd/sys/unix/tcp.rs index 5c99ad1e0ce..e2a78947e16 100644 --- a/src/libstd/sys/unix/tcp.rs +++ b/src/libstd/sys/unix/tcp.rs @@ -33,6 +33,8 @@ pub struct TcpListener { pub inner: FileDesc, } +unsafe impl Sync for TcpListener {} + impl TcpListener { pub fn bind(addr: ip::SocketAddr) -> IoResult { let fd = try!(net::socket(addr, libc::SOCK_STREAM)); @@ -96,6 +98,8 @@ struct AcceptorInner { closed: atomic::AtomicBool, } +unsafe impl Sync for AcceptorInner {} + impl TcpAcceptor { pub fn fd(&self) -> sock_t { self.inner.listener.fd() } diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index ddd89070ed5..3ac7c09154e 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -22,6 +22,8 @@ pub struct Mutex { inner: atomic::AtomicUint } pub const MUTEX_INIT: Mutex = Mutex { inner: atomic::INIT_ATOMIC_UINT }; +unsafe impl Sync for Mutex {} + #[inline] pub unsafe fn raw(m: &Mutex) -> ffi::LPCRITICAL_SECTION { m.get() diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index bf658d0efd0..fc3640f2604 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -214,6 +214,9 @@ pub struct UnixStream { write_deadline: u64, } +unsafe impl Send for UnixStream {} +unsafe impl Sync for UnixStream {} + impl UnixStream { fn try_connect(p: *const u16) -> Option { // Note that most of this is lifted from the libuv implementation. @@ -559,6 +562,9 @@ pub struct UnixListener { name: CString, } +unsafe impl Send for UnixListener {} +unsafe impl Sync for UnixListener {} + impl UnixListener { pub fn bind(addr: &CString) -> IoResult { // Although we technically don't need the pipe until much later, we @@ -603,11 +609,17 @@ pub struct UnixAcceptor { deadline: u64, } +unsafe impl Send for UnixAcceptor {} +unsafe impl Sync for UnixAcceptor {} + struct AcceptorState { abort: Event, closed: atomic::AtomicBool, } +unsafe impl Send for AcceptorState {} +unsafe impl Sync for AcceptorState {} + impl UnixAcceptor { pub fn accept(&mut self) -> IoResult { // This function has some funky implementation details when working with diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs index 505e6137bf9..513c1d38e36 100644 --- a/src/libstd/sys/windows/tcp.rs +++ b/src/libstd/sys/windows/tcp.rs @@ -24,6 +24,9 @@ pub use sys_common::net::TcpStream; pub struct Event(c::WSAEVENT); +unsafe impl Send for Event {} +unsafe impl Sync for Event {} + impl Event { pub fn new() -> IoResult { let event = unsafe { c::WSACreateEvent() }; @@ -49,6 +52,9 @@ impl Drop for Event { pub struct TcpListener { sock: sock_t } +unsafe impl Send for TcpListener {} +unsafe impl Sync for TcpListener {} + impl TcpListener { pub fn bind(addr: ip::SocketAddr) -> IoResult { sys::init_net(); @@ -109,6 +115,9 @@ pub struct TcpAcceptor { deadline: u64, } +unsafe impl Send for TcpAcceptor {} +unsafe impl Sync for TcpAcceptor {} + struct AcceptorInner { listener: TcpListener, abort: Event, @@ -116,6 +125,9 @@ struct AcceptorInner { closed: atomic::AtomicBool, } +unsafe impl Send for AcceptorInner {} +unsafe impl Sync for AcceptorInner {} + impl TcpAcceptor { pub fn socket(&self) -> sock_t { self.inner.listener.socket() } diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs index 7e4dd768aa9..874838950cd 100644 --- a/src/libstd/sys/windows/timer.rs +++ b/src/libstd/sys/windows/timer.rs @@ -48,6 +48,9 @@ pub enum Req { RemoveTimer(libc::HANDLE, Sender<()>), } +unsafe impl Send for Req {} + + fn helper(input: libc::HANDLE, messages: Receiver, _: ()) { let mut objs = vec![input]; let mut chans = vec![]; diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 89773207347..56731bd7ec3 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -129,7 +129,7 @@ use borrow::IntoCow; use boxed::Box; use cell::UnsafeCell; use clone::Clone; -use kinds::Send; +use kinds::{Send, Sync}; use ops::{Drop, FnOnce}; use option::Option::{mod, Some, None}; use result::Result::{Err, Ok}; @@ -211,8 +211,8 @@ impl Builder { } fn spawn_inner(self, f: Thunk<(), T>) -> JoinGuard { - let my_packet = Arc::new(UnsafeCell::new(None)); - let their_packet = my_packet.clone(); + let my_packet = Packet(Arc::new(UnsafeCell::new(None))); + let their_packet = Packet(my_packet.0.clone()); let Builder { name, stack_size, stdout, stderr } = self; @@ -266,7 +266,7 @@ impl Builder { } }; unsafe { - *their_packet.get() = Some(match (output, try_result) { + *their_packet.0.get() = Some(match (output, try_result) { (Some(data), Ok(_)) => Ok(data), (None, Err(cause)) => Err(cause), _ => unreachable!() @@ -289,12 +289,16 @@ struct Inner { cvar: Condvar, } +unsafe impl Sync for Inner {} + #[deriving(Clone)] /// A handle to a thread. pub struct Thread { inner: Arc, } +unsafe impl Sync for Thread {} + impl Thread { // Used only internally to construct a thread object without spawning fn new(name: Option) -> Thread { @@ -379,6 +383,11 @@ impl thread_info::NewThread for Thread { /// A thread that completes without panicking is considered to exit successfully. pub type Result = ::result::Result>; +struct Packet(Arc>>>); + +unsafe impl Send for Packet {} +unsafe impl Sync for Packet {} + #[must_use] /// An RAII-style guard that will block until thread termination when dropped. /// @@ -387,9 +396,11 @@ pub struct JoinGuard { native: imp::rust_thread, thread: Thread, joined: bool, - packet: Arc>>>, + packet: Packet, } +unsafe impl Sync for JoinGuard {} + impl JoinGuard { /// Extract a handle to the thread this guard will join on. pub fn thread(&self) -> &Thread { @@ -406,7 +417,7 @@ impl JoinGuard { unsafe { imp::join(self.native) }; self.joined = true; unsafe { - (*self.packet.get()).take().unwrap() + (*self.packet.0.get()).take().unwrap() } } diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index 04718dcc6ae..242dceb4256 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -280,6 +280,8 @@ mod imp { pub dtor_running: UnsafeCell, // should be Cell } + unsafe impl ::kinds::Sync for Key { } + #[doc(hidden)] impl Key { pub unsafe fn get(&'static self) -> Option<&'static T> { @@ -410,6 +412,8 @@ mod imp { pub os: OsStaticKey, } + unsafe impl ::kinds::Sync for Key { } + struct Value { key: &'static Key, value: T, diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread_local/scoped.rs index 643a0f55e74..756c86c2115 100644 --- a/src/libstd/thread_local/scoped.rs +++ b/src/libstd/thread_local/scoped.rs @@ -198,10 +198,11 @@ impl Key { mod imp { use std::cell::UnsafeCell; - // FIXME: Should be a `Cell`, but that's not `Sync` #[doc(hidden)] pub struct KeyInner { pub inner: UnsafeCell<*mut T> } + unsafe impl ::kinds::Sync for KeyInner { } + #[doc(hidden)] impl KeyInner { #[doc(hidden)] @@ -222,6 +223,8 @@ mod imp { pub marker: marker::InvariantType, } + unsafe impl ::kinds::Sync for KeyInner { } + #[doc(hidden)] impl KeyInner { #[doc(hidden)] diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs index c27a27fce6a..cf29bb048d6 100644 --- a/src/libsyntax/ext/deriving/bounds.rs +++ b/src/libsyntax/ext/deriving/bounds.rs @@ -26,8 +26,11 @@ pub fn expand_deriving_bound(cx: &mut ExtCtxt, MetaWord(ref tname) => { match tname.get() { "Copy" => "Copy", - "Send" => "Send", - "Sync" => "Sync", + "Send" | "Sync" => { + return cx.span_err(span, + format!("{} is an unsafe trait and it \ + should be implemented explicitly", *tname)[]) + } ref tname => { cx.span_bug(span, format!("expected built-in trait name but \ diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 4b73fe04c85..88dd6fce88f 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -976,6 +976,8 @@ enum TestEvent { pub type MonitorMsg = (TestDesc, TestResult, Vec ); +unsafe impl Send for MonitorMsg {} + fn run_tests(opts: &TestOpts, tests: Vec , mut callback: F) -> io::IoResult<()> where diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index d746ec1dbab..66965110f73 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -46,7 +46,7 @@ extern crate libc; use std::io::stdio::{stdin_raw, stdout_raw}; use std::num::{div_rem}; -use std::ptr::{copy_memory}; +use std::ptr::{copy_memory, Unique}; use std::io::{IoResult, EndOfFile}; struct Tables { @@ -219,10 +219,15 @@ fn reverse_complement(seq: &mut [u8], tables: &Tables) { } } + +struct Racy(T); + +unsafe impl Send for Racy {} + /// Executes a closure in parallel over the given iterator over mutable slice. /// The closure `f` is run in parallel with an element of `iter`. fn parallel<'a, I, T, F>(mut iter: I, f: F) - where T: Send + Sync, + where T: 'a+Send + Sync, I: Iterator<&'a mut [T]>, F: Fn(&'a mut [T]) + Sync { use std::mem; @@ -234,11 +239,11 @@ fn parallel<'a, I, T, F>(mut iter: I, f: F) // Need to convert `f` and `chunk` to something that can cross the task // boundary. - let f = &f as *const F as *const uint; - let raw = chunk.repr(); + let f = Racy(&f as *const F as *const uint); + let raw = Racy(chunk.repr()); spawn(move|| { - let f = f as *const F; - unsafe { (*f)(mem::transmute(raw)) } + let f = f.0 as *const F; + unsafe { (*f)(mem::transmute(raw.0)) } drop(tx) }); } diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index 647c47b00a0..df388fbdde5 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -108,6 +108,11 @@ fn dot(v: &[f64], u: &[f64]) -> f64 { v.iter().zip(u.iter()).map(|(a, b)| *a * *b).sum() } + +struct Racy(T); + +unsafe impl Send for Racy {} + // Executes a closure in parallel over the given mutable slice. The closure `f` // is run in parallel and yielded the starting index within `v` as well as a // sub-slice of `v`. @@ -122,11 +127,11 @@ fn parallel<'a, T, F>(v: &'a mut [T], f: F) // Need to convert `f` and `chunk` to something that can cross the task // boundary. - let f = &f as *const _ as *const uint; - let raw = chunk.repr(); + let f = Racy(&f as *const _ as *const uint); + let raw = Racy(chunk.repr()); spawn(move|| { - let f = f as *const F; - unsafe { (*f)(i * size, mem::transmute(raw)) } + let f = f.0 as *const F; + unsafe { (*f)(i * size, mem::transmute(raw.0)) } drop(tx) }); } diff --git a/src/test/compile-fail/deriving-bounds.rs b/src/test/compile-fail/deriving-bounds.rs index 1f9bd881afe..d61ad98ee1e 100644 --- a/src/test/compile-fail/deriving-bounds.rs +++ b/src/test/compile-fail/deriving-bounds.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[deriving(Sync(Bad),Send,Copy)] +#[deriving(Copy(Bad))] //~^ ERROR unexpected value in deriving, expected a trait struct Test; +#[deriving(Sync)] +//~^ ERROR Sync is an unsafe trait and it should be implemented explicitly +struct Test1; + pub fn main() {} diff --git a/src/test/compile-fail/issue-17718-static-sync.rs b/src/test/compile-fail/issue-17718-static-sync.rs index 2304b18adb6..63a40e2374b 100644 --- a/src/test/compile-fail/issue-17718-static-sync.rs +++ b/src/test/compile-fail/issue-17718-static-sync.rs @@ -14,6 +14,6 @@ struct Foo { marker: marker::NoSync } static FOO: uint = 3; static BAR: Foo = Foo { marker: marker::NoSync }; -//~^ ERROR: shared static items must have a type which implements Sync +//~^ ERROR: the trait `core::kinds::Sync` is not implemented fn main() {} diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index bef8ca6b86c..a8a699d62d5 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -33,4 +33,5 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; //~^ ERROR the trait `core::kinds::Send` is not implemented + //~^^ ERROR the trait `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index 7f0d9ef3b11..2646edd7684 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -14,6 +14,8 @@ use std::cell::RefCell; // Regresion test for issue 7364 static boxed: Box> = box RefCell::new(0); //~^ ERROR statics are not allowed to have custom pointers -//~^^ ERROR: shared static items must have a type which implements Sync +//~^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type +//~^^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type +//~^^^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type fn main() { } diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs index 1a82a2b3832..803da617abd 100644 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ b/src/test/compile-fail/kindck-destructor-owned.rs @@ -9,19 +9,6 @@ // except according to those terms. -use std::rc::Rc; - -struct Foo { - f: Rc, -} - -impl Drop for Foo { -//~^ ERROR the trait `core::kinds::Send` is not implemented -//~^^ NOTE cannot implement a destructor on a structure or enumeration that does not satisfy Send - fn drop(&mut self) { - } -} - struct Bar<'a> { f: &'a int, } diff --git a/src/test/compile-fail/kindck-nonsendable-1.rs b/src/test/compile-fail/kindck-nonsendable-1.rs index c96054afc2f..fdd8584a8bb 100644 --- a/src/test/compile-fail/kindck-nonsendable-1.rs +++ b/src/test/compile-fail/kindck-nonsendable-1.rs @@ -17,6 +17,8 @@ fn bar(_: F) { } fn main() { let x = Rc::new(3u); - bar(move|| foo(x)); //~ ERROR `core::kinds::Send` is not implemented + bar(move|| foo(x)); + //~^ ERROR `core::kinds::Send` is not implemented + //~^^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/kindck-send-unsafe.rs b/src/test/compile-fail/kindck-send-unsafe.rs index 33314149d1f..4e1641025d5 100644 --- a/src/test/compile-fail/kindck-send-unsafe.rs +++ b/src/test/compile-fail/kindck-send-unsafe.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +extern crate core; + fn assert_send() { } -// unsafe ptrs are ok unless they point at unsendable things -fn test70() { - assert_send::<*mut int>(); -} fn test71<'a>() { - assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied + assert_send::<*mut &'a int>(); + //~^ ERROR the trait `core::kinds::Send` is not implemented for the type } fn main() { diff --git a/src/test/compile-fail/mut-not-freeze.rs b/src/test/compile-fail/mut-not-freeze.rs index 60921c04135..4b058f6fdb3 100644 --- a/src/test/compile-fail/mut-not-freeze.rs +++ b/src/test/compile-fail/mut-not-freeze.rs @@ -14,5 +14,8 @@ fn f(_: T) {} fn main() { let x = RefCell::new(0i); - f(x); //~ ERROR `core::kinds::Sync` is not implemented + f(x); + //~^ ERROR `core::kinds::Sync` is not implemented + //~^^ ERROR `core::kinds::Sync` is not implemented + //~^^^ ERROR `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index e1ba36de7c0..48747c7ce1d 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -37,6 +37,7 @@ fn main() { task::spawn(move|| { //~^ ERROR `core::kinds::Send` is not implemented + //~^^ ERROR `core::kinds::Send` is not implemented let y = x; println!("{}", y); }); diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs index c05b17afe1d..004921b1db0 100644 --- a/src/test/compile-fail/no_send-rc.rs +++ b/src/test/compile-fail/no_send-rc.rs @@ -16,4 +16,5 @@ fn main() { let x = Rc::new(5i); bar(x); //~^ ERROR `core::kinds::Send` is not implemented + //~^^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/no_share-rc.rs b/src/test/compile-fail/no_share-rc.rs index 5572f72d8fe..ac3b456def5 100644 --- a/src/test/compile-fail/no_share-rc.rs +++ b/src/test/compile-fail/no_share-rc.rs @@ -17,4 +17,5 @@ fn main() { let x = Rc::new(RefCell::new(5i)); bar(x); //~^ ERROR the trait `core::kinds::Sync` is not implemented + //~^^ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs index 67655f323f0..e15cb25295a 100644 --- a/src/test/compile-fail/regions-bounded-by-send.rs +++ b/src/test/compile-fail/regions-bounded-by-send.rs @@ -12,8 +12,11 @@ // in this file all test region bound and lifetime violations that are // detected during type check. +extern crate core; +use core::ptr::Unique; + fn assert_send() { } -trait Dummy { } +trait Dummy:Send { } // lifetime pointers with 'static lifetime are ok @@ -58,7 +61,7 @@ fn box_with_region_not_ok<'a>() { fn object_with_random_bound_not_ok<'a>() { assert_send::<&'a (Dummy+'a)>(); - //~^ ERROR not implemented + //~^ ERROR reference has a longer lifetime } fn object_with_send_bound_not_ok<'a>() { @@ -73,17 +76,12 @@ fn closure_with_lifetime_not_ok<'a>() { // unsafe pointers are ok unless they point at unsendable things +struct UniqueUnsafePtr(Unique<*const int>); + +unsafe impl Send for UniqueUnsafePtr {} + fn unsafe_ok1<'a>(_: &'a int) { - assert_send::<*const int>(); - assert_send::<*mut int>(); -} - -fn unsafe_ok2<'a>(_: &'a int) { - assert_send::<*const &'a int>(); //~ ERROR declared lifetime bound not satisfied -} - -fn unsafe_ok3<'a>(_: &'a int) { - assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied + assert_send::(); } fn main() { diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs index e9997083bab..d96599404de 100644 --- a/src/test/compile-fail/task-rng-isnt-sendable.rs +++ b/src/test/compile-fail/task-rng-isnt-sendable.rs @@ -17,4 +17,5 @@ fn test_send() {} pub fn main() { test_send::(); //~^ ERROR `core::kinds::Send` is not implemented + //~^^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/typeck-unsafe-always-share.rs b/src/test/compile-fail/typeck-unsafe-always-share.rs index 7c74cdc890d..a7911eb791e 100644 --- a/src/test/compile-fail/typeck-unsafe-always-share.rs +++ b/src/test/compile-fail/typeck-unsafe-always-share.rs @@ -30,12 +30,15 @@ fn test(s: T){ fn main() { let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0i)}); test(us); + //~^ ERROR `core::kinds::Sync` is not implemented let uns = UnsafeCell::new(NoSync{m: marker::NoSync}); test(uns); + //~^ ERROR `core::kinds::Sync` is not implemented let ms = MySync{u: uns}; test(ms); + //~^ ERROR `core::kinds::Sync` is not implemented let ns = NoSync{m: marker::NoSync}; test(ns); diff --git a/src/test/compile-fail/unique-unique-kind.rs b/src/test/compile-fail/unique-unique-kind.rs index 4c2805bf4bd..48d5028f435 100644 --- a/src/test/compile-fail/unique-unique-kind.rs +++ b/src/test/compile-fail/unique-unique-kind.rs @@ -16,5 +16,7 @@ fn f(_i: T) { fn main() { let i = box Rc::new(100i); - f(i); //~ ERROR `core::kinds::Send` is not implemented + f(i); + //~^ ERROR `core::kinds::Send` is not implemented + //~^^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs index d988a245700..cd5918e2f47 100644 --- a/src/test/compile-fail/unsendable-class.rs +++ b/src/test/compile-fail/unsendable-class.rs @@ -28,6 +28,8 @@ fn foo(i:int, j: Rc) -> foo { fn main() { let cat = "kitty".to_string(); - let (tx, _) = channel(); //~ ERROR `core::kinds::Send` is not implemented + let (tx, _) = channel(); + //~^ ERROR `core::kinds::Send` is not implemented + //~^^ ERROR `core::kinds::Send` is not implemented tx.send(foo(42, Rc::new(cat))); } diff --git a/src/test/run-pass/const-block.rs b/src/test/run-pass/const-block.rs index 01eccc53427..35783ea5899 100644 --- a/src/test/run-pass/const-block.rs +++ b/src/test/run-pass/const-block.rs @@ -11,11 +11,15 @@ #![allow(dead_code)] #![allow(unused_unsafe)] +use std::kinds::Sync; + struct Foo { a: uint, b: *const () } +unsafe impl Sync for Foo {} + fn foo(a: T) -> T { a } diff --git a/src/test/run-pass/const-cast-ptr-int.rs b/src/test/run-pass/const-cast-ptr-int.rs index e4734fc3e55..50e460bd179 100644 --- a/src/test/run-pass/const-cast-ptr-int.rs +++ b/src/test/run-pass/const-cast-ptr-int.rs @@ -10,8 +10,14 @@ use std::ptr; -static a: *const u8 = 0 as *const u8; +struct TestStruct { + x: *const u8 +} + +unsafe impl Sync for TestStruct {} + +static a: TestStruct = TestStruct{x: 0 as *const u8}; pub fn main() { - assert_eq!(a, ptr::null()); + assert_eq!(a.x, ptr::null()); } diff --git a/src/test/run-pass/const-cast.rs b/src/test/run-pass/const-cast.rs index 5d8e31f9344..b7e9c0338dd 100644 --- a/src/test/run-pass/const-cast.rs +++ b/src/test/run-pass/const-cast.rs @@ -10,14 +10,16 @@ extern crate libc; -extern fn foo() {} +struct TestStruct { + x: *const libc::c_void +} +unsafe impl Sync for TestStruct {} + +extern fn foo() {} const x: extern "C" fn() = foo; -static y: *const libc::c_void = x as *const libc::c_void; -const a: &'static int = &10; -static b: *const int = a as *const int; +static y: TestStruct = TestStruct { x: x as *const libc::c_void }; pub fn main() { - assert_eq!(x as *const libc::c_void, y); - assert_eq!(a as *const int, b); + assert_eq!(x as *const libc::c_void, y.x); } diff --git a/src/test/run-pass/deriving-bounds.rs b/src/test/run-pass/deriving-bounds.rs index d120b8030c1..0bf27cfbb24 100644 --- a/src/test/run-pass/deriving-bounds.rs +++ b/src/test/run-pass/deriving-bounds.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[deriving(Sync,Send,Copy)] +#[deriving(Copy)] struct Test; pub fn main() {} diff --git a/src/test/run-pass/issue-13837.rs b/src/test/run-pass/issue-13837.rs index f62a45277b2..c6847ce55de 100644 --- a/src/test/run-pass/issue-13837.rs +++ b/src/test/run-pass/issue-13837.rs @@ -8,6 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -static TEST_VALUE : *const [int; 2] = 0x1234 as *const [int; 2]; +struct TestStruct { + x: *const [int; 2] +} + +unsafe impl Sync for TestStruct {} + +static TEST_VALUE : TestStruct = TestStruct{x: 0x1234 as *const [int; 2]}; fn main() {} diff --git a/src/test/run-pass/issue-17718-static-unsafe-interior.rs b/src/test/run-pass/issue-17718-static-unsafe-interior.rs index cd32857ede5..0851f0e367b 100644 --- a/src/test/run-pass/issue-17718-static-unsafe-interior.rs +++ b/src/test/run-pass/issue-17718-static-unsafe-interior.rs @@ -11,38 +11,46 @@ use std::kinds::marker; use std::cell::UnsafeCell; +struct MyUnsafePack(UnsafeCell); + +unsafe impl Sync for MyUnsafePack {} + struct MyUnsafe { - value: UnsafeCell + value: MyUnsafePack } impl MyUnsafe { fn forbidden(&self) {} } +unsafe impl Sync for MyUnsafe {} + enum UnsafeEnum { VariantSafe, VariantUnsafe(UnsafeCell) } +unsafe impl Sync for UnsafeEnum {} + static STATIC1: UnsafeEnum = UnsafeEnum::VariantSafe; -static STATIC2: UnsafeCell = UnsafeCell { value: 1 }; -const CONST: UnsafeCell = UnsafeCell { value: 1 }; +static STATIC2: MyUnsafePack = MyUnsafePack(UnsafeCell { value: 1 }); +const CONST: MyUnsafePack = MyUnsafePack(UnsafeCell { value: 1 }); static STATIC3: MyUnsafe = MyUnsafe{value: CONST}; -static STATIC4: &'static UnsafeCell = &STATIC2; +static STATIC4: &'static MyUnsafePack = &STATIC2; struct Wrap { value: T } -static UNSAFE: UnsafeCell = UnsafeCell{value: 1}; -static WRAPPED_UNSAFE: Wrap<&'static UnsafeCell> = Wrap { value: &UNSAFE }; +unsafe impl Sync for Wrap {} + +static UNSAFE: MyUnsafePack = MyUnsafePack(UnsafeCell{value: 2}); +static WRAPPED_UNSAFE: Wrap<&'static MyUnsafePack> = Wrap { value: &UNSAFE }; fn main() { let a = &STATIC1; STATIC3.forbidden() } - - diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs index 3943d8a3f30..d949cab97c2 100644 --- a/src/test/run-pass/issue-2718.rs +++ b/src/test/run-pass/issue-2718.rs @@ -23,6 +23,7 @@ pub mod pipes { use std::mem::{replace, swap}; use std::mem; use std::task; + use std::kinds::Send; pub struct Stuff { state: state, @@ -45,6 +46,8 @@ pub mod pipes { payload: Option } + unsafe impl Send for packet {} + pub fn packet() -> *const packet { unsafe { let p: *const packet = mem::transmute(box Stuff{ @@ -230,8 +233,13 @@ pub mod pingpong { use std::mem; pub struct ping(::pipes::send_packet); + + unsafe impl Send for ping {} + pub struct pong(::pipes::send_packet); + unsafe impl Send for pong {} + pub fn liberate_ping(p: ping) -> ::pipes::send_packet { unsafe { let _addr : *const ::pipes::send_packet = match &p { diff --git a/src/test/run-pass/typeck_type_placeholder_1.rs b/src/test/run-pass/typeck_type_placeholder_1.rs index 10c91274f10..a8ae3f40f0e 100644 --- a/src/test/run-pass/typeck_type_placeholder_1.rs +++ b/src/test/run-pass/typeck_type_placeholder_1.rs @@ -11,7 +11,14 @@ // This test checks that the `_` type placeholder works // correctly for enabling type inference. -static CONSTEXPR: *const int = &413 as *const _; +struct TestStruct { + x: *const int +} + +unsafe impl Sync for TestStruct {} + +static CONSTEXPR: TestStruct = TestStruct{x: &413 as *const _}; + pub fn main() { let x: Vec<_> = range(0u, 5).collect();