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/alloc.rs4
-rw-r--r--src/libstd/error.rs4
-rw-r--r--src/libstd/future.rs6
-rw-r--r--src/libstd/lib.rs41
-rw-r--r--src/libstd/net/ip.rs1
-rw-r--r--src/libstd/os/fortanix_sgx/mod.rs21
-rw-r--r--src/libstd/sync/mutex.rs4
-rw-r--r--src/libstd/sys/mod.rs2
-rw-r--r--src/libstd/sys/redox/thread_local.rs4
-rw-r--r--src/libstd/sys/sgx/abi/entry.S20
-rw-r--r--src/libstd/sys/sgx/abi/panic.rs30
-rw-r--r--src/libstd/sys/sgx/abi/tls.rs41
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/alloc.rs7
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/mod.rs5
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/raw.rs13
-rw-r--r--src/libstd/sys/sgx/ext/ffi.rs109
-rw-r--r--src/libstd/sys/sgx/ext/mod.rs1
-rw-r--r--src/libstd/sys/sgx/mod.rs2
-rw-r--r--src/libstd/sys/sgx/rwlock.rs18
-rw-r--r--src/libstd/sys/unix/pipe.rs4
-rw-r--r--src/libstd/sys/windows/pipe.rs4
-rw-r--r--src/libstd/sys/windows/time.rs118
-rw-r--r--src/libstd/tests/run-time-detect.rs100
-rw-r--r--src/libstd/thread/mod.rs2
-rw-r--r--src/libstd/time.rs9
25 files changed, 429 insertions, 141 deletions
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index 537f56a8da7..8b6e5680c2d 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -95,11 +95,11 @@ pub use alloc_crate::alloc::*;
 ///
 /// ```rust
 /// use std::alloc::{System, GlobalAlloc, Layout};
-/// use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering::SeqCst};
+/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
 ///
 /// struct Counter;
 ///
-/// static ALLOCATED: AtomicUsize = ATOMIC_USIZE_INIT;
+/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
 ///
 /// unsafe impl GlobalAlloc for Counter {
 ///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 2f9efb3f0fb..50415d9aeb9 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -197,9 +197,7 @@ pub trait Error: Debug + Display {
 
     /// Get the `TypeId` of `self`
     #[doc(hidden)]
-    #[unstable(feature = "error_type_id",
-               reason = "unclear whether to commit to this public implementation detail",
-               issue = "27745")]
+    #[stable(feature = "error_type_id", since = "1.34.0")]
     fn type_id(&self) -> TypeId where Self: 'static {
         TypeId::of::<Self>()
     }
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index a7b9895177f..d1203be3cf0 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -11,7 +11,7 @@ use core::ops::{Drop, Generator, GeneratorState};
 #[doc(inline)]
 pub use core::future::*;
 
-/// Wrap a future in a generator.
+/// Wrap a generator in a future.
 ///
 /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
 /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
@@ -33,7 +33,9 @@ impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
 impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
     type Output = T::Return;
     fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
