about summary refs log tree commit diff
path: root/tests/ui/threads-sendsync
diff options
context:
space:
mode:
authorAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-05 09:13:28 +0100
committerAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-11 09:32:08 +0000
commitcf2dff2b1e3fa55fa5415d524200070d0d7aacfe (patch)
tree40a88d9a46aaf3e8870676eb2538378b75a263eb /tests/ui/threads-sendsync
parentca855e6e42787ecd062d81d53336fe6788ef51a9 (diff)
downloadrust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.tar.gz
rust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.zip
Move /src/test to /tests
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 00000000000..4d3c4e8accd
--- /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 00000000000..e3a39a44bb8
--- /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 00000000000..9fc661b1477
--- /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 00000000000..aa86e174d44
--- /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 00000000000..f5243077384
--- /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 00000000000..c28b4ca9601
--- /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 00000000000..3c9a6a80dbf
--- /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 00000000000..32baeec4359
--- /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 00000000000..1e21a6b37a9
--- /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 00000000000..935e02944b9
--- /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 00000000000..ea7ff408048
--- /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 00000000000..948f2a7bdf3
--- /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 00000000000..27d0326891b
--- /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 00000000000..95be7616a4f
--- /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 00000000000..3e7e9a51cdd
--- /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 00000000000..c2e1912deb7
--- /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 00000000000..dbe46555101
--- /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 00000000000..023a84d6b6e
--- /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 00000000000..0d9af7512b4
--- /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 00000000000..7d4cca8ad74
--- /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 00000000000..4d463174590
--- /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 00000000000..7facf245bde
--- /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 00000000000..62807d8941a
--- /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 00000000000..1e598b9e709
--- /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 00000000000..1243bb2579f
--- /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 00000000000..1bead6e1bb1
--- /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 00000000000..b1dcc9417fb
--- /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 00000000000..83e066aef96
--- /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 00000000000..9d3487ffb29
--- /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 00000000000..bc64c816243
--- /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 00000000000..0466f4f0e9d
--- /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 00000000000..6d1fba64e42
--- /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 00000000000..fd53bb607f7
--- /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 00000000000..2f6d35f01be
--- /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 00000000000..2b9a50e4d41
--- /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 00000000000..68ca62909bf
--- /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 00000000000..4cac0dc90cf
--- /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 00000000000..8541e143fb9
--- /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 00000000000..613a5cee58b
--- /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 00000000000..327eaaf8fa1
--- /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 00000000000..88d6b090268
--- /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 00000000000..adb14abdce9
--- /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 00000000000..d808fd9aceb
--- /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 00000000000..72249787093
--- /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 00000000000..570ae0a82ff
--- /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 00000000000..b259d69d15d
--- /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 00000000000..cdedf034ac3
--- /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 00000000000..990205ad334
--- /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 00000000000..0b9673e0033
--- /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 00000000000..5ed33012100
--- /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 00000000000..a93ddff43dc
--- /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 00000000000..785cff9a0f3
--- /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 00000000000..e5b899e0af9
--- /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 00000000000..a6390377802
--- /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 00000000000..68d226ffbae
--- /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 00000000000..17566364340
--- /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 00000000000..6411421429c
--- /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 00000000000..a2dda31aa55
--- /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 00000000000..2f4805e4731
--- /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 00000000000..e3da83aa12b
--- /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 00000000000..8baef433410
--- /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 00000000000..193c1815105
--- /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 00000000000..f36ab4e4f9c
--- /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 00000000000..5831e867be5
--- /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 00000000000..6950a9c40d2
--- /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 00000000000..e83ba556078
--- /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 00000000000..002e590550c
--- /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 00000000000..376faab0c48
--- /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(); }
+}