Skip to content

Implement RFC 458: improve Send #22319

New issue

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

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

Already on GitHub? Sign in to your account

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,19 @@ use clone::Clone;
reason = "will be overhauled with new lifetime rules; see RFC 458")]
#[lang="send"]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
#[cfg(stage0)] // SNAP ac134f7 remove after stage0
pub unsafe trait Send: 'static {
// empty.
}
/// Types able to be transferred across thread boundaries.
#[unstable(feature = "core",
reason = "will be overhauled with new lifetime rules; see RFC 458")]
#[lang="send"]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
#[cfg(not(stage0))]
pub unsafe trait Send {
// empty.
}

/// Types with a constant size known at compile-time.
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -424,3 +434,11 @@ pub struct NoCopy;
#[lang="managed_bound"]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Managed;

#[cfg(not(stage0))] // SNAP ac134f7 remove this attribute after the next snapshot
mod impls {
use super::{Send, Sync, Sized};

unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
}
32 changes: 3 additions & 29 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use self::EvaluationResult::*;
use super::{DerivedObligationCause};
use super::{project};
use super::project::Normalized;
use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause};
use super::{PredicateObligation, TraitObligation, ObligationCause};
use super::{ObligationCauseCode, BuiltinDerivedObligation};
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
use super::{Selection};
Expand All @@ -34,7 +34,7 @@ use super::{util};
use middle::fast_reject;
use middle::mem_categorization::Typer;
use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
use middle::ty::{self, AsPredicate, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener};
use middle::ty_fold::TypeFoldable;
Expand Down Expand Up @@ -1459,22 +1459,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

ty::BoundSync |
ty::BoundSend => {
// Note: technically, a region pointer is only
// sendable if it has lifetime
// `'static`. However, we don't take regions
// into account when doing trait matching:
// instead, when we decide that `T : Send`, we
// will register a separate constraint with
// the region inferencer that `T : 'static`
// holds as well (because the trait `Send`
// requires it). This will ensure that there
// is no borrowed data in `T` (or else report
// an inference error). The reason we do it
// this way is that we do not yet *know* what
// lifetime the borrowed reference has, since
// we haven't finished running inference -- in
// other words, there's a kind of
// chicken-and-egg problem.
Ok(If(vec![referent_ty]))
}
}
Expand Down Expand Up @@ -1817,21 +1801,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
})
}).collect::<Result<_, _>>();
let mut obligations = match obligations {
let obligations = match obligations {
Ok(o) => o,
Err(ErrorReported) => Vec::new()
};

// as a special case, `Send` requires `'static`
if bound == ty::BoundSend {
obligations.push(Obligation {
cause: obligation.cause.clone(),
recursion_depth: obligation.recursion_depth+1,
predicate: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(),
ty::ReStatic)).as_predicate(),
});
}

let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new());

debug!("vtable_builtin_data: obligations={}",
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,8 @@ impl<'tcx> UserString<'tcx> for ty::TyTrait<'tcx> {
}