-        set_task_waker(lw, || match unsafe { Pin::get_unchecked_mut(self).0.resume() } {
+        // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
+        let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
+        set_task_waker(lw, || match gen.resume() {
             GeneratorState::Yielded(()) => Poll::Pending,
             GeneratorState::Complete(x) => Poll::Ready(x),
         })
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 83db3f347a7..244caf28ec7 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -7,11 +7,9 @@
 //! primitives](#primitives), [standard macros](#macros), [I/O] and
 //! [multithreading], among [many other things][other].
 //!
-//! `std` is available to all Rust crates by default, just as if each one
-//! contained an `extern crate std;` import at the [crate root]. Therefore the
+//! `std` is available to all Rust crates by default. Therefore the
 //! standard library can be accessed in [`use`] statements through the path
-//! `std`, as in [`use std::env`], or in expressions through the absolute path
-//! `::std`, as in [`::std::env::args`].
+//! `std`, as in [`use std::env`].
 //!
 //! # How to read this documentation
 //!
@@ -157,7 +155,6 @@
 //! [TCP]: net/struct.TcpStream.html
 //! [The Rust Prelude]: prelude/index.html
 //! [UDP]: net/struct.UdpSocket.html
-//! [`::std::env::args`]: env/fn.args.html
 //! [`Arc`]: sync/struct.Arc.html
 //! [owned slice]: boxed/index.html
 //! [`Cell`]: cell/struct.Cell.html
@@ -191,7 +188,6 @@
 //! [`thread`]: thread/index.html
 //! [`use std::env`]: env/index.html
 //! [`use`]: ../book/ch07-02-modules-and-use-to-control-scope-and-privacy.html#the-use-keyword-to-bring-paths-into-a-scope
-//! [crate root]: ../book/ch07-01-packages-and-crates-for-making-libraries-and-executables.html
 //! [crates.io]: https://crates.io
 //! [deref-coercions]: ../book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods
 //! [files]: fs/struct.File.html
@@ -238,12 +234,9 @@
 #![feature(c_variadic)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
-#![cfg_attr(stage0, feature(cfg_target_vendor))]
 #![feature(char_error_internals)]
 #![feature(compiler_builtins_lib)]
 #![feature(concat_idents)]
-#![cfg_attr(stage0, feature(const_int_ops))]
-#![cfg_attr(stage0, feature(const_ip))]
 #![feature(const_raw_ptr_deref)]
 #![feature(const_cstr_unchecked)]
 #![feature(core_intrinsics)]
@@ -365,6 +358,9 @@ pub mod prelude;
 // Public module declarations and re-exports
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::any;
+#[stable(feature = "simd_arch", since = "1.27.0")]
+#[doc(no_inline)]
+pub use core::arch;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::cell;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -496,29 +492,22 @@ mod memchr;
 // compiler
 pub mod rt;
 
-// Pull in the `stdsimd` crate directly into libstd. This is the same as
-// libcore's arch/simd modules where the source of truth here is in a different
-// repository, but we pull things in here manually to get it into libstd.
+// Pull in the `std_detect` crate directly into libstd. The contents of
+// `std_detect` are in a different repository: rust-lang-nursery/stdsimd.
 //
-// Note that the #[cfg] here is intended to do two things. First it allows us to
-// change the rustc implementation of intrinsics in stage0 by not compiling simd
-// intrinsics in stage0. Next it doesn't compile anything in test mode as
-// stdsimd has tons of its own tests which we don't want to run.
-#[path = "../stdsimd/stdsimd/mod.rs"]
+// `std_detect` depends on libstd, but the contents of this module are
+// set up in such a way that directly pulling it here works such that the
+// crate uses the this crate as its libstd.
+#[path = "../stdsimd/crates/std_detect/src/mod.rs"]
 #[allow(missing_debug_implementations, missing_docs, dead_code)]
 #[unstable(feature = "stdsimd", issue = "48556")]
 #[cfg(not(test))]
-mod stdsimd;
-
-// A "fake" module needed by the `stdsimd` module to compile, not actually
-// exported though.
-mod coresimd {
-    pub use core::arch;
-}
+mod std_detect;
 
-#[stable(feature = "simd_arch", since = "1.27.0")]
+#[doc(hidden)]
+#[unstable(feature = "stdsimd", issue = "48556")]
 #[cfg(not(test))]
-pub use stdsimd::arch;
+pub use std_detect::detect;
 
 // Include a number of private modules that exist solely to provide
 // the rustdoc documentation for primitive types. Using `include!`
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index f98113e0896..f45cd8b8c10 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -328,7 +328,6 @@ impl Ipv4Addr {
     /// let addr = Ipv4Addr::new(127, 0, 0, 1);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(stage0, rustc_const_unstable(feature = "const_ip"))]
     pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
         Ipv4Addr {
             inner: c::in_addr {
diff --git a/src/libstd/os/fortanix_sgx/mod.rs b/src/libstd/os/fortanix_sgx/mod.rs
index 47c7b5dcbe6..bd6f4b4465b 100644
--- a/src/libstd/os/fortanix_sgx/mod.rs
+++ b/src/libstd/os/fortanix_sgx/mod.rs
@@ -16,31 +16,16 @@ pub mod usercalls {
     /// Primitives for allocating memory in userspace as well as copying data
     /// to and from user memory.
     pub mod alloc {
-        pub use sys::abi::usercalls::alloc;
+        pub use sys::abi::usercalls::alloc::*;
     }
 
     /// Lowest-level interfaces to usercalls and usercall ABI type definitions.
     pub mod raw {
-        use sys::abi::usercalls::raw::invoke_with_usercalls;
-        pub use sys::abi::usercalls::raw::do_usercall;
+        pub use sys::abi::usercalls::raw::{do_usercall, Usercalls as UsercallNrs};
         pub use sys::abi::usercalls::raw::{accept_stream, alloc, async_queues, bind_stream, close,
                                            connect_stream, exit, flush, free, insecure_time,
                                            launch_thread, read, read_alloc, send, wait, write};
 
-        macro_rules! define_usercallnrs {
-            ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)*; )*) => {
-                /// Usercall numbers as per the ABI.
-                #[repr(C)]
-                #[unstable(feature = "sgx_platform", issue = "56975")]
-                #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
-                #[allow(missing_docs)]
-                pub enum UsercallNrs {
-                    $($f,)*
-                }
-            };
-        }
-        invoke_with_usercalls!(define_usercallnrs);
-
         // fortanix-sgx-abi re-exports
         pub use sys::abi::usercalls::raw::{ByteBuffer, FifoDescriptor, Return, Usercall};
         pub use sys::abi::usercalls::raw::Error;
@@ -56,4 +41,4 @@ pub mod mem {
     pub use sys::abi::mem::*;
 }
 
-pub use sys::ext::{io, arch};
+pub use sys::ext::{io, arch, ffi};
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 856bb260424..59829db23cb 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -450,9 +450,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_struct("MutexGuard")
-            .field("lock", &self.__lock)
-            .finish()
+        fmt::Debug::fmt(&**self, f)
     }
 }
 
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index f398a2a6225..99ef74179c2 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -54,6 +54,7 @@ cfg_if! {
 cfg_if! {
     if #[cfg(any(unix, target_os = "redox"))] {
         // On unix we'll document what's already available
+        #[stable(feature = "rust1", since = "1.0.0")]
         pub use self::ext as unix_ext;
     } else if #[cfg(any(target_os = "cloudabi",
                         target_arch = "wasm32",
@@ -77,6 +78,7 @@ cfg_if! {
     if #[cfg(windows)] {
         // On windows we'll just be documenting what's already available
         #[allow(missing_docs)]
+        #[stable(feature = "rust1", since = "1.0.0")]
         pub use self::ext as windows_ext;
     } else if #[cfg(any(target_os = "cloudabi",
                         target_arch = "wasm32",
diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs
index a1c4b10e450..a1929b94165 100644
--- a/src/libstd/sys/redox/thread_local.rs
+++ b/src/libstd/sys/redox/thread_local.rs
@@ -2,13 +2,13 @@
 
 use collections::BTreeMap;
 use ptr;
-use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use sync::atomic::{AtomicUsize, Ordering};
 
 pub type Key = usize;
 
 type Dtor = unsafe extern fn(*mut u8);
 
-static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;
+static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
 
 static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();
 
diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index ac7f95d4eae..9b46c2180d9 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -66,7 +66,7 @@ IMAGE_BASE:
     globvar EH_FRM_HDR_SIZE 8
 
 .Lreentry_panic_msg:
-    .asciz "Re-entered panicked enclave!"
+    .asciz "Re-entered aborted enclave!"
 .Lreentry_panic_msg_end:
 
 .Lusercall_panic_msg:
@@ -80,7 +80,7 @@ IMAGE_BASE:
     .org .+48 /*  reserved bits */
 
 .data
-.Lpanicked:
+.Laborted:
     .byte 0
 
 /*  TCS local storage section */
@@ -134,6 +134,9 @@ sgx_entry:
     jz .Lskip_debug_init
     mov %r10,%gs:tcsls_debug_panic_buf_ptr
 .Lskip_debug_init:
+/*  check for abort */
+    bt $0,.Laborted(%rip)
+    jc .Lreentry_panic
 /*  check if returning from usercall */
     mov %gs:tcsls_last_rsp,%r11
     test %r11,%r11
@@ -164,9 +167,6 @@ sgx_entry:
     mov %r14,%r8
     mov %r15,%r9
 .Lskip_init:
-/*  check for panic */
-    bt $0,.Lpanicked(%rip)
-    jc .Lreentry_panic
 /*  call into main entry point */
     load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
     call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
@@ -237,18 +237,18 @@ sgx_entry:
     stmxcsr (%rsp)
 .endm
 
-.global panic_exit
-panic_exit:
+.global usercall_exit
+usercall_exit:
 /* save registers in DEBUG mode, so that debugger can reconstruct the stack */
     testb $0xff,DEBUG(%rip)
     jz .Lskip_save_registers
     push_callee_saved_registers
     movq %rsp,%gs:tcsls_panic_last_rsp
 .Lskip_save_registers:
-/* set panicked bit */
-    movb $1,.Lpanicked(%rip)
+/* set aborted bit */
+    movb $1,.Laborted(%rip)
 /* call usercall exit(true) */
-    mov $1,%esi   /*  RSI = usercall() argument: panic = true */
+    /* NOP: mov %rsi,%rsi */ /*  RSI = usercall() argument: panic */
     xor %rdx,%rdx /*  RDX cleared */
     movq $usercall_nr_exit,%rdi /*  RDI = usercall exit */
     jmp .Lexit
diff --git a/src/libstd/sys/sgx/abi/panic.rs b/src/libstd/sys/sgx/abi/panic.rs
index 5ace7fb3368..d23fa9a9ec6 100644
--- a/src/libstd/sys/sgx/abi/panic.rs
+++ b/src/libstd/sys/sgx/abi/panic.rs
@@ -1,12 +1,18 @@
+use super::usercalls::alloc::UserRef;
+use cmp;
 use io::{self, Write};
-use slice::from_raw_parts_mut;
+use mem;
 
 extern "C" {
     fn take_debug_panic_buf_ptr() -> *mut u8;
     static DEBUG: u8;
 }
 
-pub(crate) struct SgxPanicOutput(Option<&'static mut [u8]>);
+pub(crate) struct SgxPanicOutput(Option<&'static mut UserRef<[u8]>>);
+
+fn empty_user_slice() -> &'static mut UserRef<[u8]> {
+    unsafe { UserRef::from_raw_parts_mut(1 as *mut u8, 0) }
+}
 
 impl SgxPanicOutput {
     pub(crate) fn new() -> Option<Self> {
@@ -17,32 +23,36 @@ impl SgxPanicOutput {
         }
     }
 
-    fn init(&mut self) -> &mut &'static mut [u8] {
+    fn init(&mut self) -> &mut &'static mut UserRef<[u8]> {
         self.0.get_or_insert_with(|| unsafe {
             let ptr = take_debug_panic_buf_ptr();
             if ptr.is_null() {
-                &mut []
+                empty_user_slice()
             } else {
-                from_raw_parts_mut(ptr, 1024)
+                UserRef::from_raw_parts_mut(ptr, 1024)
             }
         })
     }
 }
 
 impl Write for SgxPanicOutput {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.init().write(buf)
+    fn write(&mut self, src: &[u8]) -> io::Result<usize> {
+        let dst = mem::replace(self.init(), empty_user_slice());
+        let written = cmp::min(src.len(), dst.len());
+        dst[..written].copy_from_enclave(&src[..written]);
+        self.0 = Some(&mut dst[written..]);
+        Ok(written)
     }
 
     fn flush(&mut self) -> io::Result<()> {
-        self.init().flush()
+        Ok(())
     }
 }
 
 #[no_mangle]
 pub extern "C" fn panic_msg(msg: &str) -> ! {
     let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes()));
-    unsafe { panic_exit(); }
+    unsafe { usercall_exit(true); }
 }
 
-extern "C" { pub fn panic_exit() -> !; }
+extern "C" { pub fn usercall_exit(panic: bool) -> !; }
diff --git a/src/libstd/sys/sgx/abi/tls.rs b/src/libstd/sys/sgx/abi/tls.rs
index aba93db915f..b8e09d58deb 100644
--- a/src/libstd/sys/sgx/abi/tls.rs
+++ b/src/libstd/sys/sgx/abi/tls.rs
@@ -1,4 +1,4 @@
-use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use sync::atomic::{AtomicUsize, Ordering};
 use ptr;
 use mem;
 use cell::Cell;
@@ -15,7 +15,40 @@ macro_rules! dup {
     ((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* ));
     (() $($val:tt)*) => ([$($val),*])
 }
-static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) ATOMIC_USIZE_INIT);
+static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = [
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+];
 
 extern "C" {
     fn get_tls_ptr() -> *const u8;
@@ -119,7 +152,7 @@ impl Tls {
 }
 
 mod sync_bitset {
-    use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+    use sync::atomic::{AtomicUsize, Ordering};
     use iter::{Enumerate, Peekable};
     use slice::Iter;
     use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS};
@@ -128,7 +161,7 @@ mod sync_bitset {
     pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]);
 
     pub(super) const SYNC_BITSET_INIT: SyncBitset =
