about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/macros.rs18
-rw-r--r--src/libstd/sync/mpsc/mod.rs3
-rw-r--r--src/libstd/sync/mpsc/select.rs416
-rw-r--r--src/libstd/sync/mpsc/select_tests.rs413
-rw-r--r--src/libstd/thread/local.rs8
5 files changed, 435 insertions, 423 deletions
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index b87257188df..506b6d4e8e0 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -53,7 +53,8 @@
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable]
+#[cfg_attr(stage0, allow_internal_unstable)]
+#[cfg_attr(not(stage0), allow_internal_unstable(__rust_unstable_column, libstd_sys_internals))]
 macro_rules! panic {
     () => ({
         panic!("explicit panic")
@@ -111,7 +112,8 @@ macro_rules! panic {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable]
+#[cfg_attr(stage0, allow_internal_unstable)]
+#[cfg_attr(not(stage0), allow_internal_unstable(print_internals))]
 macro_rules! print {
     ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
 }
@@ -143,7 +145,8 @@ macro_rules! print {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable]
+#[cfg_attr(stage0, allow_internal_unstable)]
+#[cfg_attr(not(stage0), allow_internal_unstable(print_internals, format_args_nl))]
 macro_rules! println {
     () => (print!("\n"));
     ($($arg:tt)*) => ({
@@ -174,7 +177,8 @@ macro_rules! println {
 /// ```
 #[macro_export]
 #[stable(feature = "eprint", since = "1.19.0")]
-#[allow_internal_unstable]
+#[cfg_attr(stage0, allow_internal_unstable)]
+#[cfg_attr(not(stage0), allow_internal_unstable(print_internals))]
 macro_rules! eprint {
     ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)));
 }
@@ -202,7 +206,8 @@ macro_rules! eprint {
 /// ```
 #[macro_export]
 #[stable(feature = "eprint", since = "1.19.0")]
-#[allow_internal_unstable]
+#[cfg_attr(stage0, allow_internal_unstable)]
+#[cfg_attr(not(stage0), allow_internal_unstable(print_internals, format_args_nl))]
 macro_rules! eprintln {
     () => (eprint!("\n"));
     ($($arg:tt)*) => ({
@@ -325,7 +330,8 @@ macro_rules! dbg {
 /// A macro to await on an async call.
 #[macro_export]
 #[unstable(feature = "await_macro", issue = "50547")]
-#[allow_internal_unstable]
+#[cfg_attr(stage0, allow_internal_unstable)]
+#[cfg_attr(not(stage0), allow_internal_unstable(gen_future, generators))]
 #[allow_internal_unsafe]
 macro_rules! await {
     ($e:expr) => { {
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index 446c164965d..a8843549b8a 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -279,6 +279,9 @@ use self::select::StartResult;
 use self::select::StartResult::*;
 use self::blocking::SignalToken;
 
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod select_tests;
+
 mod blocking;
 mod oneshot;
 mod select;
diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs
index 8f41680a818..e34fc5487cf 100644
--- a/src/libstd/sync/mpsc/select.rs
+++ b/src/libstd/sync/mpsc/select.rs
@@ -158,7 +158,7 @@ impl Select {
     }
 
     /// Helper method for skipping the preflight checks during testing
-    fn wait2(&self, do_preflight_checks: bool) -> usize {
+    pub(super) fn wait2(&self, do_preflight_checks: bool) -> usize {
         // Note that this is currently an inefficient implementation. We in
         // theory have knowledge about all receivers in the set ahead of time,
         // so this method shouldn't really have to iterate over all of them yet
@@ -352,417 +352,3 @@ impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> {
         f.debug_struct("Handle").finish()
     }
 }
-
-#[allow(unused_imports)]
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
-    use thread;
-    use sync::mpsc::*;
-
-    // Don't use the libstd version so we can pull in the right Select structure
-    // (std::comm points at the wrong one)
-    macro_rules! select {
-        (
-            $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
-        ) => ({
-            let sel = Select::new();
-            $( let mut $rx = sel.handle(&$rx); )+
-            unsafe {
-                $( $rx.add(); )+
-            }
-            let ret = sel.wait();
-            $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
-            { unreachable!() }
-        })
-    }
-
-    #[test]
-    fn smoke() {
-        let (tx1, rx1) = channel::<i32>();
-        let (tx2, rx2) = channel::<i32>();
-        tx1.send(1).unwrap();
-        select! {
-            foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
-            _bar = rx2.recv() => { panic!() }
-        }
-        tx2.send(2).unwrap();
-        select! {
-            _foo = rx1.recv() => { panic!() },
-            bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
-        }
-        drop(tx1);
-        select! {
-            foo = rx1.recv() => { assert!(foo.is_err()); },
-            _bar = rx2.recv() => { panic!() }
-        }
-        drop(tx2);
-        select! {
-            bar = rx2.recv() => { assert!(bar.is_err()); }
-        }
-    }
-
-    #[test]
-    fn smoke2() {
-        let (_tx1, rx1) = channel::<i32>();
-        let (_tx2, rx2) = channel::<i32>();
-        let (_tx3, rx3) = channel::<i32>();
-        let (_tx4, rx4) = channel::<i32>();
-        let (tx5, rx5) = channel::<i32>();
-        tx5.send(4).unwrap();
-        select! {
-            _foo = rx1.recv() => { panic!("1") },
-            _foo = rx2.recv() => { panic!("2") },
-            _foo = rx3.recv() => { panic!("3") },
-            _foo = rx4.recv() => { panic!("4") },
-            foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
-        }
-    }
-
-    #[test]
-    fn closed() {
-        let (_tx1, rx1) = channel::<i32>();
-        let (tx2, rx2) = channel::<i32>();
-        drop(tx2);
-
-        select! {
-            _a1 = rx1.recv() => { panic!() },
-            a2 = rx2.recv() => { assert!(a2.is_err()); }
-        }
-    }
-
-    #[test]
-    fn unblocks() {
-        let (tx1, rx1) = channel::<i32>();
-        let (_tx2, rx2) = channel::<i32>();
-        let (tx3, rx3) = channel::<i32>();
-
-        let _t = thread::spawn(move|| {
-            for _ in 0..20 { thread::yield_now(); }
-            tx1.send(1).unwrap();
-            rx3.recv().unwrap();
-            for _ in 0..20 { thread::yield_now(); }
-        });
-
-        select! {
-            a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-            _b = rx2.recv() => { panic!() }
-        }
-        tx3.send(1).unwrap();
-        select! {
-            a = rx1.recv() => { assert!(a.is_err()) },
-            _b = rx2.recv() => { panic!() }
-        }
-    }
-
-    #[test]
-    fn both_ready() {
-        let (tx1, rx1) = channel::<i32>();
-        let (tx2, rx2) = channel::<i32>();
-        let (tx3, rx3) = channel::<()>();
-
-        let _t = thread::spawn(move|| {
-            for _ in 0..20 { thread::yield_now(); }
-            tx1.send(1).unwrap();
-            tx2.send(2).unwrap();
-            rx3.recv().unwrap();
-        });
-
-        select! {
-            a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-            a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
-        }
-        select! {
-            a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-            a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
-        }
-        assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
-        assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
-        tx3.send(()).unwrap();
-    }
-
-    #[test]
-    fn stress() {
-        const AMT: i32 = 10000;
-        let (tx1, rx1) = channel::<i32>();
-        let (tx2, rx2) = channel::<i32>();
-        let (tx3, rx3) = channel::<()>();
-
-        let _t = thread::spawn(move|| {
-            for i in 0..AMT {
-                if i % 2 == 0 {
-                    tx1.send(i).unwrap();
-                } else {
-                    tx2.send(i).unwrap();
-                }
-                rx3.recv().unwrap();
-            }
-        });
-
-        for i in 0..AMT {
-            select! {
-                i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
-                i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
-            }
-            tx3.send(()).unwrap();
-        }
-    }
-
-    #[allow(unused_must_use)]
-    #[test]
-    fn cloning() {
-        let (tx1, rx1) = channel::<i32>();
-        let (_tx2, rx2) = channel::<i32>();
-        let (tx3, rx3) = channel::<()>();
-
-        let _t = thread::spawn(move|| {
-            rx3.recv().unwrap();
-            tx1.clone();
-            assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
-            tx1.send(2).unwrap();
-            rx3.recv().unwrap();
-        });
-
-        tx3.send(()).unwrap();
-        select! {
-            _i1 = rx1.recv() => {},
-            _i2 = rx2.recv() => panic!()
-        }
-        tx3.send(()).unwrap();
-    }
-
-    #[allow(unused_must_use)]
-    #[test]
-    fn cloning2() {
-        let (tx1, rx1) = channel::<i32>();
-        let (_tx2, rx2) = channel::<i32>();
-        let (tx3, rx3) = channel::<()>();
-
-        let _t = thread::spawn(move|| {
-            rx3.recv().unwrap();
-            tx1.clone();
-            assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
-            tx1.send(2).unwrap();
-            rx3.recv().unwrap();
-        });
-
-        tx3.send(()).unwrap();
-        select! {
-            _i1 = rx1.recv() => {},
-            _i2 = rx2.recv() => panic!()
-        }
-        tx3.send(()).unwrap();
-    }
-
-    #[test]
-    fn cloning3() {
-        let (tx1, rx1) = channel::<()>();
-        let (tx2, rx2) = channel::<()>();
-        let (tx3, rx3) = channel::<()>();
-        let _t = thread::spawn(move|| {
-            let s = Select::new();
-            let mut h1 = s.handle(&rx1);
-            let mut h2 = s.handle(&rx2);
-            unsafe { h2.add(); }
-            unsafe { h1.add(); }
-            assert_eq!(s.wait(), h2.id);
-            tx3.send(()).unwrap();
-        });
-
-        for _ in 0..1000 { thread::yield_now(); }
-        drop(tx1.clone());
-        tx2.send(()).unwrap();
-        rx3.recv().unwrap();
-    }
-
-    #[test]
-    fn preflight1() {
-        let (tx, rx) = channel();
-        tx.send(()).unwrap();
-        select! {
-            _n = rx.recv() => {}
-        }
-    }
-
-    #[test]
-    fn preflight2() {
-        let (tx, rx) = channel();
-        tx.send(()).unwrap();
-        tx.send(()).unwrap();
-        select! {
-            _n = rx.recv() => {}
-        }
-    }
-
-    #[test]
-    fn preflight3() {
-        let (tx, rx) = channel();
-        drop(tx.clone());
-        tx.send(()).unwrap();
-        select! {
-            _n = rx.recv() => {}
-        }
-    }
-
-    #[test]
-    fn preflight4() {
-        let (tx, rx) = channel();
-        tx.send(()).unwrap();
-        let s = Select::new();
-        let mut h = s.handle(&rx);
-        unsafe { h.add(); }
-        assert_eq!(s.wait2(false), h.id);
-    }
-
-    #[test]
-    fn preflight5() {
-        let (tx, rx) = channel();
-        tx.send(()).unwrap();
-        tx.send(()).unwrap();
-        let s = Select::new();
-        let mut h = s.handle(&rx);
-        unsafe { h.add(); }
-        assert_eq!(s.wait2(false), h.id);
-    }
-
-    #[test]
-    fn preflight6() {
-        let (tx, rx) = channel();
-        drop(tx.clone());
-        tx.send(()).unwrap();
-        let s = Select::new();
-        let mut h = s.handle(&rx);
-        unsafe { h.add(); }
-        assert_eq!(s.wait2(false), h.id);
-    }
-
-    #[test]
-    fn preflight7() {
-        let (tx, rx) = channel::<()>();
-        drop(tx);
-        let s = Select::new();
-        let mut h = s.handle(&rx);
-        unsafe { h.add(); }
-        assert_eq!(s.wait2(false), h.id);
-    }
-
-    #[test]
-    fn preflight8() {
-        let (tx, rx) = channel();
-        tx.send(()).unwrap();
-        drop(tx);
-        rx.recv().unwrap();
-        let s = Select::new();
-        let mut h = s.handle(&rx);
-        unsafe { h.add(); }
-        assert_eq!(s.wait2(false), h.id);
-    }
-
-    #[test]
-    fn preflight9() {
-        let (tx, rx) = channel();
-        drop(tx.clone());
-        tx.send(()).unwrap();
-        drop(tx);
-        rx.recv().unwrap();
-        let s = Select::new();
-        let mut h = s.handle(&rx);
-        unsafe { h.add(); }
-        assert_eq!(s.wait2(false), h.id);
-    }
-
-    #[test]
-    fn oneshot_data_waiting() {
-        let (tx1, rx1) = channel();
-        let (tx2, rx2) = channel();
-        let _t = thread::spawn(move|| {
-            select! {
-                _n = rx1.recv() => {}
-            }
-            tx2.send(()).unwrap();
-        });
-
-        for _ in 0..100 { thread::yield_now() }
-        tx1.send(()).unwrap();
-        rx2.recv().unwrap();
-    }
-
-    #[test]
-    fn stream_data_waiting() {
-        let (tx1, rx1) = channel();
-        let (tx2, rx2) = channel();
-        tx1.send(()).unwrap();
-        tx1.send(()).unwrap();
-        rx1.recv().unwrap();
-        rx1.recv().unwrap();
-        let _t = thread::spawn(move|| {
-            select! {
-                _n = rx1.recv() => {}
-            }
-            tx2.send(()).unwrap();
-        });
-
-        for _ in 0..100 { thread::yield_now() }
-        tx1.send(()).unwrap();
-        rx2.recv().unwrap();
-    }
-
-    #[test]
-    fn shared_data_waiting() {
-        let (tx1, rx1) = channel();
-        let (tx2, rx2) = channel();
-        drop(tx1.clone());
-        tx1.send(()).unwrap();
-        rx1.recv().unwrap();
-        let _t = thread::spawn(move|| {
-            select! {
-                _n = rx1.recv() => {}
-            }
-            tx2.send(()).unwrap();
-        });
-
-        for _ in 0..100 { thread::yield_now() }
-        tx1.send(()).unwrap();
-        rx2.recv().unwrap();
-    }
-
-    #[test]
-    fn sync1() {
-        let (tx, rx) = sync_channel::<i32>(1);
-        tx.send(1).unwrap();
-        select! {
-            n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
-        }
-    }
-
-    #[test]
-    fn sync2() {
-        let (tx, rx) = sync_channel::<i32>(0);
-        let _t = thread::spawn(move|| {
-            for _ in 0..100 { thread::yield_now() }
-            tx.send(1).unwrap();
-        });
-        select! {
-            n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
-        }
-    }
-
-    #[test]
-    fn sync3() {
-        let (tx1, rx1) = sync_channel::<i32>(0);
-        let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
-        let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
-        let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
-        select! {
-            n = rx1.recv() => {
-                let n = n.unwrap();
-                assert_eq!(n, 1);
-                assert_eq!(rx2.recv().unwrap(), 2);
-            },
-            n = rx2.recv() => {
-                let n = n.unwrap();
-                assert_eq!(n, 2);
-                assert_eq!(rx1.recv().unwrap(), 1);
-            }
-        }
-    }
-}
diff --git a/src/libstd/sync/mpsc/select_tests.rs b/src/libstd/sync/mpsc/select_tests.rs
new file mode 100644
index 00000000000..be048511caa
--- /dev/null
+++ b/src/libstd/sync/mpsc/select_tests.rs
@@ -0,0 +1,413 @@
+#![allow(unused_imports)]
+
+/// This file exists to hack around https://github.com/rust-lang/rust/issues/47238
+
+use thread;
+use sync::mpsc::*;
+
+// Don't use the libstd version so we can pull in the right Select structure
+// (std::comm points at the wrong one)
+macro_rules! select {
+    (
+        $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
+    ) => ({
+        let sel = Select::new();
+        $( let mut $rx = sel.handle(&$rx); )+
+        unsafe {
+            $( $rx.add(); )+
+        }
+        let ret = sel.wait();
+        $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
+        { unreachable!() }
+    })
+}
+
+#[test]
+fn smoke() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<i32>();
+    tx1.send(1).unwrap();
+    select! {
+        foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
+        _bar = rx2.recv() => { panic!() }
+    }
+    tx2.send(2).unwrap();
+    select! {
+        _foo = rx1.recv() => { panic!() },
+        bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
+    }
+    drop(tx1);
+    select! {
+        foo = rx1.recv() => { assert!(foo.is_err()); },
+        _bar = rx2.recv() => { panic!() }
+    }
+    drop(tx2);
+    select! {
+        bar = rx2.recv() => { assert!(bar.is_err()); }
+    }
+}
+
+#[test]
+fn smoke2() {
+    let (_tx1, rx1) = channel::<i32>();
+    let (_tx2, rx2) = channel::<i32>();
+    let (_tx3, rx3) = channel::<i32>();
+    let (_tx4, rx4) = channel::<i32>();
+    let (tx5, rx5) = channel::<i32>();
+    tx5.send(4).unwrap();
+    select! {
+        _foo = rx1.recv() => { panic!("1") },
+        _foo = rx2.recv() => { panic!("2") },
+        _foo = rx3.recv() => { panic!("3") },
+        _foo = rx4.recv() => { panic!("4") },
+        foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
+    }
+}
+
+#[test]
+fn closed() {
+    let (_tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<i32>();
+    drop(tx2);
+
+    select! {
+        _a1 = rx1.recv() => { panic!() },
+        a2 = rx2.recv() => { assert!(a2.is_err()); }
+    }
+}
+
+#[test]
+fn unblocks() {
+    let (tx1, rx1) = channel::<i32>();
+    let (_tx2, rx2) = channel::<i32>();
+    let (tx3, rx3) = channel::<i32>();
+
+    let _t = thread::spawn(move|| {
+        for _ in 0..20 { thread::yield_now(); }
+        tx1.send(1).unwrap();
+        rx3.recv().unwrap();
+        for _ in 0..20 { thread::yield_now(); }
+    });
+
+    select! {
+        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
+        _b = rx2.recv() => { panic!() }
+    }
+    tx3.send(1).unwrap();
+    select! {
+        a = rx1.recv() => { assert!(a.is_err()) },
+        _b = rx2.recv() => { panic!() }
+    }
+}
+
+#[test]
+fn both_ready() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<i32>();
+    let (tx3, rx3) = channel::<()>();
+
+    let _t = thread::spawn(move|| {
+        for _ in 0..20 { thread::yield_now(); }
+        tx1.send(1).unwrap();
+        tx2.send(2).unwrap();
+        rx3.recv().unwrap();
+    });
+
+    select! {
+        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
+        a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
+    }
+    select! {
+        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
+        a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
+    }
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
+    tx3.send(()).unwrap();
+}
+
+#[test]
+fn stress() {
+    const AMT: i32 = 10000;
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<i32>();
+    let (tx3, rx3) = channel::<()>();
+
+    let _t = thread::spawn(move|| {
+        for i in 0..AMT {
+            if i % 2 == 0 {
+                tx1.send(i).unwrap();
+            } else {
+                tx2.send(i).unwrap();
+            }
+            rx3.recv().unwrap();
+        }
+    });
+
+    for i in 0..AMT {
+        select! {
+            i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
+            i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
+        }
+        tx3.send(()).unwrap();
+    }
+}
+
+#[allow(unused_must_use)]
+#[test]
+fn cloning() {
+    let (tx1, rx1) = channel::<i32>();
+    let (_tx2, rx2) = channel::<i32>();
+    let (tx3, rx3) = channel::<()>();
+
+    let _t = thread::spawn(move|| {
+        rx3.recv().unwrap();
+        tx1.clone();
+        assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
+        tx1.send(2).unwrap();
+        rx3.recv().unwrap();
+    });
+
+    tx3.send(()).unwrap();
+    select! {
+        _i1 = rx1.recv() => {},
+        _i2 = rx2.recv() => panic!()
+    }
+    tx3.send(()).unwrap();
+}
+
+#[allow(unused_must_use)]
+#[test]
+fn cloning2() {
+    let (tx1, rx1) = channel::<i32>();
+    let (_tx2, rx2) = channel::<i32>();
+    let (tx3, rx3) = channel::<()>();
+
+    let _t = thread::spawn(move|| {
+        rx3.recv().unwrap();
+        tx1.clone();
+        assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
+        tx1.send(2).unwrap();
+        rx3.recv().unwrap();
+    });
+
+    tx3.send(()).unwrap();
+    select! {
+        _i1 = rx1.recv() => {},
+        _i2 = rx2.recv() => panic!()
+    }
+    tx3.send(()).unwrap();
+}
+
+#[test]
+fn cloning3() {
+    let (tx1, rx1) = channel::<()>();
+    let (tx2, rx2) = channel::<()>();
+    let (tx3, rx3) = channel::<()>();
+    let _t = thread::spawn(move|| {
+        let s = Select::new();
+        let mut h1 = s.handle(&rx1);
+        let mut h2 = s.handle(&rx2);
+        unsafe { h2.add(); }
+        unsafe { h1.add(); }
+        assert_eq!(s.wait(), h2.id());
+        tx3.send(()).unwrap();
+    });
+
+    for _ in 0..1000 { thread::yield_now(); }
+    drop(tx1.clone());
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+}
+
+#[test]
+fn preflight1() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    select! {
+        _n = rx.recv() => {}
+    }
+}
+
+#[test]
+fn preflight2() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    tx.send(()).unwrap();
+    select! {
+        _n = rx.recv() => {}
+    }
+}
+
+#[test]
+fn preflight3() {
+    let (tx, rx) = channel();
+    drop(tx.clone());
+    tx.send(()).unwrap();
+    select! {
+        _n = rx.recv() => {}
+    }
+}
+
+#[test]
+fn preflight4() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    let s = Select::new();
+    let mut h = s.handle(&rx);
+    unsafe { h.add(); }
+    assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight5() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    tx.send(()).unwrap();
+    let s = Select::new();
+    let mut h = s.handle(&rx);
+    unsafe { h.add(); }
+    assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight6() {
+    let (tx, rx) = channel();
+    drop(tx.clone());
+    tx.send(()).unwrap();
+    let s = Select::new();
+    let mut h = s.handle(&rx);
+    unsafe { h.add(); }
+    assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight7() {
+    let (tx, rx) = channel::<()>();
+    drop(tx);
+    let s = Select::new();
+    let mut h = s.handle(&rx);
+    unsafe { h.add(); }
+    assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight8() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    drop(tx);
+    rx.recv().unwrap();
+    let s = Select::new();
+    let mut h = s.handle(&rx);
+    unsafe { h.add(); }
+    assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn preflight9() {
+    let (tx, rx) = channel();
+    drop(tx.clone());
+    tx.send(()).unwrap();
+    drop(tx);
+    rx.recv().unwrap();
+    let s = Select::new();
+    let mut h = s.handle(&rx);
+    unsafe { h.add(); }
+    assert_eq!(s.wait2(false), h.id());
+}
+
+#[test]
+fn oneshot_data_waiting() {
+    let (tx1, rx1) = channel();
+    let (tx2, rx2) = channel();
+    let _t = thread::spawn(move|| {
+        select! {
+            _n = rx1.recv() => {}
+        }
+        tx2.send(()).unwrap();
+    });
+
+    for _ in 0..100 { thread::yield_now() }
+    tx1.send(()).unwrap();
+    rx2.recv().unwrap();
+}
+
+#[test]
+fn stream_data_waiting() {
+    let (tx1, rx1) = channel();
+    let (tx2, rx2) = channel();
+    tx1.send(()).unwrap();
+    tx1.send(()).unwrap();
+    rx1.recv().unwrap();
+    rx1.recv().unwrap();
+    let _t = thread::spawn(move|| {
+        select! {
+            _n = rx1.recv() => {}
+        }
+        tx2.send(()).unwrap();
+    });
+
+    for _ in 0..100 { thread::yield_now() }
+    tx1.send(()).unwrap();
+    rx2.recv().unwrap();
+}
+
+#[test]
+fn shared_data_waiting() {
+    let (tx1, rx1) = channel();
+    let (tx2, rx2) = channel();
+    drop(tx1.clone());
+    tx1.send(()).unwrap();
+    rx1.recv().unwrap();
+    let _t = thread::spawn(move|| {
+        select! {
+            _n = rx1.recv() => {}
+        }
+        tx2.send(()).unwrap();
+    });
+
+    for _ in 0..100 { thread::yield_now() }
+    tx1.send(()).unwrap();
+    rx2.recv().unwrap();
+}
+
+#[test]
+fn sync1() {
+    let (tx, rx) = sync_channel::<i32>(1);
+    tx.send(1).unwrap();
+    select! {
+        n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
+    }
+}
+
+#[test]
+fn sync2() {
+    let (tx, rx) = sync_channel::<i32>(0);
+    let _t = thread::spawn(move|| {
+        for _ in 0..100 { thread::yield_now() }
+        tx.send(1).unwrap();
+    });
+    select! {
+        n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
+    }
+}
+
+#[test]
+fn sync3() {
+    let (tx1, rx1) = sync_channel::<i32>(0);
+    let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
+    let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
+    let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
+    select! {
+        n = rx1.recv() => {
+            let n = n.unwrap();
+            assert_eq!(n, 1);
+            assert_eq!(rx2.recv().unwrap(), 2);
+        },
+        n = rx2.recv() => {
+            let n = n.unwrap();
+            assert_eq!(n, 2);
+            assert_eq!(rx1.recv().unwrap(), 1);
+        }
+    }
+}
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index 5d2eb5f8e73..8207709e1f9 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -126,7 +126,8 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
 /// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable]
+#[cfg_attr(stage0, allow_internal_unstable)]
+#[cfg_attr(not(stage0), allow_internal_unstable(thread_local_internals))]
 macro_rules! thread_local {
     // empty (base case for the recursion)
     () => {};
@@ -148,7 +149,10 @@ macro_rules! thread_local {
            reason = "should not be necessary",
            issue = "0")]
 #[macro_export]
-#[allow_internal_unstable]
+#[cfg_attr(stage0, allow_internal_unstable)]
+#[cfg_attr(not(stage0), allow_internal_unstable(
+    thread_local_internals, cfg_target_thread_local, thread_local,
+))]
 #[allow_internal_unsafe]
 macro_rules! __thread_local_inner {
     (@key $(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {