Skip to content

Commit fe19754

Browse files
committed
Suggest using move when trying to share ...::channel::{Receiver, Sender}
Extend `rustc_on_unimplemented` to match on ADT without evaluating type arguments.
1 parent 6d8a173 commit fe19754

File tree

4 files changed

+81
-14
lines changed

4 files changed

+81
-14
lines changed

src/libcore/marker.rs

+8
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,14 @@ pub trait Copy : Clone {
344344
#[stable(feature = "rust1", since = "1.0.0")]
345345
#[lang = "sync"]
346346
#[rustc_on_unimplemented(
347+
on(
348+
_Self="std::sync::mpsc::Receiver<T>",
349+
label="`{Self}` cannot be shared safely, if using a closure consider marking it `move`"
350+
),
351+
on(
352+
_Self="std::sync::mpsc::Sender<T>",
353+
label="`{Self}` cannot be shared safely, if using a closure consider marking it `move`"
354+
),
347355
message="`{Self}` cannot be shared between threads safely",
348356
label="`{Self}` cannot be shared between threads safely"
349357
)]

src/librustc/traits/error_reporting.rs

+17-14
Original file line numberDiff line numberDiff line change
@@ -338,18 +338,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
338338
.unwrap_or(trait_ref.def_id());
339339
let trait_ref = *trait_ref.skip_binder();
340340

341-
let desugaring;
342-
let method;
343341
let mut flags = vec![];
344-
let direct = match obligation.cause.code {
342+
match obligation.cause.code {
345343
ObligationCauseCode::BuiltinDerivedObligation(..) |
346-
ObligationCauseCode::ImplDerivedObligation(..) => false,
347-
_ => true
348-
};
349-
if direct {
350-
// this is a "direct", user-specified, rather than derived,
351-
// obligation.
352-
flags.push(("direct".to_string(), None));
344+
ObligationCauseCode::ImplDerivedObligation(..) => {}
345+
_ => {
346+
// this is a "direct", user-specified, rather than derived,
347+
// obligation.
348+
flags.push(("direct".to_string(), None));
349+
}
353350
}
354351

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

368365
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
369-
desugaring = k.as_symbol().as_str();
366+
let desugaring = k.as_symbol().as_str();
370367
flags.push(("from_desugaring".to_string(), None));
371368
flags.push(("from_desugaring".to_string(), Some(desugaring.to_string())));
372369
}
373370
let generics = self.tcx.generics_of(def_id);
374371
let self_ty = trait_ref.self_ty();
375-
let self_ty_str = self_ty.to_string();
376-
flags.push(("_Self".to_string(), Some(self_ty_str.clone())));
372+
// This is also included through the generics list as `Self`,
373+
// but the parser won't allow you to use it
374+
flags.push(("_Self".to_string(), Some(self_ty.to_string())));
375+
if let Some(def) = self_ty.ty_adt_def() {
376+
// We also want to be able to select self's original
377+
// signature with no type arguments resolved
378+
flags.push(("_Self".to_string(), Some(self.tcx.type_of(def.did).to_string())));
379+
}
377380

378381
for param in generics.types.iter() {
379382
let name = param.name.as_str().to_string();

src/test/ui/closure-move-sync.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::thread;
12+
use std::sync::mpsc::channel;
13+
14+
fn bar() {
15+
let (send, recv) = channel();
16+
let t = thread::spawn(|| {
17+
recv.recv().unwrap();
18+
//~^^ ERROR `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely
19+
});
20+
21+
send.send(());
22+
23+
t.join().unwrap();
24+
}
25+
26+
fn foo() {
27+
let (tx, _rx) = channel();
28+
thread::spawn(|| tx.send(()).unwrap());
29+
//~^ ERROR `std::sync::mpsc::Sender<()>` cannot be shared between threads safely
30+
}
31+
32+
fn main() {}

src/test/ui/closure-move-sync.stderr

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely
2+
--> $DIR/closure-move-sync.rs:16:13
3+
|
4+
16 | let t = thread::spawn(|| {
5+
| ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared safely, if using a closure consider marking it `move`
6+
|
7+
= help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>`
8+
= note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>`
9+
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:16:27: 19:6 recv:&std::sync::mpsc::Receiver<()>]`
10+
= note: required by `std::thread::spawn`
11+
12+
error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads safely
13+
--> $DIR/closure-move-sync.rs:28:5
14+
|
15+
28 | thread::spawn(|| tx.send(()).unwrap());
16+
| ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared safely, if using a closure consider marking it `move`
17+
|
18+
= help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>`
19+
= note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>`
20+
= note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:28:19: 28:42 tx:&std::sync::mpsc::Sender<()>]`
21+
= note: required by `std::thread::spawn`
22+
23+
error: aborting due to 2 previous errors
24+

0 commit comments

Comments
 (0)