auto merge of #20119 : FlaPer87/rust/oibit-send-and-friends, r=nikomatsakis
More work on opt-in built in traits. `Send` and `Sync` are not opt-in, `OwnedPtr` renamed to `UniquePtr` and the `Send` and `Sync` traits are now unsafe. NOTE: This likely needs to be rebased on top of the yet-to-land snapshot. r? @nikomatsakis cc #13231
This commit is contained in:
commit
4a4c89c7a4
@ -117,6 +117,10 @@ pub struct Arc<T> {
|
||||
_ptr: *mut ArcInner<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Sync + Send> Send for Arc<T> { }
|
||||
unsafe impl<T: Sync + Send> Sync for Arc<T> { }
|
||||
|
||||
|
||||
/// 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<T> {
|
||||
_ptr: *mut ArcInner<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Sync + Send> Send for Weak<T> { }
|
||||
unsafe impl<T: Sync + Send> Sync for Weak<T> { }
|
||||
|
||||
struct ArcInner<T> {
|
||||
strong: atomic::AtomicUint,
|
||||
weak: atomic::AtomicUint,
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T: Sync + Send> Arc<T> {
|
||||
unsafe impl<T: Sync + Send> Send for ArcInner<T> {}
|
||||
unsafe impl<T: Sync + Send> Sync for ArcInner<T> {}
|
||||
|
||||
impl<T> Arc<T> {
|
||||
/// Constructs a new `Arc<T>`.
|
||||
///
|
||||
/// # 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;
|
||||
|
@ -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<T>(*mut T);
|
||||
pub struct Box<T>(Unique<T>);
|
||||
|
||||
#[stable]
|
||||
impl<T: Default> Default for Box<T> {
|
||||
|
@ -43,6 +43,8 @@ struct Rawlink<T> {
|
||||
}
|
||||
|
||||
impl<T> Copy for Rawlink<T> {}
|
||||
unsafe impl<T:'static+Send> Send for Rawlink<T> {}
|
||||
unsafe impl<T:Send+Sync> Sync for Rawlink<T> {}
|
||||
|
||||
struct Node<T> {
|
||||
next: Link<T>,
|
||||
|
@ -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<T> {
|
||||
ptr: *mut T,
|
||||
ptr: Unique<T>,
|
||||
len: uint,
|
||||
cap: uint,
|
||||
}
|
||||
@ -176,7 +176,7 @@ impl<T> Vec<T> {
|
||||
// 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<T>` with the specified capacity.
|
||||
@ -209,7 +209,7 @@ impl<T> Vec<T> {
|
||||
#[stable]
|
||||
pub fn with_capacity(capacity: uint) -> Vec<T> {
|
||||
if mem::size_of::<T>() == 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<T> Vec<T> {
|
||||
.expect("capacity overflow");
|
||||
let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
|
||||
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<T> Vec<T> {
|
||||
#[unstable = "needs finalization"]
|
||||
pub unsafe fn from_raw_parts(ptr: *mut T, length: uint,
|
||||
capacity: uint) -> Vec<T> {
|
||||
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<T> Vec<T> {
|
||||
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<T> Vec<T> {
|
||||
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::<T>(),
|
||||
self.len * mem::size_of::<T>(),
|
||||
mem::min_align_of::<T>()) 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::<T>(),
|
||||
self.len * mem::size_of::<T>(),
|
||||
mem::min_align_of::<T>()) as *mut T);
|
||||
if self.ptr.0.is_null() { ::alloc::oom() }
|
||||
}
|
||||
self.cap = self.len;
|
||||
}
|
||||
@ -867,7 +867,7 @@ impl<T> Vec<T> {
|
||||
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<T> Vec<T> {
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn into_iter(self) -> IntoIter<T> {
|
||||
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::<T>() == 0 {
|
||||
(ptr as uint + self.len()) as *const T
|
||||
} else {
|
||||
@ -1110,14 +1110,14 @@ impl<T> Vec<T> {
|
||||
let size = max(old_size, 2 * mem::size_of::<T>()) * 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<T> Vec<T> {
|
||||
#[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::<T>() == 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<T> Vec<T> {
|
||||
let size = capacity.checked_mul(mem::size_of::<T>())
|
||||
.expect("capacity overflow");
|
||||
unsafe {
|
||||
self.ptr = alloc_or_realloc(self.ptr, self.cap * mem::size_of::<T>(), size);
|
||||
if self.ptr.is_null() { ::alloc::oom() }
|
||||
self.ptr = Unique(alloc_or_realloc(self.ptr.0,
|
||||
self.cap * mem::size_of::<T>(),
|
||||
size));
|
||||
if self.ptr.0.is_null() { ::alloc::oom() }
|
||||
}
|
||||
self.cap = capacity;
|
||||
}
|
||||
@ -1355,7 +1357,7 @@ impl<T> AsSlice<T> for Vec<T> {
|
||||
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<T> Drop for Vec<T> {
|
||||
for x in self.iter() {
|
||||
ptr::read(x);
|
||||
}
|
||||
dealloc(self.ptr, self.cap)
|
||||
dealloc(self.ptr.0, self.cap)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1418,7 +1420,7 @@ impl<T> IntoIter<T> {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<uint>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for AtomicBool {}
|
||||
|
||||
/// A signed integer type which can be safely shared between threads.
|
||||
#[stable]
|
||||
pub struct AtomicInt {
|
||||
v: UnsafeCell<int>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for AtomicInt {}
|
||||
|
||||
/// An unsigned integer type which can be safely shared between threads.
|
||||
#[stable]
|
||||
pub struct AtomicUint {
|
||||
v: UnsafeCell<uint>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for AtomicUint {}
|
||||
|
||||
/// A raw pointer type which can be safely shared between threads.
|
||||
#[stable]
|
||||
pub struct AtomicPtr<T> {
|
||||
p: UnsafeCell<uint>,
|
||||
}
|
||||
|
||||
unsafe impl<T> Sync for AtomicPtr<T> {}
|
||||
|
||||
/// Atomic memory orderings
|
||||
///
|
||||
/// Memory orderings limit the ways that both the compiler and CPU may reorder
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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<T> 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<T>` 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<T>` or `Box<T>`, which
|
||||
/// internally use raw pointers to manage the memory that they own.
|
||||
pub struct Unique<T>(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<T:Send> Send for Unique<T> { }
|
||||
|
||||
/// `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<T:Sync> Sync for Unique<T> { }
|
||||
|
||||
impl<T> Unique<T> {
|
||||
/// Returns a null Unique.
|
||||
pub fn null() -> Unique<T> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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<CVec<u8>> {
|
||||
&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<CVec<u8>> {
|
||||
&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
|
||||
}
|
||||
|
@ -67,5 +67,6 @@ register_diagnostics! {
|
||||
E0173,
|
||||
E0174,
|
||||
E0177,
|
||||
E0178
|
||||
E0178,
|
||||
E0179
|
||||
}
|
||||
|
@ -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) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<deref_kind> {
|
||||
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, _) |
|
||||
|
349
src/librustc/middle/traits/error_reporting.rs
Normal file
349
src/librustc/middle/traits/error_reporting.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
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<FulfillmentError<'tcx>>) {
|
||||
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 "<generic
|
||||
// #0> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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<ty::PolyTraitRef<'tcx>>>;
|
||||
|
||||
/// 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<ty::PolyTraitRef<'tcx>>, Rc<ObligationCauseCode<'tcx>>),
|
||||
|
||||
ImplDerivedObligation(Rc<ty::PolyTraitRef<'tcx>>, Rc<ObligationCauseCode<'tcx>>),
|
||||
}
|
||||
|
||||
pub type Obligations<'tcx, O> = subst::VecPerParamSpace<Obligation<'tcx, O>>;
|
||||
|
@ -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<Candidate<'tcx>>)
|
||||
-> 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<T>`
|
||||
// to always be sync. This is allow for types like `Queue`
|
||||
// and `Mutex`, where `Queue<T> : 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<Ty<'tcx>>)
|
||||
-> VtableBuiltinData<PredicateObligation<'tcx>>
|
||||
{
|
||||
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<Substs<'tcx>,()>
|
||||
{
|
||||
@ -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<ty::Binder<ty::TraitRef<'tcx>>>,
|
||||
Rc<ObligationCauseCode<'tcx>>)
|
||||
-> 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> {
|
||||
|
@ -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() }
|
||||
})
|
||||
|
@ -439,7 +439,7 @@ impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
|
||||
{
|
||||
fn fold_with<F:TypeFolder<'tcx>>(&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),
|
||||
}
|
||||
|
@ -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<LoanPath<'tcx>>) -> Rc<LoanPath<'
|
||||
fn helper<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Option<Rc<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.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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -281,6 +281,8 @@ struct ModuleConfig {
|
||||
time_passes: bool,
|
||||
}
|
||||
|
||||
unsafe impl Send for ModuleConfig { }
|
||||
|
||||
impl ModuleConfig {
|
||||
fn new(tm: TargetMachineRef, passes: Vec<String>) -> ModuleConfig {
|
||||
ModuleConfig {
|
||||
|
@ -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
|
||||
|
@ -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<ModuleTranslation>,
|
||||
pub metadata_module: ModuleTranslation,
|
||||
|
@ -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
|
||||
|
@ -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<FulfillmentError<'tcx>>) {
|
||||
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 "<generic
|
||||
// #0> 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); }
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -180,12 +180,12 @@ mod tests {
|
||||
|
||||
fn malloc(n: uint) -> CVec<u8> {
|
||||
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); })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<K, V> {
|
||||
capacity: uint,
|
||||
size: uint,
|
||||
hashes: *mut u64,
|
||||
hashes: Unique<u64>,
|
||||
// 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<K, V> RawTable<K, V> {
|
||||
return RawTable {
|
||||
size: 0,
|
||||
capacity: 0,
|
||||
hashes: 0 as *mut u64,
|
||||
hashes: Unique::null(),
|
||||
marker: marker::CovariantType,
|
||||
};
|
||||
}
|
||||
@ -602,7 +602,7 @@ impl<K, V> RawTable<K, V> {
|
||||
RawTable {
|
||||
capacity: capacity,
|
||||
size: 0,
|
||||
hashes: hashes,
|
||||
hashes: Unique(hashes),
|
||||
marker: marker::CovariantType,
|
||||
}
|
||||
}
|
||||
@ -611,14 +611,14 @@ impl<K, V> RawTable<K, V> {
|
||||
let hashes_size = self.capacity * size_of::<u64>();
|
||||
let keys_size = self.capacity * size_of::<K>();
|
||||
|
||||
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::<K>(),
|
||||
min_align_of::<V>());
|
||||
|
||||
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<K, V> RawTable<K, V> {
|
||||
pub fn new(capacity: uint) -> RawTable<K, V> {
|
||||
unsafe {
|
||||
let ret = RawTable::new_uninitialized(capacity);
|
||||
zero_memory(ret.hashes, capacity);
|
||||
zero_memory(ret.hashes.0, capacity);
|
||||
ret
|
||||
}
|
||||
}
|
||||
@ -651,7 +651,7 @@ impl<K, V> RawTable<K, V> {
|
||||
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<K: Clone, V: Clone> Clone for RawTable<K, V> {
|
||||
#[unsafe_destructor]
|
||||
impl<K, V> Drop for RawTable<K, V> {
|
||||
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<K, V> Drop for RawTable<K, V> {
|
||||
vals_size, min_align_of::<V>());
|
||||
|
||||
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.
|
||||
}
|
||||
|
@ -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<Inner>,
|
||||
|
@ -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<T> {
|
||||
inner: UnsafeCell<Flavor<T>>,
|
||||
// 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<T:Send> Send for Receiver<T> { }
|
||||
|
||||
/// 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<T> {
|
||||
inner: UnsafeCell<Flavor<T>>,
|
||||
// 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<T:Send> Send for Sender<T> { }
|
||||
|
||||
/// The sending-half of Rust's synchronous channel type. This half can only be
|
||||
/// owned by one task, but it can be cloned to send to other tasks.
|
||||
#[unstable = "this type may be renamed, but it will always exist"]
|
||||
pub struct SyncSender<T> {
|
||||
inner: Arc<UnsafeCell<sync::Packet<T>>>,
|
||||
inner: Arc<RacyCell<sync::Packet<T>>>,
|
||||
// can't share in an arc
|
||||
_marker: marker::NoSync,
|
||||
}
|
||||
@ -418,10 +423,10 @@ pub enum TrySendError<T> {
|
||||
}
|
||||
|
||||
enum Flavor<T> {
|
||||
Oneshot(Arc<UnsafeCell<oneshot::Packet<T>>>),
|
||||
Stream(Arc<UnsafeCell<stream::Packet<T>>>),
|
||||
Shared(Arc<UnsafeCell<shared::Packet<T>>>),
|
||||
Sync(Arc<UnsafeCell<sync::Packet<T>>>),
|
||||
Oneshot(Arc<RacyCell<oneshot::Packet<T>>>),
|
||||
Stream(Arc<RacyCell<stream::Packet<T>>>),
|
||||
Shared(Arc<RacyCell<shared::Packet<T>>>),
|
||||
Sync(Arc<RacyCell<sync::Packet<T>>>),
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -472,7 +477,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
|
||||
/// ```
|
||||
#[unstable]
|
||||
pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
|
||||
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<T: Send>() -> (Sender<T>, Receiver<T>) {
|
||||
#[unstable = "this function may be renamed to more accurately reflect the type \
|
||||
of channel that is is creating"]
|
||||
pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
|
||||
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<T: Send> Sender<T> {
|
||||
fn new(inner: Flavor<T>) -> Sender<T> {
|
||||
Sender {
|
||||
inner: UnsafeCell::new(inner),
|
||||
_marker: marker::NoSync,
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,7 +598,8 @@ impl<T: Send> Sender<T> {
|
||||
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<T: Send> Clone for Sender<T> {
|
||||
fn clone(&self) -> Sender<T> {
|
||||
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<T: Send> Clone for Sender<T> {
|
||||
}
|
||||
}
|
||||
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<T: Send> Drop for Sender<T> {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T: Send> SyncSender<T> {
|
||||
fn new(inner: Arc<UnsafeCell<sync::Packet<T>>>) -> SyncSender<T> {
|
||||
fn new(inner: Arc<RacyCell<sync::Packet<T>>>) -> SyncSender<T> {
|
||||
SyncSender { inner: inner, _marker: marker::NoSync }
|
||||
}
|
||||
|
||||
@ -775,7 +780,7 @@ impl<T: Send> Drop for SyncSender<T> {
|
||||
|
||||
impl<T: Send> Receiver<T> {
|
||||
fn new(inner: Flavor<T>) -> Receiver<T> {
|
||||
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<T: Send> Drop for Receiver<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A version of `UnsafeCell` intended for use in concurrent data
|
||||
/// structures (for example, you might put it in an `Arc`).
|
||||
struct RacyCell<T>(pub UnsafeCell<T>);
|
||||
|
||||
impl<T> RacyCell<T> {
|
||||
|
||||
fn new(value: T) -> RacyCell<T> {
|
||||
RacyCell(UnsafeCell { value: value })
|
||||
}
|
||||
|
||||
unsafe fn get(&self) -> *mut T {
|
||||
self.0.get()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsafe impl<T:Send> Send for RacyCell<T> { }
|
||||
|
||||
unsafe impl<T> kinds::Sync for RacyCell<T> { } // Oh dear
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -76,6 +76,9 @@ pub struct Queue<T> {
|
||||
tail: UnsafeCell<*mut Node<T>>,
|
||||
}
|
||||
|
||||
unsafe impl<T:Send> Send for Queue<T> { }
|
||||
unsafe impl<T:Send> Sync for Queue<T> { }
|
||||
|
||||
impl<T> Node<T> {
|
||||
unsafe fn new(v: Option<T>) -> *mut Node<T> {
|
||||
mem::transmute(box Node {
|
||||
|
@ -73,6 +73,10 @@ pub struct Queue<T> {
|
||||
cache_subtractions: AtomicUint,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for Queue<T> { }
|
||||
|
||||
unsafe impl<T: Send> Sync for Queue<T> { }
|
||||
|
||||
impl<T: Send> Node<T> {
|
||||
fn new() -> *mut Node<T> {
|
||||
unsafe {
|
||||
|
@ -53,6 +53,10 @@ pub struct Packet<T> {
|
||||
lock: Mutex<State<T>>,
|
||||
}
|
||||
|
||||
unsafe impl<T:Send> Send for Packet<T> { }
|
||||
|
||||
unsafe impl<T:Send> Sync for Packet<T> { }
|
||||
|
||||
struct State<T> {
|
||||
disconnected: bool, // Is the channel disconnected yet?
|
||||
queue: Queue, // queue of senders waiting to send data
|
||||
@ -69,6 +73,8 @@ struct State<T> {
|
||||
canceled: Option<&'static mut bool>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for State<T> {}
|
||||
|
||||
/// 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<T> {
|
||||
buf: Vec<Option<T>>,
|
||||
|
@ -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<R> {
|
||||
cap: uint,
|
||||
}
|
||||
|
||||
|
||||
unsafe impl<R: Send> Send for BufferedReader<R> {}
|
||||
unsafe impl<R: Send+Sync> Sync for BufferedReader<R> {}
|
||||
|
||||
|
||||
impl<R: Reader> BufferedReader<R> {
|
||||
/// Creates a new `BufferedReader` with the specified buffer capacity
|
||||
pub fn with_capacity(cap: uint, inner: R) -> BufferedReader<R> {
|
||||
|
@ -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<StdReader>);
|
||||
|
||||
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<Mutex<BufferedReader<StdReader>>>,
|
||||
inner: Arc<Mutex<RaceBox>>,
|
||||
}
|
||||
|
||||
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<StdReader>>,
|
||||
inner: MutexGuard<'a, RaceBox>,
|
||||
}
|
||||
|
||||
impl<'a> Deref<BufferedReader<StdReader>> for StdinReaderGuard<'a> {
|
||||
fn deref(&self) -> &BufferedReader<StdReader> {
|
||||
&*self.inner
|
||||
&self.inner.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut<BufferedReader<StdReader>> for StdinReaderGuard<'a> {
|
||||
fn deref_mut(&mut self) -> &mut BufferedReader<StdReader> {
|
||||
&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<String> {
|
||||
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<Vec<u8>> {
|
||||
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<char> {
|
||||
self.inner.lock().read_char()
|
||||
self.inner.lock().0.read_char()
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for StdinReader {
|
||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
|
||||
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<uint> {
|
||||
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<u8>) -> IoResult<uint> {
|
||||
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<Vec<u8>> {
|
||||
self.inner.lock().read_to_end()
|
||||
self.inner.lock().0.read_to_end()
|
||||
}
|
||||
|
||||
fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult<u64> {
|
||||
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<u64> {
|
||||
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
|
||||
|
@ -26,6 +26,10 @@ pub struct Exclusive<T> {
|
||||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T:Send> Send for Exclusive<T> { }
|
||||
|
||||
unsafe impl<T:Send> Sync for Exclusive<T> { }
|
||||
|
||||
/// An RAII guard returned via `lock`
|
||||
pub struct ExclusiveGuard<'a, T:'a> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -58,6 +58,9 @@ use time::Duration;
|
||||
/// ```
|
||||
pub struct Condvar { inner: Box<StaticCondvar> }
|
||||
|
||||
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,
|
||||
|
@ -73,6 +73,10 @@ pub struct Mutex<T> {
|
||||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T:Send> Send for Mutex<T> { }
|
||||
|
||||
unsafe impl<T:Send> Sync for Mutex<T> { }
|
||||
|
||||
/// 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<poison::Flag>,
|
||||
}
|
||||
|
||||
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<T>(Arc<(Mutex<T>, Condvar)>);
|
||||
|
||||
unsafe impl<T:'static+Send> Send for Packet<T> {}
|
||||
unsafe impl<T> Sync for Packet<T> {}
|
||||
|
||||
#[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 {
|
||||
|
@ -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,
|
||||
|
@ -60,6 +60,9 @@ pub struct RWLock<T> {
|
||||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T:'static+Send> Send for RWLock<T> {}
|
||||
unsafe impl<T> Sync for RWLock<T> {}
|
||||
|
||||
/// 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<poison::Flag>,
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -59,6 +59,15 @@ pub struct Helper<M> {
|
||||
pub shutdown: UnsafeCell<bool>,
|
||||
}
|
||||
|
||||
unsafe impl<M:Send> Send for Helper<M> { }
|
||||
|
||||
unsafe impl<M:Send> Sync for Helper<M> { }
|
||||
|
||||
struct RaceBox(helper_signal::signal);
|
||||
|
||||
unsafe impl Send for RaceBox {}
|
||||
unsafe impl Sync for RaceBox {}
|
||||
|
||||
impl<M: Send> Helper<M> {
|
||||
/// Lazily boots a helper thread, becoming a no-op if the helper has already
|
||||
/// been spawned.
|
||||
@ -81,9 +90,11 @@ impl<M: Send> Helper<M> {
|
||||
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()
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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],
|
||||
|
@ -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 {
|
||||
|
@ -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<u64>) -> IoResult<UnixStream> {
|
||||
@ -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<UnixListener> {
|
||||
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() }
|
||||
|
||||
|
@ -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,
|
||||
|
@ -33,6 +33,8 @@ pub struct TcpListener {
|
||||
pub inner: FileDesc,
|
||||
}
|
||||
|
||||
unsafe impl Sync for TcpListener {}
|
||||
|
||||
impl TcpListener {
|
||||
pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
|
||||
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() }
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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<libc::HANDLE> {
|
||||
// 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<UnixListener> {
|
||||
// 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<UnixStream> {
|
||||
// This function has some funky implementation details when working with
|
||||
|
@ -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<Event> {
|
||||
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<TcpListener> {
|
||||
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() }
|
||||
|
||||
|
@ -48,6 +48,9 @@ pub enum Req {
|
||||
RemoveTimer(libc::HANDLE, Sender<()>),
|
||||
}
|
||||
|
||||
unsafe impl Send for Req {}
|
||||
|
||||
|
||||
fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
|
||||
let mut objs = vec![input];
|
||||
let mut chans = vec![];
|
||||
|
@ -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<T: Send>(self, f: Thunk<(), T>) -> JoinGuard<T> {
|
||||
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<Inner>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for Thread {}
|
||||
|
||||
impl Thread {
|
||||
// Used only internally to construct a thread object without spawning
|
||||
fn new(name: Option<String>) -> 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<T> = ::result::Result<T, Box<Any + Send>>;
|
||||
|
||||
struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
|
||||
|
||||
unsafe impl<T:'static+Send> Send for Packet<T> {}
|
||||
unsafe impl<T> Sync for Packet<T> {}
|
||||
|
||||
#[must_use]
|
||||
/// An RAII-style guard that will block until thread termination when dropped.
|
||||
///
|
||||
@ -387,9 +396,11 @@ pub struct JoinGuard<T> {
|
||||
native: imp::rust_thread,
|
||||
thread: Thread,
|
||||
joined: bool,
|
||||
packet: Arc<UnsafeCell<Option<Result<T>>>>,
|
||||
packet: Packet<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Sync for JoinGuard<T> {}
|
||||
|
||||
impl<T: Send> JoinGuard<T> {
|
||||
/// Extract a handle to the thread this guard will join on.
|
||||
pub fn thread(&self) -> &Thread {
|
||||
@ -406,7 +417,7 @@ impl<T: Send> JoinGuard<T> {
|
||||
unsafe { imp::join(self.native) };
|
||||
self.joined = true;
|
||||
unsafe {
|
||||
(*self.packet.get()).take().unwrap()
|
||||
(*self.packet.0.get()).take().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,6 +280,8 @@ mod imp {
|
||||
pub dtor_running: UnsafeCell<bool>, // should be Cell
|
||||
}
|
||||
|
||||
unsafe impl<T> ::kinds::Sync for Key<T> { }
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T> Key<T> {
|
||||
pub unsafe fn get(&'static self) -> Option<&'static T> {
|
||||
@ -410,6 +412,8 @@ mod imp {
|
||||
pub os: OsStaticKey,
|
||||
}
|
||||
|
||||
unsafe impl<T> ::kinds::Sync for Key<T> { }
|
||||
|
||||
struct Value<T: 'static> {
|
||||
key: &'static Key<T>,
|
||||
value: T,
|
||||
|
@ -198,10 +198,11 @@ impl<T> Key<T> {
|
||||
mod imp {
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
// FIXME: Should be a `Cell`, but that's not `Sync`
|
||||
#[doc(hidden)]
|
||||
pub struct KeyInner<T> { pub inner: UnsafeCell<*mut T> }
|
||||
|
||||
unsafe impl<T> ::kinds::Sync for KeyInner<T> { }
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T> KeyInner<T> {
|
||||
#[doc(hidden)]
|
||||
@ -222,6 +223,8 @@ mod imp {
|
||||
pub marker: marker::InvariantType<T>,
|
||||
}
|
||||
|
||||
unsafe impl<T> ::kinds::Sync for KeyInner<T> { }
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T> KeyInner<T> {
|
||||
#[doc(hidden)]
|
||||
|
@ -26,8 +26,11 @@ pub fn expand_deriving_bound<F>(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 \
|
||||
|
@ -976,6 +976,8 @@ enum TestEvent {
|
||||
|
||||
pub type MonitorMsg = (TestDesc, TestResult, Vec<u8> );
|
||||
|
||||
unsafe impl Send for MonitorMsg {}
|
||||
|
||||
fn run_tests<F>(opts: &TestOpts,
|
||||
tests: Vec<TestDescAndFn> ,
|
||||
mut callback: F) -> io::IoResult<()> where
|
||||
|
@ -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>(T);
|
||||
|
||||
unsafe impl<T: 'static> Send for Racy<T> {}
|
||||
|
||||
/// 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)
|
||||
});
|
||||
}
|
||||
|
@ -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>(T);
|
||||
|
||||
unsafe impl<T: 'static> Send for Racy<T> {}
|
||||
|
||||
// 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)
|
||||
});
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -33,4 +33,5 @@ struct A {
|
||||
fn main() {
|
||||
let a = A {v: box B{v: None} as Box<Foo+Send>};
|
||||
//~^ ERROR the trait `core::kinds::Send` is not implemented
|
||||
//~^^ ERROR the trait `core::kinds::Send` is not implemented
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ use std::cell::RefCell;
|
||||
// Regresion test for issue 7364
|
||||
static boxed: Box<RefCell<int>> = 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() { }
|
||||
|
@ -9,19 +9,6 @@
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
struct Foo {
|
||||
f: Rc<int>,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ fn bar<F:FnOnce() + Send>(_: 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
|
||||
}
|
||||
|
||||
|
@ -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<T: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() {
|
||||
|
@ -14,5 +14,8 @@ fn f<T: Sync>(_: 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
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<T: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::<UniqueUnsafePtr>();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -17,4 +17,5 @@ fn test_send<S: Send>() {}
|
||||
pub fn main() {
|
||||
test_send::<rand::TaskRng>();
|
||||
//~^ ERROR `core::kinds::Send` is not implemented
|
||||
//~^^ ERROR `core::kinds::Send` is not implemented
|
||||
}
|
||||
|
@ -30,12 +30,15 @@ fn test<T: Sync>(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);
|
||||
|
@ -16,5 +16,7 @@ fn f<T:Send>(_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
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ fn foo(i:int, j: Rc<String>) -> 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)));
|
||||
}
|
||||
|
@ -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<T>(a: T) -> T {
|
||||
a
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -11,38 +11,46 @@
|
||||
use std::kinds::marker;
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
struct MyUnsafePack<T>(UnsafeCell<T>);
|
||||
|
||||
unsafe impl<T: Send> Sync for MyUnsafePack<T> {}
|
||||
|
||||
struct MyUnsafe<T> {
|
||||
value: UnsafeCell<T>
|
||||
value: MyUnsafePack<T>
|
||||
}
|
||||
|
||||
impl<T> MyUnsafe<T> {
|
||||
fn forbidden(&self) {}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Sync for MyUnsafe<T> {}
|
||||
|
||||
enum UnsafeEnum<T> {
|
||||
VariantSafe,
|
||||
VariantUnsafe(UnsafeCell<T>)
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Sync for UnsafeEnum<T> {}
|
||||
|
||||
static STATIC1: UnsafeEnum<int> = UnsafeEnum::VariantSafe;
|
||||
|
||||
static STATIC2: UnsafeCell<int> = UnsafeCell { value: 1 };
|
||||
const CONST: UnsafeCell<int> = UnsafeCell { value: 1 };
|
||||
static STATIC2: MyUnsafePack<int> = MyUnsafePack(UnsafeCell { value: 1 });
|
||||
const CONST: MyUnsafePack<int> = MyUnsafePack(UnsafeCell { value: 1 });
|
||||
static STATIC3: MyUnsafe<int> = MyUnsafe{value: CONST};
|
||||
|
||||
static STATIC4: &'static UnsafeCell<int> = &STATIC2;
|
||||
static STATIC4: &'static MyUnsafePack<int> = &STATIC2;
|
||||
|
||||
struct Wrap<T> {
|
||||
value: T
|
||||
}
|
||||
|
||||
static UNSAFE: UnsafeCell<int> = UnsafeCell{value: 1};
|
||||
static WRAPPED_UNSAFE: Wrap<&'static UnsafeCell<int>> = Wrap { value: &UNSAFE };
|
||||
unsafe impl<T: Send> Sync for Wrap<T> {}
|
||||
|
||||
static UNSAFE: MyUnsafePack<int> = MyUnsafePack(UnsafeCell{value: 2});
|
||||
static WRAPPED_UNSAFE: Wrap<&'static MyUnsafePack<int>> = Wrap { value: &UNSAFE };
|
||||
|
||||
fn main() {
|
||||
let a = &STATIC1;
|
||||
|
||||
STATIC3.forbidden()
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<T> {
|
||||
state: state,
|
||||
@ -45,6 +46,8 @@ pub mod pipes {
|
||||
payload: Option<T>
|
||||
}
|
||||
|
||||
unsafe impl<T:Send> Send for packet<T> {}
|
||||
|
||||
pub fn packet<T:Send>() -> *const packet<T> {
|
||||
unsafe {
|
||||
let p: *const packet<T> = mem::transmute(box Stuff{
|
||||
@ -230,8 +233,13 @@ pub mod pingpong {
|
||||
use std::mem;
|
||||
|
||||
pub struct ping(::pipes::send_packet<pong>);
|
||||
|
||||
unsafe impl Send for ping {}
|
||||
|
||||
pub struct pong(::pipes::send_packet<ping>);
|
||||
|
||||
unsafe impl Send for pong {}
|
||||
|
||||
pub fn liberate_ping(p: ping) -> ::pipes::send_packet<pong> {
|
||||
unsafe {
|
||||
let _addr : *const ::pipes::send_packet<pong> = match &p {
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user