summaryrefslogtreecommitdiffstats
path: root/tests/ui/threads-sendsync
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/threads-sendsync')
-rw-r--r--tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs10
-rw-r--r--tests/ui/threads-sendsync/child-outlives-parent.rs13
-rw-r--r--tests/ui/threads-sendsync/clone-with-exterior.rs20
-rw-r--r--tests/ui/threads-sendsync/comm.rs22
-rw-r--r--tests/ui/threads-sendsync/eprint-on-tls-drop.rs49
-rw-r--r--tests/ui/threads-sendsync/issue-24313.rs32
-rw-r--r--tests/ui/threads-sendsync/issue-29488.rs23
-rw-r--r--tests/ui/threads-sendsync/issue-43733-2.rs30
-rw-r--r--tests/ui/threads-sendsync/issue-43733.mir.stderr19
-rw-r--r--tests/ui/threads-sendsync/issue-43733.rs38
-rw-r--r--tests/ui/threads-sendsync/issue-43733.thir.stderr19
-rw-r--r--tests/ui/threads-sendsync/issue-4446.rs15
-rw-r--r--tests/ui/threads-sendsync/issue-4448.rs16
-rw-r--r--tests/ui/threads-sendsync/issue-8827.rs53
-rw-r--r--tests/ui/threads-sendsync/issue-9396.rs23
-rw-r--r--tests/ui/threads-sendsync/mpsc_stress.rs200
-rw-r--r--tests/ui/threads-sendsync/send-is-not-static-par-for.rs34
-rw-r--r--tests/ui/threads-sendsync/send-resource.rs39
-rw-r--r--tests/ui/threads-sendsync/send-type-inference.rs19
-rw-r--r--tests/ui/threads-sendsync/send_str_hashmap.rs53
-rw-r--r--tests/ui/threads-sendsync/send_str_treemap.rs58
-rw-r--r--tests/ui/threads-sendsync/sendable-class.rs28
-rw-r--r--tests/ui/threads-sendsync/sendfn-is-a-block.rs11
-rw-r--r--tests/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs21
-rw-r--r--tests/ui/threads-sendsync/spawn-fn.rs25
-rw-r--r--tests/ui/threads-sendsync/spawn-types.rs25
-rw-r--r--tests/ui/threads-sendsync/spawn.rs10
-rw-r--r--tests/ui/threads-sendsync/spawn2.rs31
-rw-r--r--tests/ui/threads-sendsync/spawning-with-debug.rs15
-rw-r--r--tests/ui/threads-sendsync/std-sync-right-kind-impls.rs16
-rw-r--r--tests/ui/threads-sendsync/sync-send-atomics.rs14
-rw-r--r--tests/ui/threads-sendsync/sync-send-in-std.rs25
-rw-r--r--tests/ui/threads-sendsync/sync-send-iterators-in-libcollections.rs71
-rw-r--r--tests/ui/threads-sendsync/sync-send-iterators-in-libcore.rs105
-rw-r--r--tests/ui/threads-sendsync/task-comm-0.rs30
-rw-r--r--tests/ui/threads-sendsync/task-comm-1.rs14
-rw-r--r--tests/ui/threads-sendsync/task-comm-10.rs33
-rw-r--r--tests/ui/threads-sendsync/task-comm-11.rs21
-rw-r--r--tests/ui/threads-sendsync/task-comm-12.rs29
-rw-r--r--tests/ui/threads-sendsync/task-comm-13.rs18
-rw-r--r--tests/ui/threads-sendsync/task-comm-14.rs36
-rw-r--r--tests/ui/threads-sendsync/task-comm-15.rs28
-rw-r--r--tests/ui/threads-sendsync/task-comm-16.rs111
-rw-r--r--tests/ui/threads-sendsync/task-comm-17.rs17
-rw-r--r--tests/ui/threads-sendsync/task-comm-3.rs63
-rw-r--r--tests/ui/threads-sendsync/task-comm-4.rs45
-rw-r--r--tests/ui/threads-sendsync/task-comm-5.rs17
-rw-r--r--tests/ui/threads-sendsync/task-comm-6.rs42
-rw-r--r--tests/ui/threads-sendsync/task-comm-7.rs59
-rw-r--r--tests/ui/threads-sendsync/task-comm-9.rs35
-rw-r--r--tests/ui/threads-sendsync/task-comm-chan-nil.rs13
-rw-r--r--tests/ui/threads-sendsync/task-life-0.rs14
-rw-r--r--tests/ui/threads-sendsync/task-spawn-barefn.rs18
-rw-r--r--tests/ui/threads-sendsync/task-spawn-move-and-copy.rs23
-rw-r--r--tests/ui/threads-sendsync/task-stderr.rs26
-rw-r--r--tests/ui/threads-sendsync/tcp-stress.rs64
-rw-r--r--tests/ui/threads-sendsync/test-tasks-invalid-value.rs11
-rw-r--r--tests/ui/threads-sendsync/thread-local-extern-static.rs27
-rw-r--r--tests/ui/threads-sendsync/thread-local-syntax.rs22
-rw-r--r--tests/ui/threads-sendsync/threads.rs16
-rw-r--r--tests/ui/threads-sendsync/tls-dtors-are-run-in-a-static-binary.rs22
-rw-r--r--tests/ui/threads-sendsync/tls-init-on-init.rs44
-rw-r--r--tests/ui/threads-sendsync/tls-try-with.rs30
-rw-r--r--tests/ui/threads-sendsync/trivial-message.rs16
-rw-r--r--tests/ui/threads-sendsync/unwind-resource.rs40
-rw-r--r--tests/ui/threads-sendsync/yield.rs21
-rw-r--r--tests/ui/threads-sendsync/yield1.rs16
-rw-r--r--tests/ui/threads-sendsync/yield2.rs8
68 files changed, 2211 insertions, 0 deletions
diff --git a/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs b/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs
new file mode 100644
index 000000000..4d3c4e8ac
--- /dev/null
+++ b/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs
@@ -0,0 +1,10 @@
+#![feature(cfg_target_thread_local, thread_local)]
+#![crate_type = "lib"]
+
+#[cfg(target_thread_local)]
+use std::cell::Cell;
+
+#[no_mangle]
+#[cfg(target_thread_local)]
+#[thread_local]
+pub static FOO: Cell<u32> = Cell::new(3);
diff --git a/tests/ui/threads-sendsync/child-outlives-parent.rs b/tests/ui/threads-sendsync/child-outlives-parent.rs
new file mode 100644
index 000000000..e3a39a44b
--- /dev/null
+++ b/tests/ui/threads-sendsync/child-outlives-parent.rs
@@ -0,0 +1,13 @@
+// run-pass
+// Reported as issue #126, child leaks the string.
+
+// pretty-expanded FIXME #23616
+// ignore-emscripten no threads support
+
+use std::thread;
+
+fn child2(_s: String) { }
+
+pub fn main() {
+ let _x = thread::spawn(move|| child2("hi".to_string()));
+}
diff --git a/tests/ui/threads-sendsync/clone-with-exterior.rs b/tests/ui/threads-sendsync/clone-with-exterior.rs
new file mode 100644
index 000000000..9fc661b14
--- /dev/null
+++ b/tests/ui/threads-sendsync/clone-with-exterior.rs
@@ -0,0 +1,20 @@
+// run-pass
+
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+
+struct Pair {
+ a: isize,
+ b: isize
+}
+
+pub fn main() {
+ let z: Box<_> = Box::new(Pair { a : 10, b : 12});
+
+ thread::spawn(move|| {
+ assert_eq!(z.a, 10);
+ assert_eq!(z.b, 12);
+ }).join();
+}
diff --git a/tests/ui/threads-sendsync/comm.rs b/tests/ui/threads-sendsync/comm.rs
new file mode 100644
index 000000000..aa86e174d
--- /dev/null
+++ b/tests/ui/threads-sendsync/comm.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::{channel, Sender};
+
+pub fn main() {
+ let (tx, rx) = channel();
+ let t = thread::spawn(move|| { child(&tx) });
+ let y = rx.recv().unwrap();
+ println!("received");
+ println!("{}", y);
+ assert_eq!(y, 10);
+ t.join();
+}
+
+fn child(c: &Sender<isize>) {
+ println!("sending");
+ c.send(10).unwrap();
+ println!("value sent");
+}
diff --git a/tests/ui/threads-sendsync/eprint-on-tls-drop.rs b/tests/ui/threads-sendsync/eprint-on-tls-drop.rs
new file mode 100644
index 000000000..f52430773
--- /dev/null
+++ b/tests/ui/threads-sendsync/eprint-on-tls-drop.rs
@@ -0,0 +1,49 @@
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+use std::cell::RefCell;
+use std::env;
+use std::process::Command;
+
+fn main() {
+ let name = "YOU_ARE_THE_TEST";
+ if env::var(name).is_ok() {
+ std::thread::spawn(|| {
+ TLS.with(|f| f.borrow().ensure());
+ })
+ .join()
+ .unwrap();
+ } else {
+ let me = env::current_exe().unwrap();
+ let output = Command::new(&me).env(name, "1").output().unwrap();
+ println!("{:?}", output);
+ assert!(output.status.success());
+ let stderr = String::from_utf8(output.stderr).unwrap();
+ assert!(stderr.contains("hello new\n"));
+ assert!(stderr.contains("hello drop\n"));
+ }
+}
+
+struct Stuff {
+ _x: usize,
+}
+
+impl Stuff {
+ fn new() -> Self {
+ eprintln!("hello new");
+ Self { _x: 0 }
+ }
+
+ fn ensure(&self) {}
+}
+
+impl Drop for Stuff {
+ fn drop(&mut self) {
+ eprintln!("hello drop");
+ }
+}
+
+thread_local! {
+ static TLS: RefCell<Stuff> = RefCell::new(Stuff::new());
+}
diff --git a/tests/ui/threads-sendsync/issue-24313.rs b/tests/ui/threads-sendsync/issue-24313.rs
new file mode 100644
index 000000000..c28b4ca96
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-24313.rs
@@ -0,0 +1,32 @@
+// run-pass
+// ignore-emscripten no threads
+// ignore-sgx no processes
+
+use std::thread;
+use std::env;
+use std::process::Command;
+
+struct Handle(i32);
+
+impl Drop for Handle {
+ fn drop(&mut self) { panic!(); }
+}
+
+thread_local!(static HANDLE: Handle = Handle(0));
+
+fn main() {
+ let args = env::args().collect::<Vec<_>>();
+ if args.len() == 1 {
+ let out = Command::new(&args[0]).arg("test").output().unwrap();
+ let stderr = std::str::from_utf8(&out.stderr).unwrap();
+ assert!(stderr.contains("panicked at 'explicit panic'"),
+ "bad failure message:\n{}\n", stderr);
+ } else {
+ // TLS dtors are not always run on process exit
+ thread::spawn(|| {
+ HANDLE.with(|h| {
+ println!("{}", h.0);
+ });
+ }).join().unwrap();
+ }
+}
diff --git a/tests/ui/threads-sendsync/issue-29488.rs b/tests/ui/threads-sendsync/issue-29488.rs
new file mode 100644
index 000000000..3c9a6a80d
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-29488.rs
@@ -0,0 +1,23 @@
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("test2");
+ }
+}
+
+thread_local!(static FOO: Foo = Foo);
+
+fn main() {
+ // Off the main thread due to #28129, be sure to initialize FOO first before
+ // calling `println!`
+ thread::spawn(|| {
+ FOO.with(|_| {});
+ println!("test1");
+ }).join().unwrap();
+}
diff --git a/tests/ui/threads-sendsync/issue-43733-2.rs b/tests/ui/threads-sendsync/issue-43733-2.rs
new file mode 100644
index 000000000..32baeec43
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-43733-2.rs
@@ -0,0 +1,30 @@
+// ignore-wasm32
+// dont-check-compiler-stderr
+#![feature(cfg_target_thread_local, thread_local_internals)]
+
+// On platforms *without* `#[thread_local]`, use
+// a custom non-`Sync` type to fake the same error.
+#[cfg(not(target_thread_local))]
+struct Key<T> {
+ _data: std::cell::UnsafeCell<Option<T>>,
+ _flag: std::cell::Cell<()>,
+}
+
+#[cfg(not(target_thread_local))]
+impl<T> Key<T> {
+ const fn new() -> Self {
+ Key {
+ _data: std::cell::UnsafeCell::new(None),
+ _flag: std::cell::Cell::new(()),
+ }
+ }
+}
+
+#[cfg(target_thread_local)]
+use std::thread::__FastLocalKeyInner as Key;
+
+static __KEY: Key<()> = Key::new();
+//~^ ERROR `UnsafeCell<Option<()>>` cannot be shared between threads
+//~| ERROR cannot be shared between threads safely [E0277]
+
+fn main() {}
diff --git a/tests/ui/threads-sendsync/issue-43733.mir.stderr b/tests/ui/threads-sendsync/issue-43733.mir.stderr
new file mode 100644
index 000000000..1e21a6b37
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-43733.mir.stderr
@@ -0,0 +1,19 @@
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/issue-43733.rs:21:5
+ |
+LL | __KEY.get(Default::default)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/issue-43733.rs:26:42
+ |
+LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/threads-sendsync/issue-43733.rs b/tests/ui/threads-sendsync/issue-43733.rs
new file mode 100644
index 000000000..935e02944
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-43733.rs
@@ -0,0 +1,38 @@
+// ignore-wasm32
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+// normalize-stderr-test: "__FastLocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get"
+// normalize-stderr-test: "__OsLocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get"
+#![feature(thread_local)]
+#![feature(cfg_target_thread_local, thread_local_internals)]
+
+use std::cell::RefCell;
+
+type Foo = std::cell::RefCell<String>;
+
+#[cfg(target_thread_local)]
+#[thread_local]
+static __KEY: std::thread::__FastLocalKeyInner<Foo> = std::thread::__FastLocalKeyInner::new();
+
+#[cfg(not(target_thread_local))]
+static __KEY: std::thread::__OsLocalKeyInner<Foo> = std::thread::__OsLocalKeyInner::new();
+
+fn __getit(_: Option<&mut Option<RefCell<String>>>) -> std::option::Option<&'static Foo> {
+ __KEY.get(Default::default)
+ //[mir]~^ ERROR call to unsafe function is unsafe
+ //[thir]~^^ ERROR call to unsafe function `__
+}
+
+static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
+//[mir]~^ ERROR call to unsafe function is unsafe
+//[thir]~^^ ERROR call to unsafe function `LocalKey::<T>::new`
+
+fn main() {
+ FOO.with(|foo| println!("{}", foo.borrow()));
+ std::thread::spawn(|| {
+ FOO.with(|foo| *foo.borrow_mut() += "foo");
+ })
+ .join()
+ .unwrap();
+ FOO.with(|foo| println!("{}", foo.borrow()));
+}
diff --git a/tests/ui/threads-sendsync/issue-43733.thir.stderr b/tests/ui/threads-sendsync/issue-43733.thir.stderr
new file mode 100644
index 000000000..ea7ff4080
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-43733.thir.stderr
@@ -0,0 +1,19 @@
+error[E0133]: call to unsafe function `$LOCALKEYINNER::<T>::get` is unsafe and requires unsafe function or block
+ --> $DIR/issue-43733.rs:21:5
+ |
+LL | __KEY.get(Default::default)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function `LocalKey::<T>::new` is unsafe and requires unsafe function or block
+ --> $DIR/issue-43733.rs:26:42
+ |
+LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/threads-sendsync/issue-4446.rs b/tests/ui/threads-sendsync/issue-4446.rs
new file mode 100644
index 000000000..948f2a7bd
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-4446.rs
@@ -0,0 +1,15 @@
+// run-pass
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::channel;
+use std::thread;
+
+pub fn main() {
+ let (tx, rx) = channel();
+
+ tx.send("hello, world").unwrap();
+
+ thread::spawn(move|| {
+ println!("{}", rx.recv().unwrap());
+ }).join().ok().unwrap();
+}
diff --git a/tests/ui/threads-sendsync/issue-4448.rs b/tests/ui/threads-sendsync/issue-4448.rs
new file mode 100644
index 000000000..27d032689
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-4448.rs
@@ -0,0 +1,16 @@
+// run-pass
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::channel;
+use std::thread;
+
+pub fn main() {
+ let (tx, rx) = channel::<&'static str>();
+
+ let t = thread::spawn(move|| {
+ assert_eq!(rx.recv().unwrap(), "hello, world");
+ });
+
+ tx.send("hello, world").unwrap();
+ t.join().ok().unwrap();
+}
diff --git a/tests/ui/threads-sendsync/issue-8827.rs b/tests/ui/threads-sendsync/issue-8827.rs
new file mode 100644
index 000000000..95be7616a
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-8827.rs
@@ -0,0 +1,53 @@
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::{channel, Receiver};
+
+fn periodical(n: isize) -> Receiver<bool> {
+ let (chan, port) = channel();
+ thread::spawn(move|| {
+ loop {
+ for _ in 1..n {
+ match chan.send(false) {
+ Ok(()) => {}
+ Err(..) => break,
+ }
+ }
+ match chan.send(true) {
+ Ok(()) => {}
+ Err(..) => break
+ }
+ }
+ });
+ return port;
+}
+
+fn integers() -> Receiver<isize> {
+ let (chan, port) = channel();
+ thread::spawn(move|| {
+ let mut i = 1;
+ loop {
+ match chan.send(i) {
+ Ok(()) => {}
+ Err(..) => break,
+ }
+ i = i + 1;
+ }
+ });
+ return port;
+}
+
+fn main() {
+ let ints = integers();
+ let threes = periodical(3);
+ let fives = periodical(5);
+ for _ in 1..100 {
+ match (ints.recv().unwrap(), threes.recv().unwrap(), fives.recv().unwrap()) {
+ (_, true, true) => println!("FizzBuzz"),
+ (_, true, false) => println!("Fizz"),
+ (_, false, true) => println!("Buzz"),
+ (i, false, false) => println!("{}", i)
+ }
+ }
+}
diff --git a/tests/ui/threads-sendsync/issue-9396.rs b/tests/ui/threads-sendsync/issue-9396.rs
new file mode 100644
index 000000000..3e7e9a51c
--- /dev/null
+++ b/tests/ui/threads-sendsync/issue-9396.rs
@@ -0,0 +1,23 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(deprecated)]
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::{TryRecvError, channel};
+use std::thread;
+
+pub fn main() {
+ let (tx, rx) = channel();
+ let t = thread::spawn(move||{
+ thread::sleep_ms(10);
+ tx.send(()).unwrap();
+ });
+ loop {
+ match rx.try_recv() {
+ Ok(()) => break,
+ Err(TryRecvError::Empty) => {}
+ Err(TryRecvError::Disconnected) => unreachable!()
+ }
+ }
+ t.join();
+}
diff --git a/tests/ui/threads-sendsync/mpsc_stress.rs b/tests/ui/threads-sendsync/mpsc_stress.rs
new file mode 100644
index 000000000..c2e1912de
--- /dev/null
+++ b/tests/ui/threads-sendsync/mpsc_stress.rs
@@ -0,0 +1,200 @@
+// run-pass
+// compile-flags:--test
+// ignore-emscripten
+
+use std::sync::mpsc::channel;
+use std::sync::mpsc::TryRecvError;
+use std::sync::mpsc::RecvError;
+use std::sync::mpsc::RecvTimeoutError;
+use std::sync::Arc;
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+
+use std::thread;
+use std::time::Duration;
+
+
+/// Simple thread synchronization utility
+struct Barrier {
+ // Not using mutex/condvar for precision
+ shared: Arc<AtomicUsize>,
+ count: usize,
+}
+
+impl Barrier {
+ fn new(count: usize) -> Vec<Barrier> {
+ let shared = Arc::new(AtomicUsize::new(0));
+ (0..count).map(|_| Barrier { shared: shared.clone(), count: count }).collect()
+ }
+
+ fn new2() -> (Barrier, Barrier) {
+ let mut v = Barrier::new(2);
+ (v.pop().unwrap(), v.pop().unwrap())
+ }
+
+ /// Returns when `count` threads enter `wait`
+ fn wait(self) {
+ self.shared.fetch_add(1, Ordering::SeqCst);
+ while self.shared.load(Ordering::SeqCst) != self.count {
+ #[cfg(target_env = "sgx")]
+ thread::yield_now();
+ }
+ }
+}
+
+
+fn shared_close_sender_does_not_lose_messages_iter() {
+ let (tb, rb) = Barrier::new2();
+
+ let (tx, rx) = channel();
+ let _ = tx.clone(); // convert to shared
+
+ thread::spawn(move || {
+ tb.wait();
+ thread::sleep(Duration::from_micros(1));
+ tx.send(17).expect("send");
+ drop(tx);
+ });
+
+ let i = rx.into_iter();
+ rb.wait();
+ // Make sure it doesn't return disconnected before returning an element
+ assert_eq!(vec![17], i.collect::<Vec<_>>());
+}
+
+#[test]
+fn shared_close_sender_does_not_lose_messages() {
+ with_minimum_timer_resolution(|| {
+ for _ in 0..10000 {
+ shared_close_sender_does_not_lose_messages_iter();
+ }
+ });
+}
+
+
+// https://github.com/rust-lang/rust/issues/39364
+fn concurrent_recv_timeout_and_upgrade_iter() {
+ // 1 us
+ let sleep = Duration::new(0, 1_000);
+
+ let (a, b) = Barrier::new2();
+ let (tx, rx) = channel();
+ let th = thread::spawn(move || {
+ a.wait();
+ loop {
+ match rx.recv_timeout(sleep) {
+ Ok(_) => {
+ break;
+ },
+ Err(_) => {},
+ }
+ }
+ });
+ b.wait();
+ thread::sleep(sleep);
+ tx.clone().send(()).expect("send");
+ th.join().unwrap();
+}
+
+#[test]
+fn concurrent_recv_timeout_and_upgrade() {
+ with_minimum_timer_resolution(|| {
+ for _ in 0..10000 {
+ concurrent_recv_timeout_and_upgrade_iter();
+ }
+ });
+}
+
+
+fn concurrent_writes_iter() {
+ const THREADS: usize = 4;
+ const PER_THR: usize = 100;
+
+ let mut bs = Barrier::new(THREADS + 1);
+ let (tx, rx) = channel();
+
+ let mut threads = Vec::new();
+ for j in 0..THREADS {
+ let tx = tx.clone();
+ let b = bs.pop().unwrap();
+ threads.push(thread::spawn(move || {
+ b.wait();
+ for i in 0..PER_THR {
+ tx.send(j * 1000 + i).expect("send");
+ }
+ }));
+ }
+
+ let b = bs.pop().unwrap();
+ b.wait();
+
+ let mut v: Vec<_> = rx.iter().take(THREADS * PER_THR).collect();
+ v.sort();
+
+ for j in 0..THREADS {
+ for i in 0..PER_THR {
+ assert_eq!(j * 1000 + i, v[j * PER_THR + i]);
+ }
+ }
+
+ for t in threads {
+ t.join().unwrap();
+ }
+
+ let one_us = Duration::new(0, 1000);
+
+ assert_eq!(TryRecvError::Empty, rx.try_recv().unwrap_err());
+ assert_eq!(RecvTimeoutError::Timeout, rx.recv_timeout(one_us).unwrap_err());
+
+ drop(tx);
+
+ assert_eq!(RecvError, rx.recv().unwrap_err());
+ assert_eq!(RecvTimeoutError::Disconnected, rx.recv_timeout(one_us).unwrap_err());
+ assert_eq!(TryRecvError::Disconnected, rx.try_recv().unwrap_err());
+}
+
+#[test]
+fn concurrent_writes() {
+ with_minimum_timer_resolution(|| {
+ for _ in 0..100 {
+ concurrent_writes_iter();
+ }
+ });
+}
+
+#[cfg(windows)]
+pub mod timeapi {
+ #![allow(non_snake_case)]
+ use std::ffi::c_uint;
+
+ pub const TIMERR_NOERROR: c_uint = 0;
+
+ #[link(name = "winmm")]
+ extern "system" {
+ pub fn timeBeginPeriod(uPeriod: c_uint) -> c_uint;
+ pub fn timeEndPeriod(uPeriod: c_uint) -> c_uint;
+ }
+}
+
+/// Window's minimum sleep time can be as much as 16ms.
+// This function evaluates the closure with this resolution
+// set as low as possible.
+///
+/// This takes the above test's duration from 10000*16/1000/60=2.67 minutes to ~16 seconds.
+fn with_minimum_timer_resolution(f: impl Fn()) {
+ #[cfg(windows)]
+ unsafe {
+ let ret = timeapi::timeBeginPeriod(1);
+ assert_eq!(ret, timeapi::TIMERR_NOERROR);
+
+ f();
+
+ let ret = timeapi::timeEndPeriod(1);
+ assert_eq!(ret, timeapi::TIMERR_NOERROR);
+ }
+
+ #[cfg(not(windows))]
+ {
+ f();
+ }
+}
diff --git a/tests/ui/threads-sendsync/send-is-not-static-par-for.rs b/tests/ui/threads-sendsync/send-is-not-static-par-for.rs
new file mode 100644
index 000000000..dbe465551
--- /dev/null
+++ b/tests/ui/threads-sendsync/send-is-not-static-par-for.rs
@@ -0,0 +1,34 @@
+// run-pass
+#![allow(unused_imports)]
+use std::thread;
+use std::sync::Mutex;
+
+fn par_for<I, F>(iter: I, f: F)
+ where I: Iterator,
+ I::Item: Send,
+ F: Fn(I::Item) + Sync
+{
+ for item in iter {
+ f(item)
+ }
+}
+
+fn sum(x: &[i32]) {
+ let sum_lengths = Mutex::new(0);
+ par_for(x.windows(4), |x| {
+ *sum_lengths.lock().unwrap() += x.len()
+ });
+
+ assert_eq!(*sum_lengths.lock().unwrap(), (x.len() - 3) * 4);
+}
+
+fn main() {
+ let mut elements = [0; 20];
+
+ // iterators over references into this stack frame
+ par_for(elements.iter_mut().enumerate(), |(i, x)| {
+ *x = i as i32
+ });
+
+ sum(&elements)
+}
diff --git a/tests/ui/threads-sendsync/send-resource.rs b/tests/ui/threads-sendsync/send-resource.rs
new file mode 100644
index 000000000..023a84d6b
--- /dev/null
+++ b/tests/ui/threads-sendsync/send-resource.rs
@@ -0,0 +1,39 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+// pretty-expanded FIXME #23616
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::channel;
+
+struct test {
+ f: isize,
+}
+
+impl Drop for test {
+ fn drop(&mut self) {}
+}
+
+fn test(f: isize) -> test {
+ test {
+ f: f
+ }
+}
+
+pub fn main() {
+ let (tx, rx) = channel();
+
+ let t = thread::spawn(move|| {
+ let (tx2, rx2) = channel();
+ tx.send(tx2).unwrap();
+
+ let _r = rx2.recv().unwrap();
+ });
+
+ rx.recv().unwrap().send(test(42)).unwrap();
+
+ t.join();
+}
diff --git a/tests/ui/threads-sendsync/send-type-inference.rs b/tests/ui/threads-sendsync/send-type-inference.rs
new file mode 100644
index 000000000..0d9af7512
--- /dev/null
+++ b/tests/ui/threads-sendsync/send-type-inference.rs
@@ -0,0 +1,19 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(dead_code)]
+#![allow(unused_mut)]
+// pretty-expanded FIXME #23616
+
+use std::sync::mpsc::{channel, Sender};
+
+// tests that ctrl's type gets inferred properly
+struct Command<K, V> {
+ key: K,
+ val: V
+}
+
+fn cache_server<K:Send+'static,V:Send+'static>(mut tx: Sender<Sender<Command<K, V>>>) {
+ let (tx1, _rx) = channel();
+ tx.send(tx1);
+}
+pub fn main() { }
diff --git a/tests/ui/threads-sendsync/send_str_hashmap.rs b/tests/ui/threads-sendsync/send_str_hashmap.rs
new file mode 100644
index 000000000..7d4cca8ad
--- /dev/null
+++ b/tests/ui/threads-sendsync/send_str_hashmap.rs
@@ -0,0 +1,53 @@
+// run-pass
+use std::collections::HashMap;
+use std::borrow::Cow;
+
+use std::borrow::Cow::Borrowed as B;
+use std::borrow::Cow::Owned as O;
+
+type SendStr = Cow<'static, str>;
+
+fn main() {
+ let mut map: HashMap<SendStr, usize> = HashMap::new();
+ assert!(map.insert(B("foo"), 42).is_none());
+ assert!(map.insert(O("foo".to_string()), 42).is_some());
+ assert!(map.insert(B("foo"), 42).is_some());
+ assert!(map.insert(O("foo".to_string()), 42).is_some());
+
+ assert!(map.insert(B("foo"), 43).is_some());
+ assert!(map.insert(O("foo".to_string()), 44).is_some());
+ assert!(map.insert(B("foo"), 45).is_some());
+ assert!(map.insert(O("foo".to_string()), 46).is_some());
+
+ let v = 46;
+
+ assert_eq!(map.get(&O("foo".to_string())), Some(&v));
+ assert_eq!(map.get(&B("foo")), Some(&v));
+
+ let (a, b, c, d) = (50, 51, 52, 53);
+
+ assert!(map.insert(B("abc"), a).is_none());
+ assert!(map.insert(O("bcd".to_string()), b).is_none());
+ assert!(map.insert(B("cde"), c).is_none());
+ assert!(map.insert(O("def".to_string()), d).is_none());
+
+ assert!(map.insert(B("abc"), a).is_some());
+ assert!(map.insert(O("bcd".to_string()), b).is_some());
+ assert!(map.insert(B("cde"), c).is_some());
+ assert!(map.insert(O("def".to_string()), d).is_some());
+
+ assert!(map.insert(O("abc".to_string()), a).is_some());
+ assert!(map.insert(B("bcd"), b).is_some());
+ assert!(map.insert(O("cde".to_string()), c).is_some());
+ assert!(map.insert(B("def"), d).is_some());
+
+ assert_eq!(map.get("abc"), Some(&a));
+ assert_eq!(map.get("bcd"), Some(&b));
+ assert_eq!(map.get("cde"), Some(&c));
+ assert_eq!(map.get("def"), Some(&d));
+
+ assert_eq!(map.get(&B("abc")), Some(&a));
+ assert_eq!(map.get(&B("bcd")), Some(&b));
+ assert_eq!(map.get(&B("cde")), Some(&c));
+ assert_eq!(map.get(&B("def")), Some(&d));
+}
diff --git a/tests/ui/threads-sendsync/send_str_treemap.rs b/tests/ui/threads-sendsync/send_str_treemap.rs
new file mode 100644
index 000000000..4d4631745
--- /dev/null
+++ b/tests/ui/threads-sendsync/send_str_treemap.rs
@@ -0,0 +1,58 @@
+// run-pass
+use std::collections::BTreeMap;
+use std::borrow::Cow;
+
+use std::borrow::Cow::{Owned as O, Borrowed as B};
+
+type SendStr = Cow<'static, str>;
+
+fn main() {
+ let mut map: BTreeMap<SendStr, usize> = BTreeMap::new();
+ assert!(map.insert(B("foo"), 42).is_none());
+ assert!(map.insert(O("foo".to_string()), 42).is_some());
+ assert!(map.insert(B("foo"), 42).is_some());
+ assert!(map.insert(O("foo".to_string()), 42).is_some());
+
+ assert!(map.insert(B("foo"), 43).is_some());
+ assert!(map.insert(O("foo".to_string()), 44).is_some());
+ assert!(map.insert(B("foo"), 45).is_some());
+ assert!(map.insert(O("foo".to_string()), 46).is_some());
+
+ let v = 46;
+
+ assert_eq!(map.get(&O("foo".to_string())), Some(&v));
+ assert_eq!(map.get(&B("foo")), Some(&v));
+
+ let (a, b, c, d) = (50, 51, 52, 53);
+
+ assert!(map.insert(B("abc"), a).is_none());
+ assert!(map.insert(O("bcd".to_string()), b).is_none());
+ assert!(map.insert(B("cde"), c).is_none());
+ assert!(map.insert(O("def".to_string()), d).is_none());
+
+ assert!(map.insert(B("abc"), a).is_some());
+ assert!(map.insert(O("bcd".to_string()), b).is_some());
+ assert!(map.insert(B("cde"), c).is_some());
+ assert!(map.insert(O("def".to_string()), d).is_some());
+
+ assert!(map.insert(O("abc".to_string()), a).is_some());
+ assert!(map.insert(B("bcd"), b).is_some());
+ assert!(map.insert(O("cde".to_string()), c).is_some());
+ assert!(map.insert(B("def"), d).is_some());
+
+ assert_eq!(map.get(&B("abc")), Some(&a));
+ assert_eq!(map.get(&B("bcd")), Some(&b));
+ assert_eq!(map.get(&B("cde")), Some(&c));
+ assert_eq!(map.get(&B("def")), Some(&d));
+
+ assert_eq!(map.get(&O("abc".to_string())), Some(&a));
+ assert_eq!(map.get(&O("bcd".to_string())), Some(&b));
+ assert_eq!(map.get(&O("cde".to_string())), Some(&c));
+ assert_eq!(map.get(&O("def".to_string())), Some(&d));
+
+ assert!(map.remove(&B("foo")).is_some());
+ assert_eq!(map.into_iter().map(|(k, v)| format!("{}{}", k, v))
+ .collect::<Vec<String>>()
+ .concat(),
+ "abc50bcd51cde52def53".to_string());
+}
diff --git a/tests/ui/threads-sendsync/sendable-class.rs b/tests/ui/threads-sendsync/sendable-class.rs
new file mode 100644
index 000000000..7facf245b
--- /dev/null
+++ b/tests/ui/threads-sendsync/sendable-class.rs
@@ -0,0 +1,28 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(non_camel_case_types)]
+
+// Test that a class with only sendable fields can be sent
+
+// pretty-expanded FIXME #23616
+
+use std::sync::mpsc::channel;
+
+struct foo {
+ i: isize,
+ j: char,
+}
+
+fn foo(i:isize, j: char) -> foo {
+ foo {
+ i: i,
+ j: j
+ }
+}
+
+pub fn main() {
+ let (tx, rx) = channel();
+ tx.send(foo(42, 'c'));
+}
diff --git a/tests/ui/threads-sendsync/sendfn-is-a-block.rs b/tests/ui/threads-sendsync/sendfn-is-a-block.rs
new file mode 100644
index 000000000..62807d894
--- /dev/null
+++ b/tests/ui/threads-sendsync/sendfn-is-a-block.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+
+fn test<F>(f: F) -> usize where F: FnOnce(usize) -> usize {
+ return f(22);
+}
+
+pub fn main() {
+ let y = test(|x| 4 * x);
+ assert_eq!(y, 88);
+}
diff --git a/tests/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs b/tests/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs
new file mode 100644
index 000000000..1e598b9e7
--- /dev/null
+++ b/tests/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs
@@ -0,0 +1,21 @@
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+
+pub fn main() { test05(); }
+
+fn test05_start<F:FnOnce(isize)>(f: F) {
+ f(22);
+}
+
+fn test05() {
+ let three: Box<_> = Box::new(3);
+ let fn_to_send = move|n:isize| {
+ println!("{}", *three + n); // will copy x into the closure
+ assert_eq!(*three, 3);
+ };
+ thread::spawn(move|| {
+ test05_start(fn_to_send);
+ }).join().ok().unwrap();
+}
diff --git a/tests/ui/threads-sendsync/spawn-fn.rs b/tests/ui/threads-sendsync/spawn-fn.rs
new file mode 100644
index 000000000..1243bb257
--- /dev/null
+++ b/tests/ui/threads-sendsync/spawn-fn.rs
@@ -0,0 +1,25 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+
+fn x(s: String, n: isize) {
+ println!("{}", s);
+ println!("{}", n);
+}
+
+pub fn main() {
+ let t1 = thread::spawn(|| x("hello from first spawned fn".to_string(), 65) );
+ let t2 = thread::spawn(|| x("hello from second spawned fn".to_string(), 66) );
+ let t3 = thread::spawn(|| x("hello from third spawned fn".to_string(), 67) );
+ let mut i = 30;
+ while i > 0 {
+ i = i - 1;
+ println!("parent sleeping");
+ thread::yield_now();
+ }
+ t1.join();
+ t2.join();
+ t3.join();
+}
diff --git a/tests/ui/threads-sendsync/spawn-types.rs b/tests/ui/threads-sendsync/spawn-types.rs
new file mode 100644
index 000000000..1bead6e1b
--- /dev/null
+++ b/tests/ui/threads-sendsync/spawn-types.rs
@@ -0,0 +1,25 @@
+// run-pass
+#![allow(non_camel_case_types)]
+
+// ignore-emscripten no threads support
+
+/*
+ Make sure we can spawn tasks that take different types of
+ parameters. This is based on a test case for #520 provided by Rob
+ Arnold.
+ */
+
+use std::thread;
+use std::sync::mpsc::{channel, Sender};
+
+type ctx = Sender<isize>;
+
+fn iotask(_tx: &ctx, ip: String) {
+ assert_eq!(ip, "localhost".to_string());
+}
+
+pub fn main() {
+ let (tx, _rx) = channel::<isize>();
+ let t = thread::spawn(move|| iotask(&tx, "localhost".to_string()) );
+ t.join().ok().unwrap();
+}
diff --git a/tests/ui/threads-sendsync/spawn.rs b/tests/ui/threads-sendsync/spawn.rs
new file mode 100644
index 000000000..b1dcc9417
--- /dev/null
+++ b/tests/ui/threads-sendsync/spawn.rs
@@ -0,0 +1,10 @@
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+
+pub fn main() {
+ thread::spawn(move|| child(10)).join().ok().unwrap();
+}
+
+fn child(i: isize) { println!("{}", i); assert_eq!(i, 10); }
diff --git a/tests/ui/threads-sendsync/spawn2.rs b/tests/ui/threads-sendsync/spawn2.rs
new file mode 100644
index 000000000..83e066aef
--- /dev/null
+++ b/tests/ui/threads-sendsync/spawn2.rs
@@ -0,0 +1,31 @@
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+
+pub fn main() {
+ let t = thread::spawn(move|| child((10, 20, 30, 40, 50, 60, 70, 80, 90)) );
+ t.join().ok().unwrap(); // forget Err value, since it doesn't implement Debug
+}
+
+fn child(args: (isize, isize, isize, isize, isize, isize, isize, isize, isize)) {
+ let (i1, i2, i3, i4, i5, i6, i7, i8, i9) = args;
+ println!("{}", i1);
+ println!("{}", i2);
+ println!("{}", i3);
+ println!("{}", i4);
+ println!("{}", i5);
+ println!("{}", i6);
+ println!("{}", i7);
+ println!("{}", i8);
+ println!("{}", i9);
+ assert_eq!(i1, 10);
+ assert_eq!(i2, 20);
+ assert_eq!(i3, 30);
+ assert_eq!(i4, 40);
+ assert_eq!(i5, 50);
+ assert_eq!(i6, 60);
+ assert_eq!(i7, 70);
+ assert_eq!(i8, 80);
+ assert_eq!(i9, 90);
+}
diff --git a/tests/ui/threads-sendsync/spawning-with-debug.rs b/tests/ui/threads-sendsync/spawning-with-debug.rs
new file mode 100644
index 000000000..9d3487ffb
--- /dev/null
+++ b/tests/ui/threads-sendsync/spawning-with-debug.rs
@@ -0,0 +1,15 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(unused_mut)]
+// ignore-windows
+// exec-env:RUST_LOG=debug
+// ignore-emscripten no threads support
+
+// regression test for issue #10405, make sure we don't call println! too soon.
+
+use std::thread::Builder;
+
+pub fn main() {
+ let mut t = Builder::new();
+ t.spawn(move || ());
+}
diff --git a/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs b/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs
new file mode 100644
index 000000000..bc64c8162
--- /dev/null
+++ b/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs
@@ -0,0 +1,16 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+use std::sync;
+
+fn assert_both<T: Sync + Send>() {}
+
+fn main() {
+ assert_both::<sync::Mutex<()>>();
+ assert_both::<sync::Condvar>();
+ assert_both::<sync::RwLock<()>>();
+ assert_both::<sync::Barrier>();
+ assert_both::<sync::Arc<()>>();
+ assert_both::<sync::Weak<()>>();
+ assert_both::<sync::Once>();
+}
diff --git a/tests/ui/threads-sendsync/sync-send-atomics.rs b/tests/ui/threads-sendsync/sync-send-atomics.rs
new file mode 100644
index 000000000..0466f4f0e
--- /dev/null
+++ b/tests/ui/threads-sendsync/sync-send-atomics.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+// pretty-expanded FIXME #23616
+
+use std::sync::atomic::*;
+
+trait SendSync: Send + Sync {}
+
+impl SendSync for AtomicBool {}
+impl SendSync for AtomicIsize {}
+impl SendSync for AtomicUsize {}
+impl<T> SendSync for AtomicPtr<T> {}
+
+fn main() {}
diff --git a/tests/ui/threads-sendsync/sync-send-in-std.rs b/tests/ui/threads-sendsync/sync-send-in-std.rs
new file mode 100644
index 000000000..6d1fba64e
--- /dev/null
+++ b/tests/ui/threads-sendsync/sync-send-in-std.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+// ignore-wasm32-bare networking not available
+// ignore-sgx ToSocketAddrs cannot be used for DNS Resolution
+// ignore-fuchsia Req. test-harness networking privileges
+
+use std::net::ToSocketAddrs;
+
+fn is_sync<T>(_: T) where T: Sync {}
+fn is_send<T>(_: T) where T: Send {}
+
+macro_rules! all_sync_send {
+ ($ctor:expr, $($iter:ident),+) => ({
+ $(
+ let mut x = $ctor;
+ is_sync(x.$iter());
+ let mut y = $ctor;
+ is_send(y.$iter());
+ )+
+ })
+}
+
+fn main() {
+ all_sync_send!("localhost:80".to_socket_addrs().unwrap(), next);
+}
diff --git a/tests/ui/threads-sendsync/sync-send-iterators-in-libcollections.rs b/tests/ui/threads-sendsync/sync-send-iterators-in-libcollections.rs
new file mode 100644
index 000000000..fd53bb607
--- /dev/null
+++ b/tests/ui/threads-sendsync/sync-send-iterators-in-libcollections.rs
@@ -0,0 +1,71 @@
+// run-pass
+
+#![allow(warnings)]
+#![feature(drain, collections_bound, btree_range)]
+
+use std::collections::BinaryHeap;
+use std::collections::{BTreeMap, BTreeSet};
+use std::collections::LinkedList;
+use std::collections::VecDeque;
+use std::collections::HashMap;
+use std::collections::HashSet;
+
+use std::mem;
+use std::ops::Bound::Included;
+
+fn is_sync<T>(_: T) where T: Sync {}
+fn is_send<T>(_: T) where T: Send {}
+
+macro_rules! all_sync_send {
+ ($ctor:expr, $($iter:ident),+) => ({
+ $(
+ let mut x = $ctor;
+ is_sync(x.$iter());
+ let mut y = $ctor;
+ is_send(y.$iter());
+ )+
+ })
+}
+
+macro_rules! is_sync_send {
+ ($ctor:expr, $iter:ident($($param:expr),+)) => ({
+ let mut x = $ctor;
+ is_sync(x.$iter($( $param ),+));
+ let mut y = $ctor;
+ is_send(y.$iter($( $param ),+));
+ })
+}
+
+fn main() {
+ // The iterator "generator" list should exhaust what corresponding
+ // implementations have where `Sync` and `Send` semantics apply.
+ all_sync_send!(BinaryHeap::<usize>::new(), iter, drain, into_iter);
+
+ all_sync_send!(BTreeMap::<usize, usize>::new(), iter, iter_mut, into_iter, keys, values);
+ is_sync_send!(BTreeMap::<usize, usize>::new(), range((Included(&0), Included(&9))));
+ is_sync_send!(BTreeMap::<usize, usize>::new(), range_mut((Included(&0), Included(&9))));
+
+ all_sync_send!(BTreeSet::<usize>::new(), iter, into_iter);
+ is_sync_send!(BTreeSet::<usize>::new(), range((Included(&0), Included(&9))));
+ is_sync_send!(BTreeSet::<usize>::new(), difference(&BTreeSet::<usize>::new()));
+ is_sync_send!(BTreeSet::<usize>::new(), symmetric_difference(&BTreeSet::<usize>::new()));
+ is_sync_send!(BTreeSet::<usize>::new(), intersection(&BTreeSet::<usize>::new()));
+ is_sync_send!(BTreeSet::<usize>::new(), union(&BTreeSet::<usize>::new()));
+
+ all_sync_send!(HashMap::<usize, usize>::new(), iter, iter_mut, drain, into_iter, keys, values);
+ is_sync_send!(HashMap::<usize, usize>::new(), entry(0));
+ all_sync_send!(HashSet::<usize>::new(), iter, drain, into_iter);
+ is_sync_send!(HashSet::<usize>::new(), difference(&HashSet::<usize>::new()));
+ is_sync_send!(HashSet::<usize>::new(), symmetric_difference(&HashSet::<usize>::new()));
+ is_sync_send!(HashSet::<usize>::new(), intersection(&HashSet::<usize>::new()));
+ is_sync_send!(HashSet::<usize>::new(), union(&HashSet::<usize>::new()));
+
+ all_sync_send!(LinkedList::<usize>::new(), iter, iter_mut, into_iter);
+
+ all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, into_iter);
+ is_sync_send!(VecDeque::<usize>::new(), drain(..));
+
+ all_sync_send!(Vec::<usize>::new(), into_iter);
+ is_sync_send!(Vec::<usize>::new(), drain(..));
+ is_sync_send!(String::new(), drain(..));
+}
diff --git a/tests/ui/threads-sendsync/sync-send-iterators-in-libcore.rs b/tests/ui/threads-sendsync/sync-send-iterators-in-libcore.rs
new file mode 100644
index 000000000..2f6d35f01
--- /dev/null
+++ b/tests/ui/threads-sendsync/sync-send-iterators-in-libcore.rs
@@ -0,0 +1,105 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![allow(warnings)]
+
+use std::iter::{empty, once, repeat};
+
+fn is_sync<T>(_: T) where T: Sync {}
+fn is_send<T>(_: T) where T: Send {}
+
+macro_rules! all_sync_send {
+ ($ctor:expr, $iter:ident) => ({
+ let mut x = $ctor;
+ is_sync(x.$iter());
+ let mut y = $ctor;
+ is_send(y.$iter());
+ });
+ ($ctor:expr, $iter:ident($($param:expr),+)) => ({
+ let mut x = $ctor;
+ is_sync(x.$iter($( $param ),+));
+ let mut y = $ctor;
+ is_send(y.$iter($( $param ),+));
+ });
+ ($ctor:expr, $iter:ident, $($rest:tt)*) => ({
+ all_sync_send!($ctor, $iter);
+ all_sync_send!($ctor, $($rest)*);
+ });
+ ($ctor:expr, $iter:ident($($param:expr),+), $($rest:tt)*) => ({
+ all_sync_send!($ctor, $iter($( $param ),+));
+ all_sync_send!($ctor, $($rest)*);
+ });
+}
+
+macro_rules! all_sync_send_mutable_ref {
+ ($ctor:expr, $($iter:ident),+) => ({
+ $(
+ let mut x = $ctor;
+ is_sync((&mut x).$iter());
+ let mut y = $ctor;
+ is_send((&mut y).$iter());
+ )+
+ })
+}
+
+macro_rules! is_sync_send {
+ ($ctor:expr) => ({
+ let x = $ctor;
+ is_sync(x);
+ let y = $ctor;
+ is_send(y);
+ })
+}
+
+fn main() {
+ // for char.rs
+ all_sync_send!("Я", escape_debug, escape_default, escape_unicode);
+
+ // for iter.rs
+ all_sync_send_mutable_ref!([1], iter);
+
+ // Bytes implements DoubleEndedIterator
+ all_sync_send!("a".bytes(), rev);
+
+ let a = [1];
+ let b = [2];
+ all_sync_send!(a.iter(),
+ cloned,
+ cycle,
+ chain([2].iter()),
+ zip([2].iter()),
+ map(|_| 1),
+ filter(|_| true),
+ filter_map(|_| Some(1)),
+ enumerate,
+ peekable,
+ skip_while(|_| true),
+ take_while(|_| true),
+ skip(1),
+ take(1),
+ scan(1, |_, _| Some(1)),
+ flat_map(|_| b.iter()),
+ fuse,
+ inspect(|_| ()));
+
+ is_sync_send!((1..).step_by(2));
+ is_sync_send!((1..2).step_by(2));
+ is_sync_send!((1..2));
+ is_sync_send!((1..));
+ is_sync_send!(repeat(1));
+ is_sync_send!(empty::<usize>());
+ is_sync_send!(empty::<*mut i32>());
+ is_sync_send!(once(1));
+
+ // for option.rs
+ // FIXME
+
+ // for result.rs
+ // FIXME
+
+ // for slice.rs
+ // FIXME
+
+ // for str/mod.rs
+ // FIXME
+}
diff --git a/tests/ui/threads-sendsync/task-comm-0.rs b/tests/ui/threads-sendsync/task-comm-0.rs
new file mode 100644
index 000000000..2b9a50e4d
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-0.rs
@@ -0,0 +1,30 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::{channel, Sender};
+
+pub fn main() { test05(); }
+
+fn test05_start(tx : &Sender<isize>) {
+ tx.send(10).unwrap();
+ println!("sent 10");
+ tx.send(20).unwrap();
+ println!("sent 20");
+ tx.send(30).unwrap();
+ println!("sent 30");
+}
+
+fn test05() {
+ let (tx, rx) = channel();
+ let t = thread::spawn(move|| { test05_start(&tx) });
+ let mut value: isize = rx.recv().unwrap();
+ println!("{}", value);
+ value = rx.recv().unwrap();
+ println!("{}", value);
+ value = rx.recv().unwrap();
+ println!("{}", value);
+ assert_eq!(value, 30);
+ t.join();
+}
diff --git a/tests/ui/threads-sendsync/task-comm-1.rs b/tests/ui/threads-sendsync/task-comm-1.rs
new file mode 100644
index 000000000..68ca62909
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-1.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+
+pub fn main() { test00(); }
+
+fn start() { println!("Started / Finished task."); }
+
+fn test00() {
+ thread::spawn(move|| start() ).join();
+ println!("Completing.");
+}
diff --git a/tests/ui/threads-sendsync/task-comm-10.rs b/tests/ui/threads-sendsync/task-comm-10.rs
new file mode 100644
index 000000000..4cac0dc90
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-10.rs
@@ -0,0 +1,33 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(unused_mut)]
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::{channel, Sender};
+
+fn start(tx: &Sender<Sender<String>>) {
+ let (tx2, rx) = channel();
+ tx.send(tx2).unwrap();
+
+ let mut a;
+ let mut b;
+ a = rx.recv().unwrap();
+ assert_eq!(a, "A".to_string());
+ println!("{}", a);
+ b = rx.recv().unwrap();
+ assert_eq!(b, "B".to_string());
+ println!("{}", b);
+}
+
+pub fn main() {
+ let (tx, rx) = channel();
+ let child = thread::spawn(move|| { start(&tx) });
+
+ let mut c = rx.recv().unwrap();
+ c.send("A".to_string()).unwrap();
+ c.send("B".to_string()).unwrap();
+ thread::yield_now();
+
+ child.join();
+}
diff --git a/tests/ui/threads-sendsync/task-comm-11.rs b/tests/ui/threads-sendsync/task-comm-11.rs
new file mode 100644
index 000000000..8541e143f
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-11.rs
@@ -0,0 +1,21 @@
+// run-pass
+#![allow(unused_must_use)]
+// pretty-expanded FIXME #23616
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::{channel, Sender};
+use std::thread;
+
+fn start(tx: &Sender<Sender<isize>>) {
+ let (tx2, _rx) = channel();
+ tx.send(tx2).unwrap();
+}
+
+pub fn main() {
+ let (tx, rx) = channel();
+ let child = thread::spawn(move|| {
+ start(&tx)
+ });
+ let _tx = rx.recv().unwrap();
+ child.join();
+}
diff --git a/tests/ui/threads-sendsync/task-comm-12.rs b/tests/ui/threads-sendsync/task-comm-12.rs
new file mode 100644
index 000000000..613a5cee5
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-12.rs
@@ -0,0 +1,29 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(unused_mut)]
+// ignore-emscripten no threads support
+
+use std::thread;
+
+pub fn main() { test00(); }
+
+fn start(_task_number: isize) { println!("Started / Finished task."); }
+
+fn test00() {
+ let i: isize = 0;
+ let mut result = thread::spawn(move|| {
+ start(i)
+ });
+
+ // Sleep long enough for the thread to finish.
+ let mut i = 0_usize;
+ while i < 10000 {
+ thread::yield_now();
+ i += 1;
+ }
+
+ // Try joining threads that have already finished.
+ result.join();
+
+ println!("Joined task.");
+}
diff --git a/tests/ui/threads-sendsync/task-comm-13.rs b/tests/ui/threads-sendsync/task-comm-13.rs
new file mode 100644
index 000000000..327eaaf8f
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-13.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![allow(unused_variables)]
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::{channel, Sender};
+use std::thread;
+
+fn start(tx: &Sender<isize>, start: isize, number_of_messages: isize) {
+ let mut i: isize = 0;
+ while i< number_of_messages { tx.send(start + i).unwrap(); i += 1; }
+}
+
+pub fn main() {
+ println!("Check that we don't deadlock.");
+ let (tx, rx) = channel();
+ let _ = thread::spawn(move|| { start(&tx, 0, 10) }).join();
+ println!("Joined task");
+}
diff --git a/tests/ui/threads-sendsync/task-comm-14.rs b/tests/ui/threads-sendsync/task-comm-14.rs
new file mode 100644
index 000000000..88d6b0902
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-14.rs
@@ -0,0 +1,36 @@
+// run-pass
+#![allow(unused_parens)]
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::{channel, Sender};
+use std::thread;
+
+pub fn main() {
+ let (tx, rx) = channel();
+
+ // Spawn 10 threads each sending us back one isize.
+ let mut i = 10;
+ while (i > 0) {
+ println!("{}", i);
+ let tx = tx.clone();
+ thread::spawn({let i = i; move|| { child(i, &tx) }});
+ i = i - 1;
+ }
+
+ // Spawned threads are likely killed before they get a chance to send
+ // anything back, so we deadlock here.
+
+ i = 10;
+ while (i > 0) {
+ println!("{}", i);
+ rx.recv().unwrap();
+ i = i - 1;
+ }
+
+ println!("main thread exiting");
+}
+
+fn child(x: isize, tx: &Sender<isize>) {
+ println!("{}", x);
+ tx.send(x).unwrap();
+}
diff --git a/tests/ui/threads-sendsync/task-comm-15.rs b/tests/ui/threads-sendsync/task-comm-15.rs
new file mode 100644
index 000000000..adb14abdc
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-15.rs
@@ -0,0 +1,28 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+// pretty-expanded FIXME #23616
+
+use std::sync::mpsc::{channel, Sender};
+use std::thread;
+
+fn start(tx: &Sender<isize>, i0: isize) {
+ let mut i = i0;
+ while i > 0 {
+ tx.send(0).unwrap();
+ i = i - 1;
+ }
+}
+
+pub fn main() {
+ // Spawn a thread that sends us back messages. The parent thread
+ // is likely to terminate before the child completes, so from
+ // the child's point of view the receiver may die. We should
+ // drop messages on the floor in this case, and not crash!
+ let (tx, rx) = channel();
+ let t = thread::spawn(move|| {
+ start(&tx, 10)
+ });
+ rx.recv();
+ t.join();
+}
diff --git a/tests/ui/threads-sendsync/task-comm-16.rs b/tests/ui/threads-sendsync/task-comm-16.rs
new file mode 100644
index 000000000..d808fd9ac
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-16.rs
@@ -0,0 +1,111 @@
+// run-pass
+#![allow(unused_mut)]
+#![allow(unused_parens)]
+#![allow(non_camel_case_types)]
+
+use std::sync::mpsc::channel;
+use std::cmp;
+
+// Tests of ports and channels on various types
+fn test_rec() {
+ struct R {val0: isize, val1: u8, val2: char}
+
+ let (tx, rx) = channel();
+ let r0: R = R {val0: 0, val1: 1, val2: '2'};
+ tx.send(r0).unwrap();
+ let mut r1: R;
+ r1 = rx.recv().unwrap();
+ assert_eq!(r1.val0, 0);
+ assert_eq!(r1.val1, 1);
+ assert_eq!(r1.val2, '2');
+}
+
+fn test_vec() {
+ let (tx, rx) = channel();
+ let v0: Vec<isize> = vec![0, 1, 2];
+ tx.send(v0).unwrap();
+ let v1 = rx.recv().unwrap();
+ assert_eq!(v1[0], 0);
+ assert_eq!(v1[1], 1);
+ assert_eq!(v1[2], 2);
+}
+
+fn test_str() {
+ let (tx, rx) = channel();
+ let s0 = "test".to_string();
+ tx.send(s0).unwrap();
+ let s1 = rx.recv().unwrap();
+ assert_eq!(s1.as_bytes()[0], 't' as u8);
+ assert_eq!(s1.as_bytes()[1], 'e' as u8);
+ assert_eq!(s1.as_bytes()[2], 's' as u8);
+ assert_eq!(s1.as_bytes()[3], 't' as u8);
+}
+
+#[derive(Debug)]
+enum t {
+ tag1,
+ tag2(isize),
+ tag3(isize, u8, char)
+}
+
+impl cmp::PartialEq for t {
+ fn eq(&self, other: &t) -> bool {
+ match *self {
+ t::tag1 => {
+ match (*other) {
+ t::tag1 => true,
+ _ => false
+ }
+ }
+ t::tag2(e0a) => {
+ match (*other) {
+ t::tag2(e0b) => e0a == e0b,
+ _ => false
+ }
+ }
+ t::tag3(e0a, e1a, e2a) => {
+ match (*other) {
+ t::tag3(e0b, e1b, e2b) =>
+ e0a == e0b && e1a == e1b && e2a == e2b,
+ _ => false
+ }
+ }
+ }
+ }
+ fn ne(&self, other: &t) -> bool { !(*self).eq(other) }
+}
+
+fn test_tag() {
+ let (tx, rx) = channel();
+ tx.send(t::tag1).unwrap();
+ tx.send(t::tag2(10)).unwrap();
+ tx.send(t::tag3(10, 11, 'A')).unwrap();
+ let mut t1: t;
+ t1 = rx.recv().unwrap();
+ assert_eq!(t1, t::tag1);
+ t1 = rx.recv().unwrap();
+ assert_eq!(t1, t::tag2(10));
+ t1 = rx.recv().unwrap();
+ assert_eq!(t1, t::tag3(10, 11, 'A'));
+}
+
+fn test_chan() {
+ let (tx1, rx1) = channel();
+ let (tx2, rx2) = channel();
+ tx1.send(tx2).unwrap();
+ let tx2 = rx1.recv().unwrap();
+ // Does the transmitted channel still work?
+
+ tx2.send(10).unwrap();
+ let mut i: isize;
+ i = rx2.recv().unwrap();
+ assert_eq!(i, 10);
+}
+
+pub fn main() {
+ test_rec();
+ test_vec();
+ test_str();
+ test_tag();
+ test_chan();
+}
diff --git a/tests/ui/threads-sendsync/task-comm-17.rs b/tests/ui/threads-sendsync/task-comm-17.rs
new file mode 100644
index 000000000..722497870
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-17.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+// pretty-expanded FIXME #23616
+
+// Issue #922
+
+// This test is specifically about spawning temporary closures.
+
+use std::thread;
+
+fn f() {
+}
+
+pub fn main() {
+ thread::spawn(move|| f() ).join();
+}
diff --git a/tests/ui/threads-sendsync/task-comm-3.rs b/tests/ui/threads-sendsync/task-comm-3.rs
new file mode 100644
index 000000000..570ae0a82
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-3.rs
@@ -0,0 +1,63 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::{channel, Sender};
+
+pub fn main() { println!("===== WITHOUT THREADS ====="); test00(); }
+
+fn test00_start(ch: &Sender<isize>, message: isize, count: isize) {
+ println!("Starting test00_start");
+ let mut i: isize = 0;
+ while i < count {
+ println!("Sending Message");
+ ch.send(message + 0).unwrap();
+ i = i + 1;
+ }
+ println!("Ending test00_start");
+}
+
+fn test00() {
+ let number_of_tasks: isize = 16;
+ let number_of_messages: isize = 4;
+
+ println!("Creating tasks");
+
+ let (tx, rx) = channel();
+
+ let mut i: isize = 0;
+
+ // Create and spawn threads...
+ let mut results = Vec::new();
+ while i < number_of_tasks {
+ let tx = tx.clone();
+ results.push(thread::spawn({
+ let i = i;
+ move|| {
+ test00_start(&tx, i, number_of_messages)
+ }
+ }));
+ i = i + 1;
+ }
+
+ // Read from spawned threads...
+ let mut sum = 0;
+ for _r in &results {
+ i = 0;
+ while i < number_of_messages {
+ let value = rx.recv().unwrap();
+ sum += value;
+ i = i + 1;
+ }
+ }
+
+ // Join spawned threads...
+ for r in results { r.join(); }
+
+ println!("Completed: Final number is: ");
+ println!("{}", sum);
+ // assert (sum == (((number_of_threads * (number_of_threads - 1)) / 2) *
+ // number_of_messages));
+ assert_eq!(sum, 480);
+}
diff --git a/tests/ui/threads-sendsync/task-comm-4.rs b/tests/ui/threads-sendsync/task-comm-4.rs
new file mode 100644
index 000000000..b259d69d1
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-4.rs
@@ -0,0 +1,45 @@
+// run-pass
+#![allow(unused_assignments)]
+
+use std::sync::mpsc::channel;
+
+pub fn main() { test00(); }
+
+fn test00() {
+ let mut r: isize = 0;
+ let mut sum: isize = 0;
+ let (tx, rx) = channel();
+ tx.send(1).unwrap();
+ tx.send(2).unwrap();
+ tx.send(3).unwrap();
+ tx.send(4).unwrap();
+ r = rx.recv().unwrap();
+ sum += r;
+ println!("{}", r);
+ r = rx.recv().unwrap();
+ sum += r;
+ println!("{}", r);
+ r = rx.recv().unwrap();
+ sum += r;
+ println!("{}", r);
+ r = rx.recv().unwrap();
+ sum += r;
+ println!("{}", r);
+ tx.send(5).unwrap();
+ tx.send(6).unwrap();
+ tx.send(7).unwrap();
+ tx.send(8).unwrap();
+ r = rx.recv().unwrap();
+ sum += r;
+ println!("{}", r);
+ r = rx.recv().unwrap();
+ sum += r;
+ println!("{}", r);
+ r = rx.recv().unwrap();
+ sum += r;
+ println!("{}", r);
+ r = rx.recv().unwrap();
+ sum += r;
+ println!("{}", r);
+ assert_eq!(sum, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
+}
diff --git a/tests/ui/threads-sendsync/task-comm-5.rs b/tests/ui/threads-sendsync/task-comm-5.rs
new file mode 100644
index 000000000..cdedf034a
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-5.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+use std::sync::mpsc::channel;
+
+pub fn main() { test00(); }
+
+fn test00() {
+ let _r: isize = 0;
+ let mut sum: isize = 0;
+ let (tx, rx) = channel();
+ let number_of_messages: isize = 1000;
+ let mut i: isize = 0;
+ while i < number_of_messages { tx.send(i + 0).unwrap(); i += 1; }
+ i = 0;
+ while i < number_of_messages { sum += rx.recv().unwrap(); i += 1; }
+ assert_eq!(sum, number_of_messages * (number_of_messages - 1) / 2);
+}
diff --git a/tests/ui/threads-sendsync/task-comm-6.rs b/tests/ui/threads-sendsync/task-comm-6.rs
new file mode 100644
index 000000000..990205ad3
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-6.rs
@@ -0,0 +1,42 @@
+// run-pass
+#![allow(unused_mut)]
+#![allow(unused_assignments)]
+
+use std::sync::mpsc::channel;
+
+pub fn main() { test00(); }
+
+fn test00() {
+ let mut r: isize = 0;
+ let mut sum: isize = 0;
+ let (tx, rx) = channel();
+ let mut tx0 = tx.clone();
+ let mut tx1 = tx.clone();
+ let mut tx2 = tx.clone();
+ let mut tx3 = tx.clone();
+ let number_of_messages: isize = 1000;
+ let mut i: isize = 0;
+ while i < number_of_messages {
+ tx0.send(i + 0).unwrap();
+ tx1.send(i + 0).unwrap();
+ tx2.send(i + 0).unwrap();
+ tx3.send(i + 0).unwrap();
+ i += 1;
+ }
+ i = 0;
+ while i < number_of_messages {
+ r = rx.recv().unwrap();
+ sum += r;
+ r = rx.recv().unwrap();
+ sum += r;
+ r = rx.recv().unwrap();
+ sum += r;
+ r = rx.recv().unwrap();
+ sum += r;
+ i += 1;
+ }
+ assert_eq!(sum, 1998000);
+ // assert (sum == 4 * ((number_of_messages *
+ // (number_of_messages - 1)) / 2));
+
+}
diff --git a/tests/ui/threads-sendsync/task-comm-7.rs b/tests/ui/threads-sendsync/task-comm-7.rs
new file mode 100644
index 000000000..0b9673e00
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-7.rs
@@ -0,0 +1,59 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(unused_assignments)]
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::{channel, Sender};
+use std::thread;
+
+pub fn main() { test00(); }
+
+fn test00_start(c: &Sender<isize>, start: isize,
+ number_of_messages: isize) {
+ let mut i: isize = 0;
+ while i < number_of_messages { c.send(start + i).unwrap(); i += 1; }
+}
+
+fn test00() {
+ let mut r: isize = 0;
+ let mut sum: isize = 0;
+ let (tx, rx) = channel();
+ let number_of_messages: isize = 10;
+
+ let tx2 = tx.clone();
+ let t1 = thread::spawn(move|| {
+ test00_start(&tx2, number_of_messages * 0, number_of_messages);
+ });
+ let tx2 = tx.clone();
+ let t2 = thread::spawn(move|| {
+ test00_start(&tx2, number_of_messages * 1, number_of_messages);
+ });
+ let tx2 = tx.clone();
+ let t3 = thread::spawn(move|| {
+ test00_start(&tx2, number_of_messages * 2, number_of_messages);
+ });
+ let tx2 = tx.clone();
+ let t4 = thread::spawn(move|| {
+ test00_start(&tx2, number_of_messages * 3, number_of_messages);
+ });
+
+ let mut i: isize = 0;
+ while i < number_of_messages {
+ r = rx.recv().unwrap();
+ sum += r;
+ r = rx.recv().unwrap();
+ sum += r;
+ r = rx.recv().unwrap();
+ sum += r;
+ r = rx.recv().unwrap();
+ sum += r;
+ i += 1;
+ }
+
+ assert_eq!(sum, number_of_messages * 4 * (number_of_messages * 4 - 1) / 2);
+
+ t1.join();
+ t2.join();
+ t3.join();
+ t4.join();
+}
diff --git a/tests/ui/threads-sendsync/task-comm-9.rs b/tests/ui/threads-sendsync/task-comm-9.rs
new file mode 100644
index 000000000..5ed330121
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-9.rs
@@ -0,0 +1,35 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::{channel, Sender};
+
+pub fn main() { test00(); }
+
+fn test00_start(c: &Sender<isize>, number_of_messages: isize) {
+ let mut i: isize = 0;
+ while i < number_of_messages { c.send(i + 0).unwrap(); i += 1; }
+}
+
+fn test00() {
+ let r: isize = 0;
+ let mut sum: isize = 0;
+ let (tx, rx) = channel();
+ let number_of_messages: isize = 10;
+
+ let result = thread::spawn(move|| {
+ test00_start(&tx, number_of_messages);
+ });
+
+ let mut i: isize = 0;
+ while i < number_of_messages {
+ sum += rx.recv().unwrap();
+ println!("{}", r);
+ i += 1;
+ }
+
+ result.join();
+
+ assert_eq!(sum, number_of_messages * (number_of_messages - 1) / 2);
+}
diff --git a/tests/ui/threads-sendsync/task-comm-chan-nil.rs b/tests/ui/threads-sendsync/task-comm-chan-nil.rs
new file mode 100644
index 000000000..a93ddff43
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-comm-chan-nil.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+use std::sync::mpsc::channel;
+
+// rustboot can't transmit nils across channels because they don't have
+// any size, but rustc currently can because they do have size. Whether
+// or not this is desirable I don't know, but here's a regression test.
+pub fn main() {
+ let (tx, rx) = channel();
+ tx.send(()).unwrap();
+ let n: () = rx.recv().unwrap();
+ assert_eq!(n, ());
+}
diff --git a/tests/ui/threads-sendsync/task-life-0.rs b/tests/ui/threads-sendsync/task-life-0.rs
new file mode 100644
index 000000000..785cff9a0
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-life-0.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+// pretty-expanded FIXME #23616
+
+use std::thread;
+
+pub fn main() {
+ thread::spawn(move|| child("Hello".to_string()) ).join();
+}
+
+fn child(_s: String) {
+
+}
diff --git a/tests/ui/threads-sendsync/task-spawn-barefn.rs b/tests/ui/threads-sendsync/task-spawn-barefn.rs
new file mode 100644
index 000000000..e5b899e0a
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-spawn-barefn.rs
@@ -0,0 +1,18 @@
+// run-fail
+// error-pattern:Ensure that the child thread runs by panicking
+// ignore-emscripten Needs threads.
+
+use std::thread;
+
+fn main() {
+ // the purpose of this test is to make sure that thread::spawn()
+ // works when provided with a bare function:
+ let r = thread::spawn(startfn).join();
+ if r.is_err() {
+ panic!()
+ }
+}
+
+fn startfn() {
+ assert!("Ensure that the child thread runs by panicking".is_empty());
+}
diff --git a/tests/ui/threads-sendsync/task-spawn-move-and-copy.rs b/tests/ui/threads-sendsync/task-spawn-move-and-copy.rs
new file mode 100644
index 000000000..a63903778
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-spawn-move-and-copy.rs
@@ -0,0 +1,23 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::channel;
+
+pub fn main() {
+ let (tx, rx) = channel::<usize>();
+
+ let x: Box<isize> = Box::new(1);
+ let x_in_parent = &(*x) as *const isize as usize;
+
+ let t = thread::spawn(move || {
+ let x_in_child = &(*x) as *const isize as usize;
+ tx.send(x_in_child).unwrap();
+ });
+
+ let x_in_child = rx.recv().unwrap();
+ assert_eq!(x_in_parent, x_in_child);
+
+ t.join();
+}
diff --git a/tests/ui/threads-sendsync/task-stderr.rs b/tests/ui/threads-sendsync/task-stderr.rs
new file mode 100644
index 000000000..68d226ffb
--- /dev/null
+++ b/tests/ui/threads-sendsync/task-stderr.rs
@@ -0,0 +1,26 @@
+// run-pass
+// ignore-emscripten no threads support
+// needs-unwind
+
+#![feature(internal_output_capture)]
+
+use std::io;
+use std::str;
+use std::sync::{Arc, Mutex};
+use std::thread;
+
+fn main() {
+ let data = Arc::new(Mutex::new(Vec::new()));
+ let res = thread::Builder::new().spawn({
+ let data = data.clone();
+ move || {
+ io::set_output_capture(Some(data));
+ panic!("Hello, world!")
+ }
+ }).unwrap().join();
+ assert!(res.is_err());
+
+ let output = data.lock().unwrap();
+ let output = str::from_utf8(&output).unwrap();
+ assert!(output.contains("Hello, world!"));
+}
diff --git a/tests/ui/threads-sendsync/tcp-stress.rs b/tests/ui/threads-sendsync/tcp-stress.rs
new file mode 100644
index 000000000..175663643
--- /dev/null
+++ b/tests/ui/threads-sendsync/tcp-stress.rs
@@ -0,0 +1,64 @@
+// run-pass
+// ignore-android needs extra network permissions
+// ignore-emscripten no threads or sockets support
+// ignore-netbsd system ulimit (Too many open files)
+// ignore-openbsd system ulimit (Too many open files)
+
+use std::io::prelude::*;
+use std::net::{TcpListener, TcpStream};
+use std::process;
+use std::sync::mpsc::channel;
+use std::time::Duration;
+use std::thread::{self, Builder};
+
+const TARGET_CNT: usize = 200;
+
+fn main() {
+ // This test has a chance to time out, try to not let it time out
+ thread::spawn(move|| -> () {
+ thread::sleep(Duration::from_secs(30));
+ process::exit(1);
+ });
+
+ let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let addr = listener.local_addr().unwrap();
+ thread::spawn(move || -> () {
+ loop {
+ let mut stream = match listener.accept() {
+ Ok(stream) => stream.0,
+ Err(_) => continue,
+ };
+ let _ = stream.read(&mut [0]);
+ let _ = stream.write(&[2]);
+ }
+ });
+
+ let (tx, rx) = channel();
+
+ let mut spawned_cnt = 0;
+ for _ in 0..TARGET_CNT {
+ let tx = tx.clone();
+ let res = Builder::new().stack_size(64 * 1024).spawn(move|| {
+ match TcpStream::connect(addr) {
+ Ok(mut stream) => {
+ let _ = stream.write(&[1]);
+ let _ = stream.read(&mut [0]);
+ },
+ Err(..) => {}
+ }
+ tx.send(()).unwrap();
+ });
+ if let Ok(_) = res {
+ spawned_cnt += 1;
+ };
+ }
+
+ // Wait for all clients to exit, but don't wait for the server to exit. The
+ // server just runs infinitely.
+ drop(tx);
+ for _ in 0..spawned_cnt {
+ rx.recv().unwrap();
+ }
+ assert_eq!(spawned_cnt, TARGET_CNT);
+ process::exit(0);
+}
diff --git a/tests/ui/threads-sendsync/test-tasks-invalid-value.rs b/tests/ui/threads-sendsync/test-tasks-invalid-value.rs
new file mode 100644
index 000000000..641142142
--- /dev/null
+++ b/tests/ui/threads-sendsync/test-tasks-invalid-value.rs
@@ -0,0 +1,11 @@
+// This checks that RUST_TEST_THREADS not being 1, 2, ... is detected
+// properly.
+
+// run-fail
+// error-pattern:should be a positive integer
+// compile-flags: --test
+// exec-env:RUST_TEST_THREADS=foo
+// ignore-emscripten
+
+#[test]
+fn do_nothing() {}
diff --git a/tests/ui/threads-sendsync/thread-local-extern-static.rs b/tests/ui/threads-sendsync/thread-local-extern-static.rs
new file mode 100644
index 000000000..a2dda31aa
--- /dev/null
+++ b/tests/ui/threads-sendsync/thread-local-extern-static.rs
@@ -0,0 +1,27 @@
+// run-pass
+// ignore-windows
+// aux-build:thread-local-extern-static.rs
+
+#![feature(cfg_target_thread_local, thread_local)]
+
+#[cfg(target_thread_local)]
+extern crate thread_local_extern_static;
+
+#[cfg(target_thread_local)]
+use std::cell::Cell;
+
+#[cfg(target_thread_local)]
+extern "C" {
+ #[thread_local]
+ static FOO: Cell<u32>;
+}
+
+#[cfg(target_thread_local)]
+fn main() {
+ unsafe {
+ assert_eq!(FOO.get(), 3);
+ }
+}
+
+#[cfg(not(target_thread_local))]
+fn main() {}
diff --git a/tests/ui/threads-sendsync/thread-local-syntax.rs b/tests/ui/threads-sendsync/thread-local-syntax.rs
new file mode 100644
index 000000000..2f4805e47
--- /dev/null
+++ b/tests/ui/threads-sendsync/thread-local-syntax.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![deny(missing_docs)]
+//! this tests the syntax of `thread_local!`
+
+mod foo {
+ mod bar {
+ thread_local! {
+ // no docs
+ #[allow(unused)]
+ static FOO: i32 = 42;
+ /// docs
+ pub static BAR: String = String::from("bar");
+
+ // look at these restrictions!!
+ pub(crate) static BAZ: usize = 0;
+ pub(in foo) static QUUX: usize = 0;
+ }
+ thread_local!(static SPLOK: u32 = 0);
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/threads-sendsync/threads.rs b/tests/ui/threads-sendsync/threads.rs
new file mode 100644
index 000000000..e3da83aa1
--- /dev/null
+++ b/tests/ui/threads-sendsync/threads.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+
+pub fn main() {
+ let mut i = 10;
+ while i > 0 {
+ thread::spawn({let i = i; move|| child(i)}).join();
+ i = i - 1;
+ }
+ println!("main thread exiting");
+}
+
+fn child(x: isize) { println!("{}", x); }
diff --git a/tests/ui/threads-sendsync/tls-dtors-are-run-in-a-static-binary.rs b/tests/ui/threads-sendsync/tls-dtors-are-run-in-a-static-binary.rs
new file mode 100644
index 000000000..8baef4334
--- /dev/null
+++ b/tests/ui/threads-sendsync/tls-dtors-are-run-in-a-static-binary.rs
@@ -0,0 +1,22 @@
+// run-pass
+// no-prefer-dynamic
+// ignore-emscripten no threads support
+
+static mut HIT: bool = false;
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ unsafe { HIT = true; }
+ }
+}
+
+thread_local!(static FOO: Foo = Foo);
+
+fn main() {
+ std::thread::spawn(|| {
+ FOO.with(|_| {});
+ }).join().unwrap();
+ assert!(unsafe { HIT });
+}
diff --git a/tests/ui/threads-sendsync/tls-init-on-init.rs b/tests/ui/threads-sendsync/tls-init-on-init.rs
new file mode 100644
index 000000000..193c18151
--- /dev/null
+++ b/tests/ui/threads-sendsync/tls-init-on-init.rs
@@ -0,0 +1,44 @@
+// run-pass
+#![allow(stable_features)]
+
+// ignore-emscripten no threads support
+
+#![feature(thread_local_try_with)]
+
+use std::thread;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+struct Foo { cnt: usize }
+
+thread_local!(static FOO: Foo = Foo::init());
+
+static CNT: AtomicUsize = AtomicUsize::new(0);
+
+impl Foo {
+ fn init() -> Foo {
+ let cnt = CNT.fetch_add(1, Ordering::SeqCst);
+ if cnt == 0 {
+ FOO.with(|_| {});
+ }
+ Foo { cnt: cnt }
+ }
+}
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ if self.cnt == 1 {
+ FOO.with(|foo| assert_eq!(foo.cnt, 0));
+ } else {
+ assert_eq!(self.cnt, 0);
+ if FOO.try_with(|_| ()).is_ok() {
+ panic!("should not be in valid state");
+ }
+ }
+ }
+}
+
+fn main() {
+ thread::spawn(|| {
+ FOO.with(|_| {});
+ }).join().unwrap();
+}
diff --git a/tests/ui/threads-sendsync/tls-try-with.rs b/tests/ui/threads-sendsync/tls-try-with.rs
new file mode 100644
index 000000000..f36ab4e4f
--- /dev/null
+++ b/tests/ui/threads-sendsync/tls-try-with.rs
@@ -0,0 +1,30 @@
+// run-pass
+#![allow(stable_features)]
+
+// ignore-emscripten no threads support
+
+#![feature(thread_local_try_with)]
+
+use std::thread;
+
+static mut DROP_RUN: bool = false;
+
+struct Foo;
+
+thread_local!(static FOO: Foo = Foo {});
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ assert!(FOO.try_with(|_| panic!("`try_with` closure run")).is_err());
+ unsafe { DROP_RUN = true; }
+ }
+}
+
+fn main() {
+ thread::spawn(|| {
+ assert_eq!(FOO.try_with(|_| {
+ 132
+ }).expect("`try_with` failed"), 132);
+ }).join().unwrap();
+ assert!(unsafe { DROP_RUN });
+}
diff --git a/tests/ui/threads-sendsync/trivial-message.rs b/tests/ui/threads-sendsync/trivial-message.rs
new file mode 100644
index 000000000..5831e867b
--- /dev/null
+++ b/tests/ui/threads-sendsync/trivial-message.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+#![allow(unused_must_use)]
+/*
+ This is about the simplest program that can successfully send a
+ message.
+ */
+
+use std::sync::mpsc::channel;
+
+pub fn main() {
+ let (tx, rx) = channel();
+ tx.send(42);
+ let r = rx.recv();
+ println!("{:?}", r);
+}
diff --git a/tests/ui/threads-sendsync/unwind-resource.rs b/tests/ui/threads-sendsync/unwind-resource.rs
new file mode 100644
index 000000000..6950a9c40
--- /dev/null
+++ b/tests/ui/threads-sendsync/unwind-resource.rs
@@ -0,0 +1,40 @@
+// run-pass
+// needs-unwind
+
+#![allow(non_camel_case_types)]
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::{channel, Sender};
+use std::thread;
+
+struct complainer {
+ tx: Sender<bool>,
+}
+
+impl Drop for complainer {
+ fn drop(&mut self) {
+ println!("About to send!");
+ self.tx.send(true).unwrap();
+ println!("Sent!");
+ }
+}
+
+fn complainer(tx: Sender<bool>) -> complainer {
+ println!("Hello!");
+ complainer {
+ tx: tx
+ }
+}
+
+fn f(tx: Sender<bool>) {
+ let _tx = complainer(tx);
+ panic!();
+}
+
+pub fn main() {
+ let (tx, rx) = channel();
+ let t = thread::spawn(move|| f(tx.clone()));
+ println!("hiiiiiiiii");
+ assert!(rx.recv().unwrap());
+ drop(t.join());
+}
diff --git a/tests/ui/threads-sendsync/yield.rs b/tests/ui/threads-sendsync/yield.rs
new file mode 100644
index 000000000..e83ba5560
--- /dev/null
+++ b/tests/ui/threads-sendsync/yield.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![allow(unused_must_use)]
+#![allow(unused_mut)]
+// ignore-emscripten no threads support
+
+use std::thread;
+
+pub fn main() {
+ let mut result = thread::spawn(child);
+ println!("1");
+ thread::yield_now();
+ println!("2");
+ thread::yield_now();
+ println!("3");
+ result.join();
+}
+
+fn child() {
+ println!("4"); thread::yield_now(); println!("5"); thread::yield_now(); println!("6");
+}
diff --git a/tests/ui/threads-sendsync/yield1.rs b/tests/ui/threads-sendsync/yield1.rs
new file mode 100644
index 000000000..002e59055
--- /dev/null
+++ b/tests/ui/threads-sendsync/yield1.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+#![allow(unused_must_use)]
+#![allow(unused_mut)]
+// ignore-emscripten no threads support
+
+use std::thread;
+
+pub fn main() {
+ let mut result = thread::spawn(child);
+ println!("1");
+ thread::yield_now();
+ result.join();
+}
+
+fn child() { println!("2"); }
diff --git a/tests/ui/threads-sendsync/yield2.rs b/tests/ui/threads-sendsync/yield2.rs
new file mode 100644
index 000000000..376faab0c
--- /dev/null
+++ b/tests/ui/threads-sendsync/yield2.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+use std::thread;
+
+pub fn main() {
+ let mut i: isize = 0;
+ while i < 100 { i = i + 1; println!("{}", i); thread::yield_now(); }
+}