Skip to content

Commit

Permalink
Suggest using move when trying to share `...::channel::{Receiver, S…
Browse files Browse the repository at this point in the history
…ender}`

Extend `rustc_on_unimplemented` to match on ADT without evaluating type
arguments.
  • Loading branch information
estebank committed Mar 15, 2018
1 parent 6d8a173 commit fe19754
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 14 deletions.
8 changes: 8 additions & 0 deletions src/libcore/marker.rs
Expand Up @@ -344,6 +344,14 @@ pub trait Copy : Clone {
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sync"]
#[rustc_on_unimplemented(
on(
_Self="std::sync::mpsc::Receiver<T>",
label="`{Self}` cannot be shared safely, if using a closure consider marking it `move`"
),
on(
_Self="std::sync::mpsc::Sender<T>",
label="`{Self}` cannot be shared safely, if using a closure consider marking it `move`"
),
message="`{Self}` cannot be shared between threads safely",
label="`{Self}` cannot be shared between threads safely"
)]
Expand Down
31 changes: 17 additions & 14 deletions src/librustc/traits/error_reporting.rs
Expand Up @@ -338,18 +338,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
.unwrap_or(trait_ref.def_id());
let trait_ref = *trait_ref.skip_binder();

let desugaring;
let method;
let mut flags = vec![];
let direct = match obligation.cause.code {
match obligation.cause.code {
ObligationCauseCode::BuiltinDerivedObligation(..) |
ObligationCauseCode::ImplDerivedObligation(..) => false,
_ => true
};
if direct {
// this is a "direct", user-specified, rather than derived,
// obligation.
flags.push(("direct".to_string(), None));
ObligationCauseCode::ImplDerivedObligation(..) => {}
_ => {
// this is a "direct", user-specified, rather than derived,
// obligation.
flags.push(("direct".to_string(), None));
}
}

if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
Expand All @@ -359,21 +356,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
//
// Currently I'm leaving it for what I need for `try`.
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
method = self.tcx.item_name(item);
let method = self.tcx.item_name(item);
flags.push(("from_method".to_string(), None));
flags.push(("from_method".to_string(), Some(method.to_string())));
}
}

if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
desugaring = k.as_symbol().as_str();
let desugaring = k.as_symbol().as_str();
flags.push(("from_desugaring".to_string(), None));
flags.push(("from_desugaring".to_string(), Some(desugaring.to_string())));
}
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_ref.self_ty();
let self_ty_str = self_ty.to_string();
flags.push(("_Self".to_string(), Some(self_ty_str.clone())));
// This is also included through the generics list as `Self`,
// but the parser won't allow you to use it
flags.push(("_Self".to_string(), Some(self_ty.to_string())));
if let Some(def) = self_ty.ty_adt_def() {
// We also want to be able to select self's original
// signature with no type arguments resolved
flags.push(("_Self".to_string(), Some(self.tcx.type_of(def.did).to_string())));
}

for param in generics.types.iter() {
let name = param.name.as_str().to_string();
Expand Down
32 changes: 32 additions & 0 deletions src/test/ui/closure-move-sync.rs
@@ -0,0 +1,32 @@
// Copyright 2018 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 std::thread;
use std::sync::mpsc::channel;

fn bar() {
let (send, recv) = channel();
let t = thread::spawn(|| {
recv.recv().unwrap();
//~^^ ERROR `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely
});

send.send(());

t.join().unwrap();
}

fn foo() {
let (tx, _rx) = channel();
thread::spawn(|| tx.send(()).unwrap());
//~^ ERROR `std::sync::mpsc::Sender<()>` cannot be shared between threads safely
}

fn main() {}
24 changes: 24 additions & 0 deletions src/test/ui/closure-move-sync.stderr
@@ -0,0 +1,24 @@
error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely
--> $DIR/closure-move-sync.rs:16:13
|
16 | let t = thread::spawn(|| {
| ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared safely, if using a closure consider marking it `move`
|
= help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>`
= note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>`
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:16:27: 19:6 recv:&std::sync::mpsc::Receiver<()>]`
= note: required by `std::thread::spawn`

error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads safely
--> $DIR/closure-move-sync.rs:28:5
|
28 | thread::spawn(|| tx.send(()).unwrap());
| ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared safely, if using a closure consider marking it `move`
|
= help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>`
= note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>`
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:28:19: 28:42 tx:&std::sync::mpsc::Sender<()>]`
= note: required by `std::thread::spawn`

error: aborting due to 2 previous errors

0 comments on commit fe19754

Please sign in to comment.