// Region, if not obviously implied by builtin bounds.
if bounds.region_bound != ty::ReStatic ||
!bounds.builtin_bounds.contains(&ty::BoundSend)
{ // Region bound is implied by builtin bounds:
if bounds.region_bound != ty::ReStatic {
// Region bound is implied by builtin bounds:
components.push(bounds.region_bound.user_string(tcx));
}

Expand Down
2 changes: 1 addition & 1 deletion src/libstd/old_io/net/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ mod tests {

pub fn smalltest<F,G>(server: F, client: G)
where F : FnOnce(UnixStream), F : Send,
G : FnOnce(UnixStream), G : Send
G : FnOnce(UnixStream), G : Send + 'static
{
let path1 = next_test_unix();
let path2 = path1.clone();
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ impl Child {
/// the parent waits for the child to exit.
pub fn wait_with_output(mut self) -> io::Result<Output> {
drop(self.stdin.take());
fn read<T: Read + Send>(stream: Option<T>) -> Receiver<io::Result<Vec<u8>>> {
fn read<T: Read + Send + 'static>(stream: Option<T>) -> Receiver<io::Result<Vec<u8>>> {
let (tx, rx) = channel();
match stream {
Some(stream) => {
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/rt/at_exit_imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use mem;
use thunk::Thunk;
use sys_common::mutex::{Mutex, MUTEX_INIT};

type Queue = Vec<Thunk>;
type Queue = Vec<Thunk<'static>>;

// NB these are specifically not types from `std::sync` as they currently rely
// on poisoning and this module needs to operate at a lower level than requiring
Expand Down Expand Up @@ -65,7 +65,7 @@ pub fn cleanup() {
}
}

pub fn push(f: Thunk) {
pub fn push(f: Thunk<'static>) {
unsafe {
LOCK.lock();
init();
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/rt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
///
/// It is forbidden for procedures to register more `at_exit` handlers when they
/// are running, and doing so will lead to a process abort.
pub fn at_exit<F:FnOnce()+Send>(f: F) {
pub fn at_exit<F:FnOnce()+Send+'static>(f: F) {
at_exit_imp::push(Thunk::new(f));
}

Expand Down
4 changes: 2 additions & 2 deletions src/libstd/rt/unwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ use rt::libunwind as uw;

struct Exception {
uwe: uw::_Unwind_Exception,
cause: Option<Box<Any + Send>>,
cause: Option<Box<Any + Send + 'static>>,
}

pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: uint);
Expand Down Expand Up @@ -161,7 +161,7 @@ pub fn panicking() -> bool {
#[inline(never)]
#[no_mangle]
#[allow(private_no_mangle_fns)]
fn rust_panic(cause: Box<Any + Send>) -> ! {
fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
rtdebug!("begin_unwind()");

unsafe {
Expand Down
8 changes: 4 additions & 4 deletions src/libstd/sync/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub struct Future<A> {
}

enum FutureState<A> {
Pending(Thunk<(),A>),
Pending(Thunk<'static,(),A>),
Evaluating,
Forced(A)
}
Expand Down Expand Up @@ -103,7 +103,7 @@ impl<A> Future<A> {
}

pub fn from_fn<F>(f: F) -> Future<A>
where F : FnOnce() -> A, F : Send
where F : FnOnce() -> A, F : Send + 'static
{
/*!
* Create a future from a function.
Expand All @@ -117,7 +117,7 @@ impl<A> Future<A> {
}
}

impl<A:Send> Future<A> {
impl<A:Send+'static> Future<A> {
pub fn from_receiver(rx: Receiver<A>) -> Future<A> {
/*!
* Create a future from a port
Expand All @@ -132,7 +132,7 @@ impl<A:Send> Future<A> {
}

pub fn spawn<F>(blk: F) -> Future<A>
where F : FnOnce() -> A, F : Send
where F : FnOnce() -> A, F : Send + 'static
{
/*!
* Create a future from a unique closure.
Expand Down
30 changes: 15 additions & 15 deletions src/libstd/sync/mpsc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ pub struct Receiver<T> {

// 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> { }
unsafe impl<T: Send + 'static> 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
Expand All @@ -364,7 +364,7 @@ pub struct Sender<T> {

// 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> { }
unsafe impl<T: Send + 'static> 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.
Expand All @@ -373,7 +373,7 @@ pub struct SyncSender<T> {
inner: Arc<UnsafeCell<sync::Packet<T>>>,
}

unsafe impl<T:Send> Send for SyncSender<T> {}
unsafe impl<T: Send + 'static> Send for SyncSender<T> {}

impl<T> !Sync for SyncSender<T> {}

Expand Down Expand Up @@ -485,7 +485,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
/// println!("{:?}", rx.recv().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
pub fn channel<T: Send + 'static>() -> (Sender<T>, Receiver<T>) {
let a = Arc::new(UnsafeCell::new(oneshot::Packet::new()));
(Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a)))
}
Expand Down Expand Up @@ -525,7 +525,7 @@ pub fn channel<T: Send>() -> (Sender<T>, Receiver<T>) {
/// assert_eq!(rx.recv().unwrap(), 2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
pub fn sync_channel<T: Send + 'static>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound)));
(SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a)))
}
Expand All @@ -534,7 +534,7 @@ pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
// Sender
////////////////////////////////////////////////////////////////////////////////

impl<T: Send> Sender<T> {
impl<T: Send + 'static> Sender<T> {
fn new(inner: Flavor<T>) -> Sender<T> {
Sender {
inner: UnsafeCell::new(inner),
Expand Down Expand Up @@ -616,7 +616,7 @@ impl<T: Send> Sender<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> Clone for Sender<T> {
impl<T: Send + 'static> Clone for Sender<T> {
fn clone(&self) -> Sender<T> {
let (packet, sleeper, guard) = match *unsafe { self.inner() } {
Flavor::Oneshot(ref p) => {
Expand Down Expand Up @@ -662,7 +662,7 @@ impl<T: Send> Clone for Sender<T> {

#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> Drop for Sender<T> {
impl<T: Send + 'static> Drop for Sender<T> {
fn drop(&mut self) {
match *unsafe { self.inner_mut() } {
Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); },
Expand All @@ -677,7 +677,7 @@ impl<T: Send> Drop for Sender<T> {
// SyncSender
////////////////////////////////////////////////////////////////////////////////

impl<T: Send> SyncSender<T> {
impl<T: Send + 'static> SyncSender<T> {
fn new(inner: Arc<UnsafeCell<sync::Packet<T>>>) -> SyncSender<T> {
SyncSender { inner: inner }
}
Expand Down Expand Up @@ -717,7 +717,7 @@ impl<T: Send> SyncSender<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> Clone for SyncSender<T> {
impl<T: Send + 'static> Clone for SyncSender<T> {
fn clone(&self) -> SyncSender<T> {
unsafe { (*self.inner.get()).clone_chan(); }
return SyncSender::new(self.inner.clone());
Expand All @@ -726,7 +726,7 @@ impl<T: Send> Clone for SyncSender<T> {

#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> Drop for SyncSender<T> {
impl<T: Send + 'static> Drop for SyncSender<T> {
fn drop(&mut self) {
unsafe { (*self.inner.get()).drop_chan(); }
}
Expand All @@ -736,7 +736,7 @@ impl<T: Send> Drop for SyncSender<T> {
// Receiver
////////////////////////////////////////////////////////////////////////////////

impl<T: Send> Receiver<T> {
impl<T: Send + 'static> Receiver<T> {
fn new(inner: Flavor<T>) -> Receiver<T> {
Receiver { inner: UnsafeCell::new(inner) }
}
Expand Down Expand Up @@ -855,7 +855,7 @@ impl<T: Send> Receiver<T> {
}
}

impl<T: Send> select::Packet for Receiver<T> {
impl<T: Send + 'static> select::Packet for Receiver<T> {
fn can_recv(&self) -> bool {
loop {
let new_port = match *unsafe { self.inner() } {
Expand Down Expand Up @@ -942,15 +942,15 @@ impl<T: Send> select::Packet for Receiver<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Send> Iterator for Iter<'a, T> {
impl<'a, T: Send + 'static> Iterator for Iter<'a, T> {
type Item = T;

fn next(&mut self) -> Option<T> { self.rx.recv().ok() }
}

#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> Drop for Receiver<T> {
impl<T: Send + 'static> Drop for Receiver<T> {
fn drop(&mut self) {
match *unsafe { self.inner_mut() } {
Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); },
Expand Down
6 changes: 3 additions & 3 deletions src/libstd/sync/mpsc/mpsc_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub struct Queue<T> {
}

unsafe impl<T:Send> Send for Queue<T> { }
unsafe impl<T:Send> Sync for Queue<T> { }
unsafe impl<T: Send + 'static> Sync for Queue<T> { }

impl<T> Node<T> {
unsafe fn new(v: Option<T>) -> *mut Node<T> {
Expand All @@ -89,7 +89,7 @@ impl<T> Node<T> {
}
}

impl<T: Send> Queue<T> {
impl<T: Send + 'static> Queue<T> {
/// Creates a new queue that is safe to share among multiple producers and
/// one consumer.
pub fn new() -> Queue<T> {
Expand Down Expand Up @@ -140,7 +140,7 @@ impl<T: Send> Queue<T> {

#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> Drop for Queue<T> {
impl<T: Send + 'static> Drop for Queue<T> {
fn drop(&mut self) {
unsafe {
let mut cur = *self.tail.get();
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/sync/mpsc/oneshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ enum MyUpgrade<T> {
GoUp(Receiver<T>),
}

impl<T: Send> Packet<T> {
impl<T: Send + 'static> Packet<T> {
pub fn new() -> Packet<T> {
Packet {
data: None,
Expand Down Expand Up @@ -368,7 +368,7 @@ impl<T: Send> Packet<T> {
}

#[unsafe_destructor]
impl<T: Send> Drop for Packet<T> {
impl<T: Send + 'static> Drop for Packet<T> {
fn drop(&mut self) {
assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED);
}
Expand Down
Loading