-        SyncBitset([ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT]);
+        SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]);
 
     impl SyncBitset {
         pub fn get(&self, index: usize) -> bool {
diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs
index 8d0013a235a..2efbaa9b148 100644
--- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs
@@ -537,7 +537,12 @@ impl UserRef<super::raw::ByteBuffer> {
     pub fn copy_user_buffer(&self) -> Vec<u8> {
         unsafe {
             let buf = self.to_enclave();
-            User::from_raw_parts(buf.data as _, buf.len).to_enclave()
+            if buf.len > 0 {
+                User::from_raw_parts(buf.data as _, buf.len).to_enclave()
+            } else {
+                // Mustn't look at `data` or call `free` if `len` is `0`.
+                Vec::with_capacity(0)
+            }
         }
     }
 }
diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs
index 58903761ebe..bae044b906b 100644
--- a/src/libstd/sys/sgx/abi/usercalls/mod.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs
@@ -22,7 +22,8 @@ pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> {
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn read_alloc(fd: Fd) -> IoResult<Vec<u8>> {
     unsafe {
-        let mut userbuf = alloc::User::<ByteBuffer>::uninitialized();
+        let userbuf = ByteBuffer { data: ::ptr::null_mut(), len: 0 };
+        let mut userbuf = alloc::User::new_from_enclave(&userbuf);
         raw::read_alloc(fd, userbuf.as_raw_mut_ptr()).from_sgx_result()?;
         Ok(userbuf.copy_user_buffer())
     }
@@ -119,7 +120,7 @@ pub unsafe fn launch_thread() -> IoResult<()> {
 /// Usercall `exit`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn exit(panic: bool) -> ! {
-    unsafe { raw::exit(panic) }
+    unsafe { super::panic::usercall_exit(panic) }
 }
 
 /// Usercall `wait`. See the ABI documentation for more information.
diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs
index 27aca7c0903..27f780ca224 100644
--- a/src/libstd/sys/sgx/abi/usercalls/raw.rs
+++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs
@@ -41,10 +41,15 @@ trait ReturnValue {
 macro_rules! define_usercalls {
     // Using `$r:tt` because `$r:ty` doesn't match ! in `clobber_diverging`
     ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:tt)*; )*) => {
-        #[repr(C)]
-        #[allow(non_camel_case_types)]
-        enum Usercalls {
-            __enclave_usercalls_invalid,
+        /// Usercall numbers as per the ABI.
+        #[repr(u64)]
+        #[unstable(feature = "sgx_platform", issue = "56975")]
+        #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
+        #[allow(missing_docs, non_camel_case_types)]
+        #[non_exhaustive]
+        pub enum Usercalls {
+            #[doc(hidden)]
+            __enclave_usercalls_invalid = 0,
             $($f,)*
         }
 
diff --git a/src/libstd/sys/sgx/ext/ffi.rs b/src/libstd/sys/sgx/ext/ffi.rs
new file mode 100644
index 00000000000..7b0ffea49ae
--- /dev/null
+++ b/src/libstd/sys/sgx/ext/ffi.rs
@@ -0,0 +1,109 @@
+//! SGX-specific extension to the primitives in the `std::ffi` module
+
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+use ffi::{OsStr, OsString};
+use mem;
+use sys::os_str::Buf;
+use sys_common::{FromInner, IntoInner, AsInner};
+
+/// SGX-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait OsStringExt {
+    /// Creates an [`OsString`] from a byte vector.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsString;
+    /// use std::os::unix::ffi::OsStringExt;
+    ///
+    /// let bytes = b"foo".to_vec();
+    /// let os_string = OsString::from_vec(bytes);
+    /// assert_eq!(os_string.to_str(), Some("foo"));
+    /// ```
+    ///
+    /// [`OsString`]: ../../../ffi/struct.OsString.html
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    fn from_vec(vec: Vec<u8>) -> Self;
+
+    /// Yields the underlying byte vector of this [`OsString`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsString;
+    /// use std::os::unix::ffi::OsStringExt;
+    ///
+    /// let mut os_string = OsString::new();
+    /// os_string.push("foo");
+    /// let bytes = os_string.into_vec();
+    /// assert_eq!(bytes, b"foo");
+    /// ```
+    ///
+    /// [`OsString`]: ../../../ffi/struct.OsString.html
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    fn into_vec(self) -> Vec<u8>;
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl OsStringExt for OsString {
+    fn from_vec(vec: Vec<u8>) -> OsString {
+        FromInner::from_inner(Buf { inner: vec })
+    }
+    fn into_vec(self) -> Vec<u8> {
+        self.into_inner().inner
+    }
+}
+
+/// SGX-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait OsStrExt {
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    /// Creates an [`OsStr`] from a byte slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsStr;
+    /// use std::os::unix::ffi::OsStrExt;
+    ///
+    /// let bytes = b"foo";
+    /// let os_str = OsStr::from_bytes(bytes);
+    /// assert_eq!(os_str.to_str(), Some("foo"));
+    /// ```
+    ///
+    /// [`OsStr`]: ../../../ffi/struct.OsStr.html
+    fn from_bytes(slice: &[u8]) -> &Self;
+
+    /// Gets the underlying byte view of the [`OsStr`] slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsStr;
+    /// use std::os::unix::ffi::OsStrExt;
+    ///
+    /// let mut os_str = OsStr::new("foo");
+    /// let bytes = os_str.as_bytes();
+    /// assert_eq!(bytes, b"foo");
+    /// ```
+    ///
+    /// [`OsStr`]: ../../../ffi/struct.OsStr.html
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    fn as_bytes(&self) -> &[u8];
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl OsStrExt for OsStr {
+    fn from_bytes(slice: &[u8]) -> &OsStr {
+        unsafe { mem::transmute(slice) }
+    }
+    fn as_bytes(&self) -> &[u8] {
+        &self.as_inner().inner
+    }
+}
diff --git a/src/libstd/sys/sgx/ext/mod.rs b/src/libstd/sys/sgx/ext/mod.rs
index 5489f6f5694..51b2659da83 100644
--- a/src/libstd/sys/sgx/ext/mod.rs
+++ b/src/libstd/sys/sgx/ext/mod.rs
@@ -2,3 +2,4 @@
 
 pub mod arch;
 pub mod io;
+pub mod ffi;
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
index 7f8550490a1..f2593c35bed 100644
--- a/src/libstd/sys/sgx/mod.rs
+++ b/src/libstd/sys/sgx/mod.rs
@@ -125,7 +125,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
 }
 
 pub unsafe fn abort_internal() -> ! {
-    abi::panic::panic_exit()
+    abi::panic::usercall_exit(true)
 }
 
 pub fn hashmap_random_keys() -> (u64, u64) {
diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
index 47874158ed9..33163a556c1 100644
--- a/src/libstd/sys/sgx/rwlock.rs
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -1,3 +1,4 @@
+use alloc::{self, Layout};
 use num::NonZeroUsize;
 use slice;
 use str;
@@ -18,9 +19,6 @@ unsafe fn rw_lock_size_assert(r: RWLock) {
     mem::transmute::<RWLock, [u8; 128]>(r);
 }
 
-//unsafe impl Send for RWLock {}
-//unsafe impl Sync for RWLock {} // FIXME
-
 impl RWLock {
     pub const fn new() -> RWLock {
         RWLock {
@@ -147,6 +145,7 @@ impl RWLock {
         self.__write_unlock(rguard, wguard);
     }
 
+    // only used by __rust_rwlock_unlock below
     #[inline]
     unsafe fn unlock(&self) {
         let rguard = self.readers.lock();
@@ -164,6 +163,7 @@ impl RWLock {
 
 const EINVAL: i32 = 22;
 
+// used by libunwind port
 #[no_mangle]
 pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
     if p.is_null() {
@@ -190,6 +190,8 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
     return 0;
 }
 
+// the following functions are also used by the libunwind port. They're
+// included here to make sure parallel codegen and LTO don't mess things up.
 #[no_mangle]
 pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
     if s < 0 {
@@ -206,6 +208,16 @@ pub unsafe extern "C" fn __rust_abort() {
     ::sys::abort_internal();
 }
 
+#[no_mangle]
+pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
+    alloc::alloc(Layout::from_size_align_unchecked(size, align))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
+    alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+}
+
 #[cfg(test)]
 mod tests {
 
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index 91793a0d5ec..a746d982c6c 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -1,7 +1,7 @@
 use io;
 use libc::{self, c_int};
 use mem;
-use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+use sync::atomic::{AtomicBool, Ordering};
 use sys::fd::FileDesc;
 use sys::{cvt, cvt_r};
 
@@ -13,7 +13,7 @@ pub struct AnonPipe(FileDesc);
 
 pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
     syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int }
-    static INVALID: AtomicBool = ATOMIC_BOOL_INIT;
+    static INVALID: AtomicBool = AtomicBool::new(false);
 
     let mut fds = [0; 2];
 
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
index 2b1dbe310ee..0d9195a5c97 100644
--- a/src/libstd/sys/windows/pipe.rs
+++ b/src/libstd/sys/windows/pipe.rs
@@ -7,7 +7,7 @@ use path::Path;
 use ptr;
 use slice;
 use sync::atomic::Ordering::SeqCst;
-use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+use sync::atomic::AtomicUsize;
 use sys::c;
 use sys::fs::{File, OpenOptions};
 use sys::handle::Handle;
@@ -148,7 +148,7 @@ pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> {
 }
 
 fn random_number() -> usize {
-    static N: AtomicUsize = ATOMIC_USIZE_INIT;
+    static N: AtomicUsize = AtomicUsize::new(0);
     loop {
         if N.load(SeqCst) != 0 {
             return N.fetch_add(1, SeqCst)
diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs
index 8e8e9195cf4..8a8159af2f1 100644
--- a/src/libstd/sys/windows/time.rs
+++ b/src/libstd/sys/windows/time.rs
@@ -1,10 +1,7 @@
 use cmp::Ordering;
 use fmt;
 use mem;
-use sync::Once;
 use sys::c;
-use sys::cvt;
-use sys_common::mul_div_u64;
 use time::Duration;
 use convert::TryInto;
 use core::hash::{Hash, Hasher};
@@ -14,7 +11,9 @@ const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
 
 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
 pub struct Instant {
-    t: c::LARGE_INTEGER,
+    // This duration is relative to an arbitrary microsecond epoch
+    // from the winapi QueryPerformanceCounter function.
+    t: Duration,
 }
 
 #[derive(Copy, Clone)]
@@ -33,11 +32,12 @@ pub const UNIX_EPOCH: SystemTime = SystemTime {
 
 impl Instant {
     pub fn now() -> Instant {
-        let mut t = Instant { t: 0 };
-        cvt(unsafe {
-            c::QueryPerformanceCounter(&mut t.t)
-        }).unwrap();
-        t
+        // High precision timing on windows operates in "Performance Counter"
+        // units, as returned by the WINAPI QueryPerformanceCounter function.
+        // These relate to seconds by a factor of QueryPerformanceFrequency.
+        // In order to keep unit conversions out of normal interval math, we
+        // measure in QPC units and immediately convert to nanoseconds.
+        perf_counter::PerformanceCounterInstant::now().into()
     }
 
     pub fn actually_monotonic() -> bool {
@@ -45,47 +45,31 @@ impl Instant {
     }
 
     pub const fn zero() -> Instant {
-        Instant { t: 0 }
+        Instant { t: Duration::from_secs(0) }
     }
 
     pub fn sub_instant(&self, other: &Instant) -> Duration {
-        // Values which are +- 1 need to be considered as basically the same
-        // units in time due to various measurement oddities, according to
-        // Windows [1]
-        //
-        // [1]:
-        // https://msdn.microsoft.com/en-us/library/windows/desktop
-        //                           /dn553408%28v=vs.85%29.aspx#guidance
-        if other.t > self.t && other.t - self.t == 1 {
+        // On windows there's a threshold below which we consider two timestamps
+        // equivalent due to measurement error. For more details + doc link,
+        // check the docs on epsilon.
+        let epsilon =
+            perf_counter::PerformanceCounterInstant::epsilon();
+        if other.t > self.t && other.t - self.t <= epsilon {
             return Duration::new(0, 0)
         }
-        let diff = (self.t as u64).checked_sub(other.t as u64)
-                                  .expect("specified instant was later than \
-                                           self");
-        let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64);
-        Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32)
+        self.t.checked_sub(other.t)
+              .expect("specified instant was later than self")
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
-        let freq = frequency() as u64;
-        let t = other.as_secs()
-            .checked_mul(freq)?
-            .checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))?
-            .checked_add(self.t as u64)?;
         Some(Instant {
-            t: t as c::LARGE_INTEGER,
+            t: self.t.checked_add(*other)?
         })
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
-        let freq = frequency() as u64;
-        let t = other.as_secs().checked_mul(freq).and_then(|i| {
-            (self.t as u64).checked_sub(i)
-        }).and_then(|i| {
-            i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))
-        })?;
         Some(Instant {
-            t: t as c::LARGE_INTEGER,
+            t: self.t.checked_sub(*other)?
         })
     }
 }
@@ -186,14 +170,60 @@ fn intervals2dur(intervals: u64) -> Duration {
                   ((intervals % INTERVALS_PER_SEC) * 100) as u32)
 }
 
-fn frequency() -> c::LARGE_INTEGER {
-    static mut FREQUENCY: c::LARGE_INTEGER = 0;
-    static ONCE: Once = Once::new();
+mod perf_counter {
+    use super::{NANOS_PER_SEC};
+    use sync::Once;
+    use sys_common::mul_div_u64;
+    use sys::c;
+    use sys::cvt;
+    use time::Duration;
+
+    pub struct PerformanceCounterInstant {
+        ts: c::LARGE_INTEGER
+    }
+    impl PerformanceCounterInstant {
+        pub fn now() -> Self {
+            Self {
+                ts: query()
+            }
+        }
 
-    unsafe {
-        ONCE.call_once(|| {
-            cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap();
-        });
-        FREQUENCY
+        // Per microsoft docs, the margin of error for cross-thread time comparisons
+        // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
+        // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
+        //                   /acquiring-high-resolution-time-stamps
+        pub fn epsilon() -> Duration {
+            let epsilon = NANOS_PER_SEC / (frequency() as u64);
+            Duration::from_nanos(epsilon)
+        }
+    }
+    impl From<PerformanceCounterInstant> for super::Instant {
+        fn from(other: PerformanceCounterInstant) -> Self {
+            let freq = frequency() as u64;
+            let instant_nsec = mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq);
+            Self {
+                t: Duration::from_nanos(instant_nsec)
+            }
+        }
+    }
+
+    fn frequency() -> c::LARGE_INTEGER {
+        static mut FREQUENCY: c::LARGE_INTEGER = 0;
+        static ONCE: Once = Once::new();
+
+        unsafe {
+            ONCE.call_once(|| {
+                cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap();
+            });
+            FREQUENCY
+        }
+    }
+
+    fn query() -> c::LARGE_INTEGER {
+        let mut qpc_value: c::LARGE_INTEGER = 0;
+        cvt(unsafe {
+            c::QueryPerformanceCounter(&mut qpc_value)
+        }).unwrap();
+        qpc_value
     }
 }
diff --git a/src/libstd/tests/run-time-detect.rs b/src/libstd/tests/run-time-detect.rs
new file mode 100644
index 00000000000..eacce1e5682
--- /dev/null
+++ b/src/libstd/tests/run-time-detect.rs
@@ -0,0 +1,100 @@
+//! These tests just check that the macros are available in libstd.
+
+#![cfg_attr(
+    any(
+        all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
+        all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
+        all(target_arch = "powerpc", target_os = "linux"),
+        all(target_arch = "powerpc64", target_os = "linux"),
+    ),
+    feature(stdsimd)
+)]
+
+#[test]
+#[cfg(all(target_arch = "arm",
+          any(target_os = "linux", target_os = "android")))]
+fn arm_linux() {
+    println!("neon: {}", is_arm_feature_detected!("neon"));
+    println!("pmull: {}", is_arm_feature_detected!("pmull"));
+}
+
+#[test]
+#[cfg(all(
+    target_arch = "aarch64",
+    any(target_os = "linux", target_os = "android")
+))]
+fn aarch64_linux() {
+    println!("fp: {}", is_aarch64_feature_detected!("fp"));
+    println!("fp16: {}", is_aarch64_feature_detected!("fp16"));
+    println!("neon: {}", is_aarch64_feature_detected!("neon"));
+    println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
+    println!("sve: {}", is_aarch64_feature_detected!("sve"));
+    println!("crc: {}", is_aarch64_feature_detected!("crc"));
+    println!("crypto: {}", is_aarch64_feature_detected!("crypto"));
+    println!("lse: {}", is_aarch64_feature_detected!("lse"));
+    println!("rdm: {}", is_aarch64_feature_detected!("rdm"));
+    println!("rcpc: {}", is_aarch64_feature_detected!("rcpc"));
+    println!("dotprod: {}", is_aarch64_feature_detected!("dotprod"));
+}
+
+#[test]
+#[cfg(all(target_arch = "powerpc", target_os = "linux"))]
+fn powerpc_linux() {
+    println!("altivec: {}", is_powerpc_feature_detected!("altivec"));
+    println!("vsx: {}", is_powerpc_feature_detected!("vsx"));
+    println!("power8: {}", is_powerpc_feature_detected!("power8"));
+}
+
+#[test]
+#[cfg(all(target_arch = "powerpc64", target_os = "linux"))]
+fn powerpc64_linux() {
+    println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
+    println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
+    println!("power8: {}", is_powerpc64_feature_detected!("power8"));
+}
+
+#[test]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn x86_all() {
+    println!("aes: {:?}", is_x86_feature_detected!("aes"));
+    println!("pcmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
+    println!("rdrand: {:?}", is_x86_feature_detected!("rdrand"));
+    println!("rdseed: {:?}", is_x86_feature_detected!("rdseed"));
+    println!("tsc: {:?}", is_x86_feature_detected!("tsc"));
+    println!("mmx: {:?}", is_x86_feature_detected!("mmx"));
+    println!("sse: {:?}", is_x86_feature_detected!("sse"));
+    println!("sse2: {:?}", is_x86_feature_detected!("sse2"));
+    println!("sse3: {:?}", is_x86_feature_detected!("sse3"));
+    println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
+    println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1"));
+    println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2"));
+    println!("sse4a: {:?}", is_x86_feature_detected!("sse4a"));
+    println!("sha: {:?}", is_x86_feature_detected!("sha"));
+    println!("avx: {:?}", is_x86_feature_detected!("avx"));
+    println!("avx2: {:?}", is_x86_feature_detected!("avx2"));
+    println!("avx512f {:?}", is_x86_feature_detected!("avx512f"));
+    println!("avx512cd {:?}", is_x86_feature_detected!("avx512cd"));
+    println!("avx512er {:?}", is_x86_feature_detected!("avx512er"));
+    println!("avx512pf {:?}", is_x86_feature_detected!("avx512pf"));
+    println!("avx512bw {:?}", is_x86_feature_detected!("avx512bw"));
+    println!("avx512dq {:?}", is_x86_feature_detected!("avx512dq"));
+    println!("avx512vl {:?}", is_x86_feature_detected!("avx512vl"));
+    println!("avx512_ifma {:?}", is_x86_feature_detected!("avx512ifma"));
+    println!("avx512_vbmi {:?}", is_x86_feature_detected!("avx512vbmi"));
+    println!(
+        "avx512_vpopcntdq {:?}",
+        is_x86_feature_detected!("avx512vpopcntdq")
+    );
+    println!("fma: {:?}", is_x86_feature_detected!("fma"));
+    println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
+    println!("bmi2: {:?}", is_x86_feature_detected!("bmi2"));
+    println!("abm: {:?}", is_x86_feature_detected!("abm"));
+    println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
+    println!("tbm: {:?}", is_x86_feature_detected!("tbm"));
+    println!("popcnt: {:?}", is_x86_feature_detected!("popcnt"));
+    println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
+    println!("xsave: {:?}", is_x86_feature_detected!("xsave"));
+    println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt"));
+    println!("xsaves: {:?}", is_x86_feature_detected!("xsaves"));
+    println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
+}
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index a55b32c08a3..eb8e0c1c8ac 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -607,7 +607,7 @@ impl Builder {
 pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
     F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
 {
-    Builder::new().spawn(f).unwrap()
+    Builder::new().spawn(f).expect("failed to spawn thread")
 }
 
 /// Gets a handle to the thread that invokes it.
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index 507ea395c6c..23924559fcc 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -611,6 +611,15 @@ mod tests {
     }
 
     #[test]
+    fn instant_math_is_associative() {
+        let now = Instant::now();
+        let offset = Duration::from_millis(5);
+        // Changing the order of instant math shouldn't change the results,
+        // especially when the expression reduces to X + identity.
+        assert_eq!((now + offset) - now, (now - now) + offset);
+    }
+
+    #[test]
     #[should_panic]
     fn instant_duration_panic() {
         let a = Instant::now();