about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorPankaj Chaudhary <pankajchaudhary172@gmail.com>2020-07-13 14:14:37 +0530
committerPankajChaudhary5 <pankajchaudhary172@gmail.com>2020-07-13 14:57:22 +0530
commitbc2b37aad7f9cbd1c97e416e6b16325b607422b8 (patch)
tree867a6176bcf763bba6e5de12bc08f034a320ac56 /src/libstd
parente3ae4c7345cfd06b06c6996536d7c158ce6970db (diff)
parent9d09331e00b02f81c714b0c41ce3a38380dd36a2 (diff)
Merge branch 'master' into E0688
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/Cargo.toml9
-rw-r--r--src/libstd/alloc.rs2
-rw-r--r--src/libstd/ascii.rs26
-rw-r--r--src/libstd/collections/hash/map.rs39
-rw-r--r--src/libstd/collections/hash/set.rs31
-rw-r--r--src/libstd/env.rs2
-rw-r--r--src/libstd/error.rs3
-rw-r--r--src/libstd/f32.rs214
-rw-r--r--src/libstd/f64.rs346
-rw-r--r--src/libstd/ffi/c_str.rs209
-rw-r--r--src/libstd/ffi/mod.rs2
-rw-r--r--src/libstd/ffi/os_str.rs21
-rw-r--r--src/libstd/fs.rs48
-rw-r--r--src/libstd/future.rs112
-rw-r--r--src/libstd/io/buffered.rs39
-rw-r--r--src/libstd/io/cursor.rs26
-rw-r--r--src/libstd/io/error.rs9
-rw-r--r--src/libstd/io/impls.rs35
-rw-r--r--src/libstd/io/mod.rs45
-rw-r--r--src/libstd/io/stdio.rs133
-rw-r--r--src/libstd/io/util.rs10
-rw-r--r--src/libstd/keyword_docs.rs473
-rw-r--r--src/libstd/lib.rs18
-rw-r--r--src/libstd/net/addr.rs148
-rw-r--r--src/libstd/net/ip.rs183
-rw-r--r--src/libstd/net/parser.rs482
-rw-r--r--src/libstd/net/tcp.rs27
-rw-r--r--src/libstd/num.rs37
-rw-r--r--src/libstd/os/illumos/fs.rs2
-rw-r--r--src/libstd/os/linux/raw.rs2
-rw-r--r--src/libstd/panicking.rs138
-rw-r--r--src/libstd/path.rs39
-rw-r--r--src/libstd/prelude/mod.rs16
-rw-r--r--src/libstd/prelude/v1.rs1
-rw-r--r--src/libstd/process.rs22
-rw-r--r--src/libstd/rt.rs2
-rw-r--r--src/libstd/sync/condvar.rs1
-rw-r--r--src/libstd/sync/mpsc/mod.rs3
-rw-r--r--src/libstd/sync/mpsc/shared.rs8
-rw-r--r--src/libstd/sync/mpsc/stream.rs2
-rw-r--r--src/libstd/sync/mpsc/sync.rs16
-rw-r--r--src/libstd/sync/mutex.rs55
-rw-r--r--src/libstd/sync/once.rs4
-rw-r--r--src/libstd/sys/cloudabi/condvar.rs2
-rw-r--r--src/libstd/sys/cloudabi/mod.rs2
-rw-r--r--src/libstd/sys/cloudabi/shims/fs.rs8
-rw-r--r--src/libstd/sys/cloudabi/shims/net.rs8
-rw-r--r--src/libstd/sys/cloudabi/shims/pipe.rs8
-rw-r--r--src/libstd/sys/hermit/condvar.rs6
-rw-r--r--src/libstd/sys/hermit/fs.rs10
-rw-r--r--src/libstd/sys/hermit/mod.rs8
-rw-r--r--src/libstd/sys/hermit/net.rs135
-rw-r--r--src/libstd/sys/hermit/pipe.rs8
-rw-r--r--src/libstd/sys/hermit/stdio.rs44
-rw-r--r--src/libstd/sys/hermit/thread.rs13
-rw-r--r--src/libstd/sys/sgx/abi/entry.S54
-rw-r--r--src/libstd/sys/sgx/abi/mod.rs1
-rw-r--r--src/libstd/sys/sgx/fd.rs10
-rw-r--r--src/libstd/sys/sgx/fs.rs8
-rw-r--r--src/libstd/sys/sgx/mod.rs4
-rw-r--r--src/libstd/sys/sgx/net.rs10
-rw-r--r--src/libstd/sys/sgx/pipe.rs8
-rw-r--r--src/libstd/sys/unix/android.rs2
-rw-r--r--src/libstd/sys/unix/args.rs21
-rw-r--r--src/libstd/sys/unix/condvar.rs8
-rw-r--r--src/libstd/sys/unix/ext/fs.rs8
-rw-r--r--src/libstd/sys/unix/ext/net.rs26
-rw-r--r--src/libstd/sys/unix/ext/process.rs2
-rw-r--r--src/libstd/sys/unix/ext/raw.rs5
-rw-r--r--src/libstd/sys/unix/fd.rs20
-rw-r--r--src/libstd/sys/unix/fs.rs16
-rw-r--r--src/libstd/sys/unix/l4re.rs16
-rw-r--r--src/libstd/sys/unix/mod.rs4
-rw-r--r--src/libstd/sys/unix/mutex.rs10
-rw-r--r--src/libstd/sys/unix/net.rs16
-rw-r--r--src/libstd/sys/unix/pipe.rs10
-rw-r--r--src/libstd/sys/unix/process/process_common.rs7
-rw-r--r--src/libstd/sys/unix/rwlock.rs48
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs13
-rw-r--r--src/libstd/sys/unix/stdio.rs15
-rw-r--r--src/libstd/sys/unix/thread.rs29
-rw-r--r--src/libstd/sys/vxworks/args.rs1
-rw-r--r--src/libstd/sys/vxworks/condvar.rs8
-rw-r--r--src/libstd/sys/vxworks/ext/fs.rs3
-rw-r--r--src/libstd/sys/vxworks/ext/process.rs2
-rw-r--r--src/libstd/sys/vxworks/fd.rs16
-rw-r--r--src/libstd/sys/vxworks/fs.rs10
-rw-r--r--src/libstd/sys/vxworks/mod.rs4
-rw-r--r--src/libstd/sys/vxworks/net.rs16
-rw-r--r--src/libstd/sys/vxworks/pipe.rs11
-rw-r--r--src/libstd/sys/vxworks/process/process_common.rs6
-rw-r--r--src/libstd/sys/vxworks/rand.rs1
-rw-r--r--src/libstd/sys/vxworks/rwlock.rs1
-rw-r--r--src/libstd/sys/vxworks/thread.rs2
-rw-r--r--src/libstd/sys/vxworks/time.rs2
-rw-r--r--src/libstd/sys/wasi/alloc.rs1
-rw-r--r--src/libstd/sys/wasi/ext/fs.rs141
-rw-r--r--src/libstd/sys/wasi/fs.rs10
-rw-r--r--src/libstd/sys/wasi/mod.rs6
-rw-r--r--src/libstd/sys/wasi/net.rs8
-rw-r--r--src/libstd/sys/wasi/pipe.rs8
-rw-r--r--src/libstd/sys/wasi/stdio.rs63
-rw-r--r--src/libstd/sys/wasi/thread.rs2
-rw-r--r--src/libstd/sys/wasm/condvar_atomics.rs4
-rw-r--r--src/libstd/sys/wasm/fs.rs8
-rw-r--r--src/libstd/sys/wasm/mod.rs4
-rw-r--r--src/libstd/sys/wasm/net.rs8
-rw-r--r--src/libstd/sys/wasm/pipe.rs8
-rw-r--r--src/libstd/sys/wasm/thread.rs2
-rw-r--r--src/libstd/sys/windows/c.rs20
-rw-r--r--src/libstd/sys/windows/ext/fs.rs2
-rw-r--r--src/libstd/sys/windows/fs.rs10
-rw-r--r--src/libstd/sys/windows/handle.rs20
-rw-r--r--src/libstd/sys/windows/io.rs4
-rw-r--r--src/libstd/sys/windows/mod.rs24
-rw-r--r--src/libstd/sys/windows/net.rs18
-rw-r--r--src/libstd/sys/windows/pipe.rs10
-rw-r--r--src/libstd/sys_common/net.rs31
-rw-r--r--src/libstd/sys_common/util.rs4
-rw-r--r--src/libstd/sys_common/wtf8.rs17
-rw-r--r--src/libstd/tests/run-time-detect.rs1
-rw-r--r--src/libstd/thread/local.rs2
-rw-r--r--src/libstd/thread/mod.rs9
-rw-r--r--src/libstd/time.rs25
124 files changed, 3188 insertions, 1028 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index ceb39c01c67..490afb5a043 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -20,7 +20,7 @@ panic_unwind = { path = "../libpanic_unwind", optional = true }
 panic_abort = { path = "../libpanic_abort" }
 core = { path = "../libcore" }
 libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.16" }
+compiler_builtins = { version = "0.1.32" }
 profiler_builtins = { path = "../libprofiler_builtins", optional = true }
 unwind = { path = "../libunwind" }
 hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] }
@@ -41,7 +41,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
 fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
-hermit-abi = { version = "0.1.10", features = ['rustc-dep-of-std'] }
+hermit-abi = { version = "0.1.14", features = ['rustc-dep-of-std'] }
 
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
@@ -74,3 +74,8 @@ std_detect_dlsym_getauxval = []
 threads = 125
 # Maximum heap size
 heap_size = 0x8000000
+
+[[bench]]
+name = "stdbenches"
+path = "benches/lib.rs"
+test = true
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index 9840cfa4304..38d223d84e9 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -279,7 +279,7 @@ pub fn rust_oom(layout: Layout) -> ! {
     let hook: fn(Layout) =
         if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
     hook(layout);
-    unsafe { crate::sys::abort_internal() }
+    crate::process::abort()
 }
 
 #[cfg(not(test))]
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
index 41bdfea53e5..5cd2a25b117 100644
--- a/src/libstd/ascii.rs
+++ b/src/libstd/ascii.rs
@@ -149,23 +149,35 @@ pub trait AsciiExt {
 macro_rules! delegating_ascii_methods {
     () => {
         #[inline]
-        fn is_ascii(&self) -> bool { self.is_ascii() }
+        fn is_ascii(&self) -> bool {
+            self.is_ascii()
+        }
 
         #[inline]
-        fn to_ascii_uppercase(&self) -> Self::Owned { self.to_ascii_uppercase() }
+        fn to_ascii_uppercase(&self) -> Self::Owned {
+            self.to_ascii_uppercase()
+        }
 
         #[inline]
-        fn to_ascii_lowercase(&self) -> Self::Owned { self.to_ascii_lowercase() }
+        fn to_ascii_lowercase(&self) -> Self::Owned {
+            self.to_ascii_lowercase()
+        }
 
         #[inline]
-        fn eq_ignore_ascii_case(&self, o: &Self) -> bool { self.eq_ignore_ascii_case(o) }
+        fn eq_ignore_ascii_case(&self, o: &Self) -> bool {
+            self.eq_ignore_ascii_case(o)
+        }
 
         #[inline]
-        fn make_ascii_uppercase(&mut self) { self.make_ascii_uppercase(); }
+        fn make_ascii_uppercase(&mut self) {
+            self.make_ascii_uppercase();
+        }
 
         #[inline]
-        fn make_ascii_lowercase(&mut self) { self.make_ascii_lowercase(); }
-    }
+        fn make_ascii_lowercase(&mut self) {
+            self.make_ascii_lowercase();
+        }
+    };
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 706b388f783..5ba5eff4407 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -198,6 +198,7 @@ use crate::sys;
 /// ```
 
 #[derive(Clone)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct HashMap<K, V, S = RandomState> {
     base: base::HashMap<K, V, S>,
@@ -250,6 +251,9 @@ impl<K, V, S> HashMap<K, V, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -260,6 +264,8 @@ impl<K, V, S> HashMap<K, V, S> {
     /// let mut map = HashMap::with_hasher(s);
     /// map.insert(1, 2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
@@ -277,6 +283,9 @@ impl<K, V, S> HashMap<K, V, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -287,6 +296,8 @@ impl<K, V, S> HashMap<K, V, S> {
     /// let mut map = HashMap::with_capacity_and_hasher(10, s);
     /// map.insert(1, 2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
@@ -2415,6 +2426,24 @@ where
     fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
         self.base.extend(iter)
     }
+
+    #[inline]
+    fn extend_one(&mut self, (k, v): (K, V)) {
+        self.base.insert(k, v);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        // self.base.extend_reserve(additional);
+        // FIXME: hashbrown should implement this method.
+        // But until then, use the same reservation logic:
+
+        // Reserve the entire hint lower bound if the map is empty.
+        // Otherwise reserve half the hint (rounded up), so the map
+        // will only resize twice in the worst case.
+        let reserve = if self.is_empty() { additional } else { (additional + 1) / 2 };
+        self.base.reserve(reserve);
+    }
 }
 
 #[stable(feature = "hash_extend_copy", since = "1.4.0")]
@@ -2428,6 +2457,16 @@ where
     fn extend<T: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: T) {
         self.base.extend(iter)
     }
+
+    #[inline]
+    fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) {
+        self.base.insert(k, v);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        Extend::<(K, V)>::extend_reserve(self, additional)
+    }
 }
 
 /// `RandomState` is the default state for [`HashMap`] types.
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index 1ad99f03703..cb2f829803b 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -105,6 +105,7 @@ use super::map::{self, HashMap, Keys, RandomState};
 /// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html
 /// [`RefCell`]: ../../std/cell/struct.RefCell.html
 #[derive(Clone)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct HashSet<T, S = RandomState> {
     map: HashMap<T, (), S>,
@@ -272,6 +273,9 @@ impl<T, S> HashSet<T, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -282,6 +286,8 @@ impl<T, S> HashSet<T, S> {
     /// let mut set = HashSet::with_hasher(s);
     /// set.insert(2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hasher: S) -> HashSet<T, S> {
@@ -299,6 +305,9 @@ impl<T, S> HashSet<T, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -309,6 +318,8 @@ impl<T, S> HashSet<T, S> {
     /// let mut set = HashSet::with_capacity_and_hasher(10, s);
     /// set.insert(1);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
@@ -959,6 +970,16 @@ where
     fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
         self.map.extend(iter.into_iter().map(|k| (k, ())));
     }
+
+    #[inline]
+    fn extend_one(&mut self, item: T) {
+        self.map.insert(item, ());
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        self.map.extend_reserve(additional);
+    }
 }
 
 #[stable(feature = "hash_extend_copy", since = "1.4.0")]
@@ -971,6 +992,16 @@ where
     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
         self.extend(iter.into_iter().cloned());
     }
+
+    #[inline]
+    fn extend_one(&mut self, &item: &'a T) {
+        self.map.insert(item, ());
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        Extend::<T>::extend_reserve(self, additional)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index 6aad082a97f..97c20ca9459 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -567,7 +567,7 @@ impl Error for JoinPathsError {
 #[rustc_deprecated(
     since = "1.29.0",
     reason = "This function's behavior is unexpected and probably not what you want. \
-              Consider using the home_dir function from https://crates.io/crates/dirs instead."
+              Consider using a crate from crates.io instead."
 )]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn home_dir() -> Option<PathBuf> {
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 24b57f12e8d..3b4cb859dd4 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -14,6 +14,7 @@
 // reconsider what crate these items belong in.
 
 use core::array;
+use core::convert::Infallible;
 
 use crate::alloc::{AllocErr, LayoutErr};
 use crate::any::TypeId;
@@ -474,7 +475,7 @@ impl Error for string::FromUtf16Error {
 }
 
 #[stable(feature = "str_parse_error2", since = "1.8.0")]
-impl Error for string::ParseError {
+impl Error for Infallible {
     fn description(&self) -> &str {
         match *self {}
     }
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 65273275a40..b392d6e7226 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -171,7 +171,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn signum(self) -> f32 {
-        if self.is_nan() { NAN } else { 1.0_f32.copysign(self) }
+        if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) }
     }
 
     /// Returns a number composed of the magnitude of `self` and the sign of
@@ -832,11 +832,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn asinh(self) -> f32 {
-        if self == NEG_INFINITY {
-            NEG_INFINITY
-        } else {
-            (self + ((self * self) + 1.0).sqrt()).ln().copysign(self)
-        }
+        (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self)
     }
 
     /// Inverse hyperbolic cosine function.
@@ -855,7 +851,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn acosh(self) -> f32 {
-        if self < 1.0 { crate::f32::NAN } else { (self + ((self * self) - 1.0).sqrt()).ln() }
+        if self < 1.0 { Self::NAN } else { (self + ((self * self) - 1.0).sqrt()).ln() }
     }
 
     /// Inverse hyperbolic tangent function.
@@ -882,7 +878,7 @@ impl f32 {
     /// Returns `max` if `self` is greater than `max`, and `min` if `self` is
     /// less than `min`. Otherwise this returns `self`.
     ///
-    /// Not that this function returns NaN if the initial value was NaN as
+    /// Note that this function returns NaN if the initial value was NaN as
     /// well.
     ///
     /// # Panics
@@ -916,8 +912,7 @@ impl f32 {
 
 #[cfg(test)]
 mod tests {
-    use crate::f32;
-    use crate::f32::*;
+    use crate::f32::consts;
     use crate::num::FpCategory as Fp;
     use crate::num::*;
 
@@ -928,14 +923,14 @@ mod tests {
 
     #[test]
     fn test_min_nan() {
-        assert_eq!(NAN.min(2.0), 2.0);
-        assert_eq!(2.0f32.min(NAN), 2.0);
+        assert_eq!(f32::NAN.min(2.0), 2.0);
+        assert_eq!(2.0f32.min(f32::NAN), 2.0);
     }
 
     #[test]
     fn test_max_nan() {
-        assert_eq!(NAN.max(2.0), 2.0);
-        assert_eq!(2.0f32.max(NAN), 2.0);
+        assert_eq!(f32::NAN.max(2.0), 2.0);
+        assert_eq!(2.0f32.max(f32::NAN), 2.0);
     }
 
     #[test]
@@ -1158,52 +1153,52 @@ mod tests {
 
     #[test]
     fn test_abs() {
-        assert_eq!(INFINITY.abs(), INFINITY);
+        assert_eq!(f32::INFINITY.abs(), f32::INFINITY);
         assert_eq!(1f32.abs(), 1f32);
         assert_eq!(0f32.abs(), 0f32);
         assert_eq!((-0f32).abs(), 0f32);
         assert_eq!((-1f32).abs(), 1f32);
-        assert_eq!(NEG_INFINITY.abs(), INFINITY);
-        assert_eq!((1f32 / NEG_INFINITY).abs(), 0f32);
-        assert!(NAN.abs().is_nan());
+        assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY);
+        assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32);
+        assert!(f32::NAN.abs().is_nan());
     }
 
     #[test]
     fn test_signum() {
-        assert_eq!(INFINITY.signum(), 1f32);
+        assert_eq!(f32::INFINITY.signum(), 1f32);
         assert_eq!(1f32.signum(), 1f32);
         assert_eq!(0f32.signum(), 1f32);
         assert_eq!((-0f32).signum(), -1f32);
         assert_eq!((-1f32).signum(), -1f32);
-        assert_eq!(NEG_INFINITY.signum(), -1f32);
-        assert_eq!((1f32 / NEG_INFINITY).signum(), -1f32);
-        assert!(NAN.signum().is_nan());
+        assert_eq!(f32::NEG_INFINITY.signum(), -1f32);
+        assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32);
+        assert!(f32::NAN.signum().is_nan());
     }
 
     #[test]
     fn test_is_sign_positive() {
-        assert!(INFINITY.is_sign_positive());
+        assert!(f32::INFINITY.is_sign_positive());
         assert!(1f32.is_sign_positive());
         assert!(0f32.is_sign_positive());
         assert!(!(-0f32).is_sign_positive());
         assert!(!(-1f32).is_sign_positive());
-        assert!(!NEG_INFINITY.is_sign_positive());
-        assert!(!(1f32 / NEG_INFINITY).is_sign_positive());
-        assert!(NAN.is_sign_positive());
-        assert!(!(-NAN).is_sign_positive());
+        assert!(!f32::NEG_INFINITY.is_sign_positive());
+        assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive());
+        assert!(f32::NAN.is_sign_positive());
+        assert!(!(-f32::NAN).is_sign_positive());
     }
 
     #[test]
     fn test_is_sign_negative() {
-        assert!(!INFINITY.is_sign_negative());
+        assert!(!f32::INFINITY.is_sign_negative());
         assert!(!1f32.is_sign_negative());
         assert!(!0f32.is_sign_negative());
         assert!((-0f32).is_sign_negative());
         assert!((-1f32).is_sign_negative());
-        assert!(NEG_INFINITY.is_sign_negative());
-        assert!((1f32 / NEG_INFINITY).is_sign_negative());
-        assert!(!NAN.is_sign_negative());
-        assert!((-NAN).is_sign_negative());
+        assert!(f32::NEG_INFINITY.is_sign_negative());
+        assert!((1f32 / f32::NEG_INFINITY).is_sign_negative());
+        assert!(!f32::NAN.is_sign_negative());
+        assert!((-f32::NAN).is_sign_negative());
     }
 
     #[test]
@@ -1268,13 +1263,13 @@ mod tests {
 
     #[test]
     fn test_sqrt_domain() {
-        assert!(NAN.sqrt().is_nan());
-        assert!(NEG_INFINITY.sqrt().is_nan());
+        assert!(f32::NAN.sqrt().is_nan());
+        assert!(f32::NEG_INFINITY.sqrt().is_nan());
         assert!((-1.0f32).sqrt().is_nan());
         assert_eq!((-0.0f32).sqrt(), -0.0);
         assert_eq!(0.0f32.sqrt(), 0.0);
         assert_eq!(1.0f32.sqrt(), 1.0);
-        assert_eq!(INFINITY.sqrt(), INFINITY);
+        assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY);
     }
 
     #[test]
@@ -1414,6 +1409,8 @@ mod tests {
         assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271
         assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
         assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
+        // regression test for the catastrophic cancellation fixed in 72486
+        assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
     }
 
     #[test]
@@ -1523,12 +1520,155 @@ mod tests {
     #[test]
     #[should_panic]
     fn test_clamp_min_is_nan() {
-        let _ = 1.0f32.clamp(NAN, 1.0);
+        let _ = 1.0f32.clamp(f32::NAN, 1.0);
     }
 
     #[test]
     #[should_panic]
     fn test_clamp_max_is_nan() {
-        let _ = 1.0f32.clamp(3.0, NAN);
+        let _ = 1.0f32.clamp(3.0, f32::NAN);
+    }
+
+    #[test]
+    fn test_total_cmp() {
+        use core::cmp::Ordering;
+
+        fn quiet_bit_mask() -> u32 {
+            1 << (f32::MANTISSA_DIGITS - 2)
+        }
+
+        fn min_subnorm() -> f32 {
+            f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0)
+        }
+
+        fn max_subnorm() -> f32 {
+            f32::MIN_POSITIVE - min_subnorm()
+        }
+
+        fn q_nan() -> f32 {
+            f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask())
+        }
+
+        fn s_nan() -> f32 {
+            f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42)
+        }
+
+        assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
+        assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5));
+        assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0));
+        assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5));
+        assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5));
+        assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0));
+        assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0));
+        assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5));
+        assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0));
+        assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5));
+        assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5));
+        assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
+        assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
+
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5));
+        assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0));
+        assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5));
+        assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5));
+        assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan()));
+        assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
+
+        assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
+        assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5));
+        assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5));
+        assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0));
+        assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5));
+        assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0));
+        assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
+        assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5));
+        assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0));
+        assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5));
+        assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5));
+        assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
+
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
+
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
     }
 }
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index 5cf9cb73d4b..72268d2cc2f 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -171,7 +171,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn signum(self) -> f64 {
-        if self.is_nan() { NAN } else { 1.0_f64.copysign(self) }
+        if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) }
     }
 
     /// Returns a number composed of the magnitude of `self` and the sign of
@@ -834,11 +834,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn asinh(self) -> f64 {
-        if self == NEG_INFINITY {
-            NEG_INFINITY
-        } else {
-            (self + ((self * self) + 1.0).sqrt()).ln().copysign(self)
-        }
+        (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self)
     }
 
     /// Inverse hyperbolic cosine function.
@@ -857,7 +853,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn acosh(self) -> f64 {
-        if self < 1.0 { NAN } else { (self + ((self * self) - 1.0).sqrt()).ln() }
+        if self < 1.0 { Self::NAN } else { (self + ((self * self) - 1.0).sqrt()).ln() }
     }
 
     /// Inverse hyperbolic tangent function.
@@ -884,7 +880,7 @@ impl f64 {
     /// Returns `max` if `self` is greater than `max`, and `min` if `self` is
     /// less than `min`. Otherwise this returns `self`.
     ///
-    /// Not that this function returns NaN if the initial value was NaN as
+    /// Note that this function returns NaN if the initial value was NaN as
     /// well.
     ///
     /// # Panics
@@ -926,16 +922,16 @@ impl f64 {
                 if self > 0.0 {
                     log_fn(self)
                 } else if self == 0.0 {
-                    NEG_INFINITY // log(0) = -Inf
+                    Self::NEG_INFINITY // log(0) = -Inf
                 } else {
-                    NAN // log(-n) = NaN
+                    Self::NAN // log(-n) = NaN
                 }
             } else if self.is_nan() {
                 self // log(NaN) = NaN
             } else if self > 0.0 {
                 self // log(Inf) = Inf
             } else {
-                NAN // log(-Inf) = NaN
+                Self::NAN // log(-Inf) = NaN
             }
         }
     }
@@ -943,8 +939,7 @@ impl f64 {
 
 #[cfg(test)]
 mod tests {
-    use crate::f64;
-    use crate::f64::*;
+    use crate::f64::consts;
     use crate::num::FpCategory as Fp;
     use crate::num::*;
 
@@ -955,19 +950,19 @@ mod tests {
 
     #[test]
     fn test_min_nan() {
-        assert_eq!(NAN.min(2.0), 2.0);
-        assert_eq!(2.0f64.min(NAN), 2.0);
+        assert_eq!(f64::NAN.min(2.0), 2.0);
+        assert_eq!(2.0f64.min(f64::NAN), 2.0);
     }
 
     #[test]
     fn test_max_nan() {
-        assert_eq!(NAN.max(2.0), 2.0);
-        assert_eq!(2.0f64.max(NAN), 2.0);
+        assert_eq!(f64::NAN.max(2.0), 2.0);
+        assert_eq!(2.0f64.max(f64::NAN), 2.0);
     }
 
     #[test]
     fn test_nan() {
-        let nan: f64 = NAN;
+        let nan: f64 = f64::NAN;
         assert!(nan.is_nan());
         assert!(!nan.is_infinite());
         assert!(!nan.is_finite());
@@ -979,7 +974,7 @@ mod tests {
 
     #[test]
     fn test_infinity() {
-        let inf: f64 = INFINITY;
+        let inf: f64 = f64::INFINITY;
         assert!(inf.is_infinite());
         assert!(!inf.is_finite());
         assert!(inf.is_sign_positive());
@@ -991,7 +986,7 @@ mod tests {
 
     #[test]
     fn test_neg_infinity() {
-        let neg_inf: f64 = NEG_INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert!(neg_inf.is_infinite());
         assert!(!neg_inf.is_finite());
         assert!(!neg_inf.is_sign_positive());
@@ -1043,9 +1038,9 @@ mod tests {
 
     #[test]
     fn test_is_nan() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert!(nan.is_nan());
         assert!(!0.0f64.is_nan());
         assert!(!5.3f64.is_nan());
@@ -1056,9 +1051,9 @@ mod tests {
 
     #[test]
     fn test_is_infinite() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert!(!nan.is_infinite());
         assert!(inf.is_infinite());
         assert!(neg_inf.is_infinite());
@@ -1069,9 +1064,9 @@ mod tests {
 
     #[test]
     fn test_is_finite() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert!(!nan.is_finite());
         assert!(!inf.is_finite());
         assert!(!neg_inf.is_finite());
@@ -1083,9 +1078,9 @@ mod tests {
     #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
     #[test]
     fn test_is_normal() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         let zero: f64 = 0.0f64;
         let neg_zero: f64 = -0.0;
         assert!(!nan.is_normal());
@@ -1101,9 +1096,9 @@ mod tests {
     #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
     #[test]
     fn test_classify() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         let zero: f64 = 0.0f64;
         let neg_zero: f64 = -0.0;
         assert_eq!(nan.classify(), Fp::Nan);
@@ -1187,59 +1182,59 @@ mod tests {
 
     #[test]
     fn test_abs() {
-        assert_eq!(INFINITY.abs(), INFINITY);
+        assert_eq!(f64::INFINITY.abs(), f64::INFINITY);
         assert_eq!(1f64.abs(), 1f64);
         assert_eq!(0f64.abs(), 0f64);
         assert_eq!((-0f64).abs(), 0f64);
         assert_eq!((-1f64).abs(), 1f64);
-        assert_eq!(NEG_INFINITY.abs(), INFINITY);
-        assert_eq!((1f64 / NEG_INFINITY).abs(), 0f64);
-        assert!(NAN.abs().is_nan());
+        assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY);
+        assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64);
+        assert!(f64::NAN.abs().is_nan());
     }
 
     #[test]
     fn test_signum() {
-        assert_eq!(INFINITY.signum(), 1f64);
+        assert_eq!(f64::INFINITY.signum(), 1f64);
         assert_eq!(1f64.signum(), 1f64);
         assert_eq!(0f64.signum(), 1f64);
         assert_eq!((-0f64).signum(), -1f64);
         assert_eq!((-1f64).signum(), -1f64);
-        assert_eq!(NEG_INFINITY.signum(), -1f64);
-        assert_eq!((1f64 / NEG_INFINITY).signum(), -1f64);
-        assert!(NAN.signum().is_nan());
+        assert_eq!(f64::NEG_INFINITY.signum(), -1f64);
+        assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64);
+        assert!(f64::NAN.signum().is_nan());
     }
 
     #[test]
     fn test_is_sign_positive() {
-        assert!(INFINITY.is_sign_positive());
+        assert!(f64::INFINITY.is_sign_positive());
         assert!(1f64.is_sign_positive());
         assert!(0f64.is_sign_positive());
         assert!(!(-0f64).is_sign_positive());
         assert!(!(-1f64).is_sign_positive());
-        assert!(!NEG_INFINITY.is_sign_positive());
-        assert!(!(1f64 / NEG_INFINITY).is_sign_positive());
-        assert!(NAN.is_sign_positive());
-        assert!(!(-NAN).is_sign_positive());
+        assert!(!f64::NEG_INFINITY.is_sign_positive());
+        assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive());
+        assert!(f64::NAN.is_sign_positive());
+        assert!(!(-f64::NAN).is_sign_positive());
     }
 
     #[test]
     fn test_is_sign_negative() {
-        assert!(!INFINITY.is_sign_negative());
+        assert!(!f64::INFINITY.is_sign_negative());
         assert!(!1f64.is_sign_negative());
         assert!(!0f64.is_sign_negative());
         assert!((-0f64).is_sign_negative());
         assert!((-1f64).is_sign_negative());
-        assert!(NEG_INFINITY.is_sign_negative());
-        assert!((1f64 / NEG_INFINITY).is_sign_negative());
-        assert!(!NAN.is_sign_negative());
-        assert!((-NAN).is_sign_negative());
+        assert!(f64::NEG_INFINITY.is_sign_negative());
+        assert!((1f64 / f64::NEG_INFINITY).is_sign_negative());
+        assert!(!f64::NAN.is_sign_negative());
+        assert!((-f64::NAN).is_sign_negative());
     }
 
     #[test]
     fn test_mul_add() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05);
         assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65);
         assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2);
@@ -1253,9 +1248,9 @@ mod tests {
 
     #[test]
     fn test_recip() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_eq!(1.0f64.recip(), 1.0);
         assert_eq!(2.0f64.recip(), 0.5);
         assert_eq!((-0.4f64).recip(), -2.5);
@@ -1267,9 +1262,9 @@ mod tests {
 
     #[test]
     fn test_powi() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_eq!(1.0f64.powi(1), 1.0);
         assert_approx_eq!((-3.1f64).powi(2), 9.61);
         assert_approx_eq!(5.9f64.powi(-2), 0.028727);
@@ -1281,9 +1276,9 @@ mod tests {
 
     #[test]
     fn test_powf() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_eq!(1.0f64.powf(1.0), 1.0);
         assert_approx_eq!(3.4f64.powf(4.5), 246.408183);
         assert_approx_eq!(2.7f64.powf(-3.2), 0.041652);
@@ -1297,13 +1292,13 @@ mod tests {
 
     #[test]
     fn test_sqrt_domain() {
-        assert!(NAN.sqrt().is_nan());
-        assert!(NEG_INFINITY.sqrt().is_nan());
+        assert!(f64::NAN.sqrt().is_nan());
+        assert!(f64::NEG_INFINITY.sqrt().is_nan());
         assert!((-1.0f64).sqrt().is_nan());
         assert_eq!((-0.0f64).sqrt(), -0.0);
         assert_eq!(0.0f64.sqrt(), 0.0);
         assert_eq!(1.0f64.sqrt(), 1.0);
-        assert_eq!(INFINITY.sqrt(), INFINITY);
+        assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY);
     }
 
     #[test]
@@ -1312,9 +1307,9 @@ mod tests {
         assert_approx_eq!(2.718282, 1.0f64.exp());
         assert_approx_eq!(148.413159, 5.0f64.exp());
 
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
+        let nan: f64 = f64::NAN;
         assert_eq!(inf, inf.exp());
         assert_eq!(0.0, neg_inf.exp());
         assert!(nan.exp().is_nan());
@@ -1325,9 +1320,9 @@ mod tests {
         assert_eq!(32.0, 5.0f64.exp2());
         assert_eq!(1.0, 0.0f64.exp2());
 
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
+        let nan: f64 = f64::NAN;
         assert_eq!(inf, inf.exp2());
         assert_eq!(0.0, neg_inf.exp2());
         assert!(nan.exp2().is_nan());
@@ -1335,9 +1330,9 @@ mod tests {
 
     #[test]
     fn test_ln() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_approx_eq!(1.0f64.exp().ln(), 1.0);
         assert!(nan.ln().is_nan());
         assert_eq!(inf.ln(), inf);
@@ -1350,9 +1345,9 @@ mod tests {
 
     #[test]
     fn test_log() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_eq!(10.0f64.log(10.0), 1.0);
         assert_approx_eq!(2.3f64.log(3.5), 0.664858);
         assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0);
@@ -1368,9 +1363,9 @@ mod tests {
 
     #[test]
     fn test_log2() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_approx_eq!(10.0f64.log2(), 3.321928);
         assert_approx_eq!(2.3f64.log2(), 1.201634);
         assert_approx_eq!(1.0f64.exp().log2(), 1.442695);
@@ -1384,9 +1379,9 @@ mod tests {
 
     #[test]
     fn test_log10() {
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_eq!(10.0f64.log10(), 1.0);
         assert_approx_eq!(2.3f64.log10(), 0.361728);
         assert_approx_eq!(1.0f64.exp().log10(), 0.434294);
@@ -1402,9 +1397,9 @@ mod tests {
     #[test]
     fn test_to_degrees() {
         let pi: f64 = consts::PI;
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_eq!(0.0f64.to_degrees(), 0.0);
         assert_approx_eq!((-5.8f64).to_degrees(), -332.315521);
         assert_eq!(pi.to_degrees(), 180.0);
@@ -1416,9 +1411,9 @@ mod tests {
     #[test]
     fn test_to_radians() {
         let pi: f64 = consts::PI;
-        let nan: f64 = NAN;
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
+        let nan: f64 = f64::NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
         assert_eq!(0.0f64.to_radians(), 0.0);
         assert_approx_eq!(154.6f64.to_radians(), 2.698279);
         assert_approx_eq!((-332.31f64).to_radians(), -5.799903);
@@ -1433,9 +1428,9 @@ mod tests {
         assert_eq!(0.0f64.asinh(), 0.0f64);
         assert_eq!((-0.0f64).asinh(), -0.0f64);
 
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
+        let nan: f64 = f64::NAN;
         assert_eq!(inf.asinh(), inf);
         assert_eq!(neg_inf.asinh(), neg_inf);
         assert!(nan.asinh().is_nan());
@@ -1443,6 +1438,8 @@ mod tests {
         // issue 63271
         assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
         assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
+        // regression test for the catastrophic cancellation fixed in 72486
+        assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083);
     }
 
     #[test]
@@ -1450,9 +1447,9 @@ mod tests {
         assert_eq!(1.0f64.acosh(), 0.0f64);
         assert!(0.999f64.acosh().is_nan());
 
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
+        let nan: f64 = f64::NAN;
         assert_eq!(inf.acosh(), inf);
         assert!(neg_inf.acosh().is_nan());
         assert!(nan.acosh().is_nan());
@@ -1465,9 +1462,9 @@ mod tests {
         assert_eq!(0.0f64.atanh(), 0.0f64);
         assert_eq!((-0.0f64).atanh(), -0.0f64);
 
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
+        let inf: f64 = f64::INFINITY;
+        let neg_inf: f64 = f64::NEG_INFINITY;
+        let nan: f64 = f64::NAN;
         assert_eq!(1.0f64.atanh(), inf);
         assert_eq!((-1.0f64).atanh(), neg_inf);
         assert!(2f64.atanh().atanh().is_nan());
@@ -1546,12 +1543,155 @@ mod tests {
     #[test]
     #[should_panic]
     fn test_clamp_min_is_nan() {
-        let _ = 1.0f64.clamp(NAN, 1.0);
+        let _ = 1.0f64.clamp(f64::NAN, 1.0);
     }
 
     #[test]
     #[should_panic]
     fn test_clamp_max_is_nan() {
-        let _ = 1.0f64.clamp(3.0, NAN);
+        let _ = 1.0f64.clamp(3.0, f64::NAN);
+    }
+
+    #[test]
+    fn test_total_cmp() {
+        use core::cmp::Ordering;
+
+        fn quiet_bit_mask() -> u64 {
+            1 << (f64::MANTISSA_DIGITS - 2)
+        }
+
+        fn min_subnorm() -> f64 {
+            f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0)
+        }
+
+        fn max_subnorm() -> f64 {
+            f64::MIN_POSITIVE - min_subnorm()
+        }
+
+        fn q_nan() -> f64 {
+            f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask())
+        }
+
+        fn s_nan() -> f64 {
+            f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42)
+        }
+
+        assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
+        assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5));
+        assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0));
+        assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5));
+        assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5));
+        assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0));
+        assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0));
+        assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5));
+        assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0));
+        assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5));
+        assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5));
+        assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
+        assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));
+
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5));
+        assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0));
+        assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5));
+        assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5));
+        assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan()));
+        assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));
+
+        assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
+        assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5));
+        assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5));
+        assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0));
+        assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5));
+        assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0));
+        assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
+        assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5));
+        assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0));
+        assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5));
+        assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5));
+        assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));
+
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));
+
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
+        assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
     }
 }
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 0a4802fb2c8..dca1fdde482 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -234,15 +234,14 @@ pub struct NulError(usize, Vec<u8>);
 
 /// An error indicating that a nul byte was not in the expected position.
 ///
-/// The slice used to create a [`CStr`] must have one and only one nul
-/// byte at the end of the slice.
+/// The slice used to create a [`CStr`] must have one and only one nul byte,
+/// positioned at the end.
 ///
-/// This error is created by the
-/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on
-/// [`CStr`]. See its documentation for more.
+/// This error is created by the [`from_bytes_with_nul`] method on [`CStr`].
+/// See its documentation for more.
 ///
 /// [`CStr`]: struct.CStr.html
-/// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
+/// [`from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
 ///
 /// # Examples
 ///
@@ -257,6 +256,32 @@ pub struct FromBytesWithNulError {
     kind: FromBytesWithNulErrorKind,
 }
 
+/// An error indicating that a nul byte was not in the expected position.
+///
+/// The vector used to create a [`CString`] must have one and only one nul byte,
+/// positioned at the end.
+///
+/// This error is created by the [`from_vec_with_nul`] method on [`CString`].
+/// See its documentation for more.
+///
+/// [`CString`]: struct.CString.html
+/// [`from_vec_with_nul`]: struct.CString.html#method.from_vec_with_nul
+///
+/// # Examples
+///
+/// ```
+/// #![feature(cstring_from_vec_with_nul)]
+/// use std::ffi::{CString, FromVecWithNulError};
+///
+/// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err();
+/// ```
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+pub struct FromVecWithNulError {
+    error_kind: FromBytesWithNulErrorKind,
+    bytes: Vec<u8>,
+}
+
 #[derive(Clone, PartialEq, Eq, Debug)]
 enum FromBytesWithNulErrorKind {
     InteriorNul(usize),
@@ -272,6 +297,59 @@ impl FromBytesWithNulError {
     }
 }
 
+#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+impl FromVecWithNulError {
+    /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`].
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(cstring_from_vec_with_nul)]
+    /// use std::ffi::CString;
+    ///
+    /// // Some invalid bytes in a vector
+    /// let bytes = b"f\0oo".to_vec();
+    ///
+    /// let value = CString::from_vec_with_nul(bytes.clone());
+    ///
+    /// assert_eq!(&bytes[..], value.unwrap_err().as_bytes());
+    /// ```
+    ///
+    /// [`CString`]: struct.CString.html
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.bytes[..]
+    }
+
+    /// Returns the bytes that were attempted to convert to a [`CString`].
+    ///
+    /// This method is carefully constructed to avoid allocation. It will
+    /// consume the error, moving out the bytes, so that a copy of the bytes
+    /// does not need to be made.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(cstring_from_vec_with_nul)]
+    /// use std::ffi::CString;
+    ///
+    /// // Some invalid bytes in a vector
+    /// let bytes = b"f\0oo".to_vec();
+    ///
+    /// let value = CString::from_vec_with_nul(bytes.clone());
+    ///
+    /// assert_eq!(bytes, value.unwrap_err().into_bytes());
+    /// ```
+    ///
+    /// [`CString`]: struct.CString.html
+    pub fn into_bytes(self) -> Vec<u8> {
+        self.bytes
+    }
+}
+
 /// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
 ///
 /// `CString` is just a wrapper over a buffer of bytes with a nul
@@ -395,6 +473,12 @@ impl CString {
     /// ownership of a string that was allocated by foreign code) is likely to lead
     /// to undefined behavior or allocator corruption.
     ///
+    /// It should be noted that the length isn't just "recomputed," but that
+    /// the recomputed length must match the original length from the
+    /// [`into_raw`] call. This means the [`into_raw`]/`from_raw` methods
+    /// should not be used when passing the string to C functions that can
+    /// modify the string's length.
+    ///
     /// > **Note:** If you need to borrow a string that was allocated by
     /// > foreign code, use [`CStr`]. If you need to take ownership of
     /// > a string that was allocated by foreign code, you will need to
@@ -440,6 +524,11 @@ impl CString {
     ///
     /// Failure to call [`from_raw`] will lead to a memory leak.
     ///
+    /// The C side must **not** modify the length of the string (by writing a
+    /// `NULL` somewhere inside the string or removing the final one) before
+    /// it makes it back into Rust using [`from_raw`]. See the safety section
+    /// in [`from_raw`].
+    ///
     /// [`from_raw`]: #method.from_raw
     ///
     /// # Examples
@@ -632,6 +721,86 @@ impl CString {
         let this = mem::ManuallyDrop::new(self);
         unsafe { ptr::read(&this.inner) }
     }
+
+    /// Converts a `Vec` of `u8` to a `CString` without checking the invariants
+    /// on the given `Vec`.
+    ///
+    /// # Safety
+    ///
+    /// The given `Vec` **must** have one nul byte as its last element.
+    /// This means it cannot be empty nor have any other nul byte anywhere else.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(cstring_from_vec_with_nul)]
+    /// use std::ffi::CString;
+    /// assert_eq!(
+    ///     unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) },
+    ///     unsafe { CString::from_vec_unchecked(b"abc".to_vec()) }
+    /// );
+    /// ```
+    #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+    pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
+        Self { inner: v.into_boxed_slice() }
+    }
+
+    /// Attempts to converts a `Vec` of `u8` to a `CString`.
+    ///
+    /// Runtime checks are present to ensure there is only one nul byte in the
+    /// `Vec`, its last element.
+    ///
+    /// # Errors
+    ///
+    /// If a nul byte is present and not the last element or no nul bytes
+    /// is present, an error will be returned.
+    ///
+    /// # Examples
+    ///
+    /// A successful conversion will produce the same result as [`new`] when
+    /// called without the ending nul byte.
+    ///
+    /// ```
+    /// #![feature(cstring_from_vec_with_nul)]
+    /// use std::ffi::CString;
+    /// assert_eq!(
+    ///     CString::from_vec_with_nul(b"abc\0".to_vec())
+    ///         .expect("CString::from_vec_with_nul failed"),
+    ///     CString::new(b"abc".to_vec()).expect("CString::new failed")
+    /// );
+    /// ```
+    ///
+    /// A incorrectly formatted vector will produce an error.
+    ///
+    /// ```
+    /// #![feature(cstring_from_vec_with_nul)]
+    /// use std::ffi::{CString, FromVecWithNulError};
+    /// // Interior nul byte
+    /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
+    /// // No nul byte
+    /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
+    /// ```
+    ///
+    /// [`new`]: #method.new
+    #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+    pub fn from_vec_with_nul(v: Vec<u8>) -> Result<Self, FromVecWithNulError> {
+        let nul_pos = memchr::memchr(0, &v);
+        match nul_pos {
+            Some(nul_pos) if nul_pos + 1 == v.len() => {
+                // SAFETY: We know there is only one nul byte, at the end
+                // of the vec.
+                Ok(unsafe { Self::from_vec_with_nul_unchecked(v) })
+            }
+            Some(nul_pos) => Err(FromVecWithNulError {
+                error_kind: FromBytesWithNulErrorKind::InteriorNul(nul_pos),
+                bytes: v,
+            }),
+            None => Err(FromVecWithNulError {
+                error_kind: FromBytesWithNulErrorKind::NotNulTerminated,
+                bytes: v,
+            }),
+        }
+    }
 }
 
 // Turns this `CString` into an empty string to prevent
@@ -730,6 +899,17 @@ impl From<&CStr> for Box<CStr> {
     }
 }
 
+#[stable(feature = "box_from_cow", since = "1.45.0")]
+impl From<Cow<'_, CStr>> for Box<CStr> {
+    #[inline]
+    fn from(cow: Cow<'_, CStr>) -> Box<CStr> {
+        match cow {
+            Cow::Borrowed(s) => Box::from(s),
+            Cow::Owned(s) => Box::from(s),
+        }
+    }
+}
+
 #[stable(feature = "c_string_from_box", since = "1.18.0")]
 impl From<Box<CStr>> for CString {
     /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
@@ -954,6 +1134,23 @@ impl fmt::Display for FromBytesWithNulError {
     }
 }
 
+#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+impl Error for FromVecWithNulError {}
+
+#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+impl fmt::Display for FromVecWithNulError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.error_kind {
+            FromBytesWithNulErrorKind::InteriorNul(pos) => {
+                write!(f, "data provided contains an interior nul byte at pos {}", pos)
+            }
+            FromBytesWithNulErrorKind::NotNulTerminated => {
+                write!(f, "data provided is not nul terminated")
+            }
+        }
+    }
+}
+
 impl IntoStringError {
     /// Consumes this error, returning original [`CString`] which generated the
     /// error.
diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs
index 5aca7b7476a..f442d7fde1a 100644
--- a/src/libstd/ffi/mod.rs
+++ b/src/libstd/ffi/mod.rs
@@ -157,6 +157,8 @@
 
 #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
 pub use self::c_str::FromBytesWithNulError;
+#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+pub use self::c_str::FromVecWithNulError;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::c_str::{CStr, CString, IntoStringError, NulError};
 
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 4fde3316973..d1eaf3c583f 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -4,6 +4,7 @@ use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::ops;
 use crate::rc::Rc;
+use crate::str::FromStr;
 use crate::sync::Arc;
 
 use crate::sys::os_str::{Buf, Slice};
@@ -849,6 +850,17 @@ impl From<&OsStr> for Box<OsStr> {
     }
 }
 
+#[stable(feature = "box_from_cow", since = "1.45.0")]
+impl From<Cow<'_, OsStr>> for Box<OsStr> {
+    #[inline]
+    fn from(cow: Cow<'_, OsStr>) -> Box<OsStr> {
+        match cow {
+            Cow::Borrowed(s) => Box::from(s),
+            Cow::Owned(s) => Box::from(s),
+        }
+    }
+}
+
 #[stable(feature = "os_string_from_box", since = "1.18.0")]
 impl From<Box<OsStr>> for OsString {
     /// Converts a [`Box`]`<`[`OsStr`]`>` into a `OsString` without copying or
@@ -1174,6 +1186,15 @@ impl AsInner<Slice> for OsStr {
     }
 }
 
+#[stable(feature = "osstring_from_str", since = "1.45.0")]
+impl FromStr for OsString {
+    type Err = core::convert::Infallible;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(OsString::from(s))
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 119bdfcb0f4..4d031cb7a52 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -8,6 +8,7 @@
 //! extension traits of `std::os::$platform`.
 
 #![stable(feature = "rust1", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
 
 use crate::ffi::OsString;
 use crate::fmt;
@@ -660,8 +661,14 @@ impl Read for File {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+        // SAFETY: Read is guaranteed to work on uninitialized memory
+        unsafe { Initializer::nop() }
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -674,6 +681,11 @@ impl Write for File {
         self.inner.write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         self.inner.flush()
     }
@@ -695,8 +707,14 @@ impl Read for &File {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+        // SAFETY: Read is guaranteed to work on uninitialized memory
+        unsafe { Initializer::nop() }
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -709,6 +727,11 @@ impl Write for &File {
         self.inner.write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         self.inner.flush()
     }
@@ -1013,8 +1036,16 @@ impl Metadata {
     /// [`is_dir`], and will be false for symlink metadata
     /// obtained from [`symlink_metadata`].
     ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
     /// [`is_dir`]: struct.Metadata.html#method.is_dir
     /// [`symlink_metadata`]: fn.symlink_metadata.html
+    /// [`File::open`]: struct.File.html#method.open
+    /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
     ///
     /// # Examples
     ///
@@ -1287,8 +1318,16 @@ impl FileType {
     /// [`is_dir`] and [`is_symlink`]; only zero or one of these
     /// tests may pass.
     ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
     /// [`is_dir`]: struct.FileType.html#method.is_dir
     /// [`is_symlink`]: struct.FileType.html#method.is_symlink
+    /// [`File::open`]: struct.File.html#method.open
+    /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
     ///
     /// # Examples
     ///
@@ -1409,7 +1448,10 @@ impl DirEntry {
     /// Returns the metadata for the file that this entry points at.
     ///
     /// This function will not traverse symlinks if this entry points at a
-    /// symlink.
+    /// symlink. To traverse symlinks use [`fs::metadata`] or [`fs::File::metadata`].
+    ///
+    /// [`fs::metadata`]: fn.metadata.html
+    /// [`fs::File::metadata`]: struct.File.html#method.metadata
     ///
     /// # Platform-specific behavior
     ///
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index c0675eeba98..89dd9fb9b2c 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -1,111 +1,17 @@
 //! Asynchronous values.
 
-#[cfg(bootstrap)]
-use core::{
-    cell::Cell,
-    marker::Unpin,
-    ops::{Drop, Generator, GeneratorState},
-    pin::Pin,
-    ptr::NonNull,
-    task::{Context, Poll},
-};
-
 #[doc(inline)]
 #[stable(feature = "futures_api", since = "1.36.0")]
-pub use core::future::*;
-
-/// 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.....]>`).
-// This is `const` to avoid extra errors after we recover from `const async fn`
-#[cfg(bootstrap)]
-#[doc(hidden)]
-#[unstable(feature = "gen_future", issue = "50547")]
-pub const fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
-    GenFuture(x)
-}
-
-/// A wrapper around generators used to implement `Future` for `async`/`await` code.
-#[cfg(bootstrap)]
-#[doc(hidden)]
-#[unstable(feature = "gen_future", issue = "50547")]
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
-struct GenFuture<T: Generator<Yield = ()>>(T);
-
-// We rely on the fact that async/await futures are immovable in order to create
-// self-referential borrows in the underlying generator.
-#[cfg(bootstrap)]
-impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
-
-#[cfg(bootstrap)]
-#[doc(hidden)]
-#[unstable(feature = "gen_future", issue = "50547")]
-impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
-    type Output = T::Return;
-    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-        // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
-        let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
-        let _guard = unsafe { set_task_context(cx) };
-        match gen.resume(()) {
-            GeneratorState::Yielded(()) => Poll::Pending,
-            GeneratorState::Complete(x) => Poll::Ready(x),
-        }
-    }
-}
+pub use core::future::Future;
 
-#[cfg(bootstrap)]
-thread_local! {
-    static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
-}
-
-#[cfg(bootstrap)]
-struct SetOnDrop(Option<NonNull<Context<'static>>>);
-
-#[cfg(bootstrap)]
-impl Drop for SetOnDrop {
-    fn drop(&mut self) {
-        TLS_CX.with(|tls_cx| {
-            tls_cx.set(self.0.take());
-        });
-    }
-}
-
-// Safety: the returned guard must drop before `cx` is dropped and before
-// any previous guard is dropped.
-#[cfg(bootstrap)]
-unsafe fn set_task_context(cx: &mut Context<'_>) -> SetOnDrop {
-    // transmute the context's lifetime to 'static so we can store it.
-    let cx = core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx);
-    let old_cx = TLS_CX.with(|tls_cx| tls_cx.replace(Some(NonNull::from(cx))));
-    SetOnDrop(old_cx)
-}
-
-#[cfg(bootstrap)]
-#[doc(hidden)]
+#[doc(inline)]
 #[unstable(feature = "gen_future", issue = "50547")]
-/// Polls a future in the current thread-local task waker.
-pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
-where
-    F: Future,
-{
-    let cx_ptr = TLS_CX.with(|tls_cx| {
-        // Clear the entry so that nested `get_task_waker` calls
-        // will fail or set their own value.
-        tls_cx.replace(None)
-    });
-    let _reset = SetOnDrop(cx_ptr);
+pub use core::future::{from_generator, get_context, ResumeTy};
 
-    let mut cx_ptr = cx_ptr.expect(
-        "TLS Context not set. This is a rustc bug. \
-        Please file an issue on https://github.com/rust-lang/rust.",
-    );
+#[doc(inline)]
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+pub use core::future::{pending, ready, Pending, Ready};
 
-    // Safety: we've ensured exclusive access to the context by
-    // removing the pointer from TLS, only to be replaced once
-    // we're done with it.
-    //
-    // The pointer that was inserted came from an `&mut Context<'_>`,
-    // so it is safe to treat as mutable.
-    unsafe { F::poll(f, cx_ptr.as_mut()) }
-}
+#[doc(inline)]
+#[unstable(feature = "into_future", issue = "67644")]
+pub use core::future::IntoFuture;
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 8862226adbb..b4c91cced43 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -184,7 +184,6 @@ impl<R> BufReader<R> {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(buffered_io_capacity)]
     /// use std::io::{BufReader, BufRead};
     /// use std::fs::File;
     ///
@@ -198,7 +197,7 @@ impl<R> BufReader<R> {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "buffered_io_capacity", issue = "68833")]
+    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
     pub fn capacity(&self) -> usize {
         self.buf.len()
     }
@@ -292,6 +291,10 @@ impl<R: Read> Read for BufReader<R> {
         Ok(nread)
     }
 
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
     // we can't skip unconditionally because of the large buffer case in read.
     unsafe fn initializer(&self) -> Initializer {
         self.inner.initializer()
@@ -363,7 +366,7 @@ impl<R: Seek> Seek for BufReader<R> {
             // it should be safe to assume that remainder fits within an i64 as the alternative
             // means we managed to allocate 8 exbibytes and that's absurd.
             // But it's not out of the realm of possibility for some weird underlying reader to
-            // support seeking by i64::min_value() so we need to handle underflow when subtracting
+            // support seeking by i64::MIN so we need to handle underflow when subtracting
             // remainder.
             if let Some(offset) = n.checked_sub(remainder) {
                 result = self.inner.seek(SeekFrom::Current(offset))?;
@@ -397,7 +400,7 @@ impl<R: Seek> Seek for BufReader<R> {
 /// in memory, like a `Vec<u8>`.
 ///
 /// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
-/// dropping will attempt to flush the the contents of the buffer, any errors
+/// dropping will attempt to flush the contents of the buffer, any errors
 /// that happen in the process of dropping will be ignored. Calling [`flush`]
 /// ensures that the buffer is empty and thus dropping will not even attempt
 /// file operations.
@@ -605,7 +608,6 @@ impl<W: Write> BufWriter<W> {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(buffered_io_capacity)]
     /// use std::io::BufWriter;
     /// use std::net::TcpStream;
     ///
@@ -616,7 +618,7 @@ impl<W: Write> BufWriter<W> {
     /// // Calculate how many bytes can be written without flushing
     /// let without_flush = capacity - buf_writer.buffer().len();
     /// ```
-    #[unstable(feature = "buffered_io_capacity", issue = "68833")]
+    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
     pub fn capacity(&self) -> usize {
         self.buf.capacity()
     }
@@ -680,6 +682,10 @@ impl<W: Write> Write for BufWriter<W> {
         }
     }
 
+    fn is_write_vectored(&self) -> bool {
+        self.get_ref().is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         self.flush_buf().and_then(|()| self.get_mut().flush())
     }
@@ -1043,15 +1049,10 @@ impl<W: Write> Write for LineWriter<W> {
         }
 
         // Find the last newline, and failing that write the whole buffer
-        let last_newline = bufs
-            .iter()
-            .enumerate()
-            .rev()
-            .filter_map(|(i, buf)| {
-                let pos = memchr::memrchr(b'\n', buf)?;
-                Some((i, pos))
-            })
-            .next();
+        let last_newline = bufs.iter().enumerate().rev().find_map(|(i, buf)| {
+            let pos = memchr::memrchr(b'\n', buf)?;
+            Some((i, pos))
+        });
         let (i, j) = match last_newline {
             Some(pair) => pair,
             None => return self.inner.write_vectored(bufs),
@@ -1267,7 +1268,7 @@ mod tests {
                         self.pos = self.pos.wrapping_add(n as u64);
                     }
                     SeekFrom::End(n) => {
-                        self.pos = u64::max_value().wrapping_add(n as u64);
+                        self.pos = u64::MAX.wrapping_add(n as u64);
                     }
                 }
                 Ok(self.pos)
@@ -1276,11 +1277,11 @@ mod tests {
 
         let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 });
         assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..]));
-        assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value() - 5));
+        assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5));
         assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
         // the following seek will require two underlying seeks
         let expected = 9223372036854775802;
-        assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected));
+        assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected));
         assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5));
         // seeking to 0 should empty the buffer.
         assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected));
@@ -1318,7 +1319,7 @@ mod tests {
         // The following seek will require two underlying seeks.  The first will
         // succeed but the second will fail.  This should still invalidate the
         // buffer.
-        assert!(reader.seek(SeekFrom::Current(i64::min_value())).is_err());
+        assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err());
         assert_eq!(reader.buffer().len(), 0);
     }
 
diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs
index f36aa1846a1..f4db5f81450 100644
--- a/src/libstd/io/cursor.rs
+++ b/src/libstd/io/cursor.rs
@@ -266,6 +266,10 @@ where
         Ok(nread)
     }
 
+    fn is_read_vectored(&self) -> bool {
+        true
+    }
+
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         let n = buf.len();
         Read::read_exact(&mut self.fill_buf()?, buf)?;
@@ -373,6 +377,11 @@ impl Write for Cursor<&mut [u8]> {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -389,6 +398,11 @@ impl Write for Cursor<&mut Vec<u8>> {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -405,6 +419,11 @@ impl Write for Cursor<Vec<u8>> {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -423,6 +442,11 @@ impl Write for Cursor<Box<[u8]>> {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -939,7 +963,7 @@ mod tests {
     #[cfg(target_pointer_width = "32")]
     fn vec_seek_and_write_past_usize_max() {
         let mut c = Cursor::new(Vec::new());
-        c.set_position(<usize>::max_value() as u64 + 1);
+        c.set_position(usize::MAX as u64 + 1);
         assert!(c.write_all(&[1, 2, 3]).is_err());
     }
 
diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs
index 3b55d9b9002..f7248e7547e 100644
--- a/src/libstd/io/error.rs
+++ b/src/libstd/io/error.rs
@@ -160,6 +160,11 @@ pub enum ErrorKind {
     #[stable(feature = "rust1", since = "1.0.0")]
     Interrupted,
     /// Any I/O error not part of this list.
+    ///
+    /// Errors that are `Other` now may move to a different or a new
+    /// [`ErrorKind`] variant in the future. It is not recommended to match
+    /// an error against `Other` and to expect any additional characteristics,
+    /// e.g., a specific [`Error::raw_os_error`] return value.
     #[stable(feature = "rust1", since = "1.0.0")]
     Other,
 
@@ -487,9 +492,9 @@ impl Error {
     /// }
     ///
     /// fn main() {
-    ///     // Will print "No inner error".
+    ///     // Will print "Other".
     ///     print_error(Error::last_os_error());
-    ///     // Will print "Inner error: ...".
+    ///     // Will print "AddrInUse".
     ///     print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
     /// }
     /// ```
diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs
index b7f82e65299..01dff0b3eb3 100644
--- a/src/libstd/io/impls.rs
+++ b/src/libstd/io/impls.rs
@@ -21,6 +21,11 @@ impl<R: Read + ?Sized> Read for &mut R {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        (**self).is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         (**self).initializer()
     }
@@ -53,6 +58,11 @@ impl<W: Write + ?Sized> Write for &mut W {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        (**self).is_write_vectored()
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         (**self).flush()
     }
@@ -110,6 +120,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        (**self).is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         (**self).initializer()
     }
@@ -142,6 +157,11 @@ impl<W: Write + ?Sized> Write for Box<W> {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        (**self).is_write_vectored()
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         (**self).flush()
     }
@@ -241,6 +261,11 @@ impl Read for &[u8] {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
@@ -317,6 +342,11 @@ impl Write for &mut [u8] {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
         if self.write(data)? == data.len() {
             Ok(())
@@ -352,6 +382,11 @@ impl Write for Vec<u8> {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
         self.extend_from_slice(buf);
         Ok(())
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 5ab88260d6a..717d2868abf 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -256,6 +256,7 @@
 //! [`Read::read`]: trait.Read.html#tymethod.read
 //! [`Result`]: ../result/enum.Result.html
 //! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap
+// ignore-tidy-filelength
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -516,6 +517,11 @@ pub trait Read {
     ///    reader will *always* no longer be able to produce bytes.
     /// 2. The buffer specified was 0 bytes in length.
     ///
+    /// It is not an error if the returned value `n` is smaller than the buffer size,
+    /// even when the reader is not at the end of the stream yet.
+    /// This may happen for example because fewer bytes are actually available right now
+    /// (e. g. being close to end-of-file) or because read() was interrupted by a signal.
+    ///
     /// No guarantees are provided about the contents of `buf` when this
     /// function is called, implementations cannot rely on any property of the
     /// contents of `buf` being true. It is recommended that *implementations*
@@ -570,8 +576,9 @@ pub trait Read {
     /// Like `read`, except that it reads into a slice of buffers.
     ///
     /// Data is copied to fill each buffer in order, with the final buffer
-    /// written to possibly being only partially filled. This method must behave
-    /// as a single call to `read` with the buffers concatenated would.
+    /// written to possibly being only partially filled. This method must
+    /// behave equivalently to a single call to `read` with concatenated
+    /// buffers.
     ///
     /// The default implementation calls `read` with either the first nonempty
     /// buffer provided, or an empty one if none exists.
@@ -580,6 +587,19 @@ pub trait Read {
         default_read_vectored(|b| self.read(b), bufs)
     }
 
+    /// Determines if this `Read`er has an efficient `read_vectored`
+    /// implementation.
+    ///
+    /// If a `Read`er does not override the default `read_vectored`
+    /// implementation, code using it may want to avoid the method all together
+    /// and coalesce writes into a single buffer for higher performance.
+    ///
+    /// The default implementation returns `false`.
+    #[unstable(feature = "can_vector", issue = "69941")]
+    fn is_read_vectored(&self) -> bool {
+        false
+    }
+
     /// Determines if this `Read`er can work with buffers of uninitialized
     /// memory.
     ///
@@ -1304,6 +1324,19 @@ pub trait Write {
         default_write_vectored(|b| self.write(b), bufs)
     }
 
+    /// Determines if this `Write`er has an efficient `write_vectored`
+    /// implementation.
+    ///
+    /// If a `Write`er does not override the default `write_vectored`
+    /// implementation, code using it may want to avoid the method all together
+    /// and coalesce writes into a single buffer for higher performance.
+    ///
+    /// The default implementation returns `false`.
+    #[unstable(feature = "can_vector", issue = "69941")]
+    fn is_write_vectored(&self) -> bool {
+        false
+    }
+
     /// Flush this output stream, ensuring that all intermediately buffered
     /// contents reach their destination.
     ///
@@ -1850,6 +1883,10 @@ pub trait BufRead: Read {
     ///
     /// If successful, this function will return the total number of bytes read.
     ///
+    /// This function is blocking and should be used carefully: it is possible for
+    /// an attacker to continuously send bytes without ever sending the delimiter
+    /// or EOF.
+    ///
     /// # Errors
     ///
     /// This function will ignore all instances of [`ErrorKind::Interrupted`] and
@@ -1912,6 +1949,10 @@ pub trait BufRead: Read {
     ///
     /// If this function returns `Ok(0)`, the stream has reached EOF.
     ///
+    /// This function is blocking and should be used carefully: it is possible for
+    /// an attacker to continuously send bytes without ever sending a newline
+    /// or EOF.
+    ///
     /// # Errors
     ///
     /// This function has the same error semantics as [`read_until`] and will
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index a064c552c84..d6b7ad6254a 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -88,10 +88,28 @@ impl Read for StdinRaw {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
+    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+        self.0.read_to_string(buf)
+    }
+
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        self.0.read_exact(buf)
+    }
 }
+
 impl Write for StdoutRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
@@ -101,10 +119,28 @@ impl Write for StdoutRaw {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         self.0.flush()
     }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.0.write_all(buf)
+    }
+
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.0.write_all_vectored(bufs)
+    }
+
+    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+        self.0.write_fmt(fmt)
+    }
 }
+
 impl Write for StderrRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
@@ -114,9 +150,26 @@ impl Write for StderrRaw {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         self.0.flush()
     }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.0.write_all(buf)
+    }
+
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.0.write_all_vectored(bufs)
+    }
+
+    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+        self.0.write_fmt(fmt)
+    }
 }
 
 enum Maybe<T> {
@@ -140,6 +193,14 @@ impl<W: io::Write> io::Write for Maybe<W> {
         }
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        match self {
+            Maybe::Real(w) => w.is_write_vectored(),
+            Maybe::Fake => true,
+        }
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         match *self {
             Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()),
@@ -162,6 +223,14 @@ impl<R: io::Read> io::Read for Maybe<R> {
             Maybe::Fake => Ok(0),
         }
     }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        match self {
+            Maybe::Real(w) => w.is_read_vectored(),
+            Maybe::Fake => true,
+        }
+    }
 }
 
 fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
@@ -352,6 +421,10 @@ impl Read for Stdin {
         self.lock().read_vectored(bufs)
     }
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.lock().is_read_vectored()
+    }
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
@@ -377,9 +450,26 @@ impl Read for StdinLock<'_> {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
+
+    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+        self.inner.read_to_string(buf)
+    }
+
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        self.inner.read_exact(buf)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -387,9 +477,18 @@ impl BufRead for StdinLock<'_> {
     fn fill_buf(&mut self) -> io::Result<&[u8]> {
         self.inner.fill_buf()
     }
+
     fn consume(&mut self, n: usize) {
         self.inner.consume(n)
     }
+
+    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_until(byte, buf)
+    }
+
+    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
+        self.inner.read_line(buf)
+    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -543,12 +642,19 @@ impl Write for Stdout {
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         self.lock().write_vectored(bufs)
     }
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.lock().is_write_vectored()
+    }
     fn flush(&mut self) -> io::Result<()> {
         self.lock().flush()
     }
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
         self.lock().write_all(buf)
     }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.lock().write_all_vectored(bufs)
+    }
     fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
         self.lock().write_fmt(args)
     }
@@ -561,9 +667,19 @@ impl Write for StdoutLock<'_> {
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         self.inner.borrow_mut().write_vectored(bufs)
     }
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.inner.borrow_mut().is_write_vectored()
+    }
     fn flush(&mut self) -> io::Result<()> {
         self.inner.borrow_mut().flush()
     }
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.inner.borrow_mut().write_all(buf)
+    }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.inner.borrow_mut().write_all_vectored(bufs)
+    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -709,12 +825,19 @@ impl Write for Stderr {
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         self.lock().write_vectored(bufs)
     }
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.lock().is_write_vectored()
+    }
     fn flush(&mut self) -> io::Result<()> {
         self.lock().flush()
     }
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
         self.lock().write_all(buf)
     }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.lock().write_all_vectored(bufs)
+    }
     fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
         self.lock().write_fmt(args)
     }
@@ -727,9 +850,19 @@ impl Write for StderrLock<'_> {
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         self.inner.borrow_mut().write_vectored(bufs)
     }
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.inner.borrow_mut().is_write_vectored()
+    }
     fn flush(&mut self) -> io::Result<()> {
         self.inner.borrow_mut().flush()
     }
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.inner.borrow_mut().write_all(buf)
+    }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.inner.borrow_mut().write_all_vectored(bufs)
+    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]
diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs
index b09161b97aa..b9d5dc27db0 100644
--- a/src/libstd/io/util.rs
+++ b/src/libstd/io/util.rs
@@ -180,6 +180,11 @@ impl Read for Repeat {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
@@ -236,6 +241,11 @@ impl Write for Sink {
     }
 
     #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    #[inline]
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index 314424631fc..0b3386c05d5 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -685,12 +685,12 @@ mod impl_keyword {}
 /// ## Literal Examples:
 ///
 ///    * `for _ **in** 1..3 {}` - Iterate over an exclusive range up to but excluding 3.
-///    * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and includeing 3.
+///    * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and including 3.
 ///
 /// (Read more about [range patterns])
 ///
 /// [`Iterator`]: ../book/ch13-04-performance.html
-/// [`range patterns`]: ../reference/patterns.html?highlight=range#range-patterns
+/// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns
 /// [`for`]: keyword.for.html
 mod in_keyword {}
 
@@ -913,10 +913,28 @@ mod match_keyword {}
 //
 /// Organize code into [modules].
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// Use `mod` to create new [modules] to encapsulate code, including other
+/// modules:
+///
+/// ```
+/// mod foo {
+///     mod bar {
+///         type MyType = (u8, u8);
+///         fn baz() {}
+///     }
+/// }
+/// ```
 ///
+/// Like [`struct`]s and [`enum`]s, a module and its content are private by
+/// default, unaccessible to code outside of the module.
+///
+/// To learn more about allowing access, see the documentation for the [`pub`]
+/// keyword.
+///
+/// [`enum`]: keyword.enum.html
+/// [`pub`]: keyword.pub.html
+/// [`struct`]: keyword.struct.html
 /// [modules]: ../reference/items/modules.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
 mod mod_keyword {}
 
 #[doc(keyword = "move")]
@@ -965,11 +983,61 @@ mod move_keyword {}
 
 #[doc(keyword = "mut")]
 //
-/// A mutable binding, reference, or pointer.
+/// A mutable variable, reference, or pointer.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `mut` can be used in several situations. The first is mutable variables,
+/// which can be used anywhere you can bind a value to a variable name. Some
+/// examples:
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// ```rust
+/// // A mutable variable in the parameter list of a function.
+/// fn foo(mut x: u8, y: u8) -> u8 {
+///     x += y;
+///     x
+/// }
+///
+/// // Modifying a mutable variable.
+/// # #[allow(unused_assignments)]
+/// let mut a = 5;
+/// a = 6;
+///
+/// assert_eq!(foo(3, 4), 7);
+/// assert_eq!(a, 6);
+/// ```
+///
+/// The second is mutable references. They can be created from `mut` variables
+/// and must be unique: no other variables can have a mutable reference, nor a
+/// shared reference.
+///
+/// ```rust
+/// // Taking a mutable reference.
+/// fn push_two(v: &mut Vec<u8>) {
+///     v.push(2);
+/// }
+///
+/// // A mutable reference cannot be taken to a non-mutable variable.
+/// let mut v = vec![0, 1];
+/// // Passing a mutable reference.
+/// push_two(&mut v);
+///
+/// assert_eq!(v, vec![0, 1, 2]);
+/// ```
+///
+/// ```rust,compile_fail,E0502
+/// let mut v = vec![0, 1];
+/// let mut_ref_v = &mut v;
+/// ##[allow(unused)]
+/// let ref_v = &v;
+/// mut_ref_v.push(2);
+/// ```
+///
+/// Mutable raw pointers work much like mutable references, with the added
+/// possibility of not pointing to a valid object. The syntax is `*mut Type`.
+///
+/// More information on mutable references and pointers can be found in```
+/// [Reference].
+///
+/// [Reference]: ../reference/types/pointer.html#mutable-references-mut
 mod mut_keyword {}
 
 #[doc(keyword = "pub")]
@@ -1000,18 +1068,148 @@ mod ref_keyword {}
 //
 /// Return a value from a function.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// A `return` marks the end of an execution path in a function:
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// ```
+/// fn foo() -> i32 {
+///     return 3;
+/// }
+/// assert_eq!(foo(), 3);
+/// ```
+///
+/// `return` is not needed when the returned value is the last expression in the
+/// function. In this case the `;` is omitted:
+///
+/// ```
+/// fn foo() -> i32 {
+///     3
+/// }
+/// assert_eq!(foo(), 3);
+/// ```
+///
+/// `return` returns from the function immediately (an "early return"):
+///
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::{Error, ErrorKind, Read, Result};
+///
+/// fn main() -> Result<()> {
+///     let mut file = match File::open("foo.txt") {
+///         Ok(f) => f,
+///         Err(e) => return Err(e),
+///     };
+///
+///     let mut contents = String::new();
+///     let size = match file.read_to_string(&mut contents) {
+///         Ok(s) => s,
+///         Err(e) => return Err(e),
+///     };
+///
+///     if contents.contains("impossible!") {
+///         return Err(Error::new(ErrorKind::Other, "oh no!"));
+///     }
+///
+///     if size > 9000 {
+///         return Err(Error::new(ErrorKind::Other, "over 9000!"));
+///     }
+///
+///     assert_eq!(contents, "Hello, world!");
+///     Ok(())
+/// }
+/// ```
 mod return_keyword {}
 
 #[doc(keyword = "self")]
 //
 /// The receiver of a method, or the current module.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `self` is used in two situations: referencing the current module and marking
+/// the receiver of a method.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// In paths, `self` can be used to refer to the current module, either in a
+/// [`use`] statement or in a path to access an element:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::io::{self, Read};
+/// ```
+///
+/// Is functionally the same as:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::io;
+/// use std::io::Read;
+/// ```
+///
+/// Using `self` to access an element in the current module:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// # fn main() {}
+/// fn foo() {}
+/// fn bar() {
+///     self::foo()
+/// }
+/// ```
+///
+/// `self` as the current receiver for a method allows to omit the parameter
+/// type most of the time. With the exception of this particularity, `self` is
+/// used much like any other parameter:
+///
+/// ```
+/// struct Foo(i32);
+///
+/// impl Foo {
+///     // No `self`.
+///     fn new() -> Self {
+///         Self(0)
+///     }
+///
+///     // Consuming `self`.
+///     fn consume(self) -> Self {
+///         Self(self.0 + 1)
+///     }
+///
+///     // Borrowing `self`.
+///     fn borrow(&self) -> &i32 {
+///         &self.0
+///     }
+///
+///     // Borrowing `self` mutably.
+///     fn borrow_mut(&mut self) -> &mut i32 {
+///         &mut self.0
+///     }
+/// }
+///
+/// // This method must be called with a `Type::` prefix.
+/// let foo = Foo::new();
+/// assert_eq!(foo.0, 0);
+///
+/// // Those two calls produces the same result.
+/// let foo = Foo::consume(foo);
+/// assert_eq!(foo.0, 1);
+/// let foo = foo.consume();
+/// assert_eq!(foo.0, 2);
+///
+/// // Borrowing is handled automatically with the second syntax.
+/// let borrow_1 = Foo::borrow(&foo);
+/// let borrow_2 = foo.borrow();
+/// assert_eq!(borrow_1, borrow_2);
+///
+/// // Borrowing mutably is handled automatically too with the second syntax.
+/// let mut foo = Foo::new();
+/// *Foo::borrow_mut(&mut foo) += 1;
+/// assert_eq!(foo.0, 1);
+/// *foo.borrow_mut() += 1;
+/// assert_eq!(foo.0, 2);
+/// ```
+///
+/// Note that this automatic conversion when calling `foo.method()` is not
+/// limited to the examples above. See the [Reference] for more information.
+///
+/// [`use`]: keyword.use.html
+/// [Reference]: ../reference/items/associated-items.html#methods
 mod self_keyword {}
 
 #[doc(keyword = "Self")]
@@ -1019,20 +1217,148 @@ mod self_keyword {}
 /// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type
 /// definition.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// Within a type definition:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// struct Node {
+///     elem: i32,
+///     // `Self` is a `Node` here.
+///     next: Option<Box<Self>>,
+/// }
+/// ```
+///
+/// In an [`impl`] block:
+///
+/// ```
+/// struct Foo(i32);
+///
+/// impl Foo {
+///     fn new() -> Self {
+///         Self(0)
+///     }
+/// }
+///
+/// assert_eq!(Foo::new().0, Foo(0).0);
+/// ```
+///
+/// Generic parameters are implicit with `Self`:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// struct Wrap<T> {
+///     elem: T,
+/// }
+///
+/// impl<T> Wrap<T> {
+///     fn new(elem: T) -> Self {
+///         Self { elem }
+///     }
+/// }
+/// ```
+///
+/// In a [`trait`] definition and related [`impl`] block:
+///
+/// ```
+/// trait Example {
+///     fn example() -> Self;
+/// }
+///
+/// struct Foo(i32);
+///
+/// impl Example for Foo {
+///     fn example() -> Self {
+///         Self(42)
+///     }
+/// }
+///
+/// assert_eq!(Foo::example().0, Foo(42).0);
+/// ```
 ///
 /// [`impl`]: keyword.impl.html
 /// [`trait`]: keyword.trait.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
 mod self_upper_keyword {}
 
 #[doc(keyword = "static")]
 //
-/// A place that is valid for the duration of a program.
+/// A static item is a value which is valid for the entire duration of your
+/// program (a `'static` lifetime).
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// On the surface, `static` items seem very similar to [`const`]s: both contain
+/// a value, both require type annotations and both can only be initialized with
+/// constant functions and values. However, `static`s are notably different in
+/// that they represent a location in memory. That means that you can have
+/// references to `static` items and potentially even modify them, making them
+/// essentially global variables.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// Static items do not call [`drop`] at the end of the program.
+///
+/// There are two types of `static` items: those declared in association with
+/// the [`mut`] keyword and those without.
+///
+/// Static items cannot be moved:
+///
+/// ```rust,compile_fail,E0507
+/// static VEC: Vec<u32> = vec![];
+///
+/// fn move_vec(v: Vec<u32>) -> Vec<u32> {
+///     v
+/// }
+///
+/// // This line causes an error
+/// move_vec(VEC);
+/// ```
+///
+/// # Simple `static`s
+///
+/// Accessing non-[`mut`] `static` items is considered safe, but some
+/// restrictions apply. Most notably, the type of a `static` value needs to
+/// implement the [`Sync`] trait, ruling out interior mutability containers
+/// like [`RefCell`]. See the [Reference] for more information.
+///
+/// ```rust
+/// static FOO: [i32; 5] = [1, 2, 3, 4, 5];
+///
+/// let r1 = &FOO as *const _;
+/// let r2 = &FOO as *const _;
+/// // With a strictly read-only static, references will have the same adress
+/// assert_eq!(r1, r2);
+/// // A static item can be used just like a variable in many cases
+/// println!("{:?}", FOO);
+/// ```
+///
+/// # Mutable `static`s
+///
+/// If a `static` item is declared with the [`mut`] keyword, then it is allowed
+/// to be modified by the program. However, accessing mutable `static`s can
+/// cause undefined behavior in a number of ways, for example due to data races
+/// in a multithreaded context. As such, all accesses to mutable `static`s
+/// require an [`unsafe`] block.
+///
+/// Despite their unsafety, mutable `static`s are necessary in many contexts:
+/// they can be used to represent global state shared by the whole program or in
+/// [`extern`] blocks to bind to variables from C libraries.
+///
+/// In an [`extern`] block:
+///
+/// ```rust,no_run
+/// # #![allow(dead_code)]
+/// extern "C" {
+///     static mut ERROR_MESSAGE: *mut std::os::raw::c_char;
+/// }
+/// ```
+///
+/// Mutable `static`s, just like simple `static`s, have some restrictions that
+/// apply to them. See the [Reference] for more information.
+///
+/// [`const`]: keyword.const.html
+/// [`extern`]: keyword.extern.html
+/// [`mut`]: keyword.mut.html
+/// [`unsafe`]: keyword.unsafe.html
+/// [`drop`]: mem/fn.drop.html
+/// [`Sync`]: marker/trait.Sync.html
+/// [`RefCell`]: cell/struct.RefCell.html
+/// [Reference]: ../reference/items/static-items.html
 mod static_keyword {}
 
 #[doc(keyword = "struct")]
@@ -1147,10 +1473,26 @@ mod struct_keyword {}
 //
 /// The parent of the current [module].
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// ```rust
+/// # #![allow(dead_code)]
+/// # fn main() {}
+/// mod a {
+///     pub fn foo() {}
+/// }
+/// mod b {
+///     pub fn foo() {
+///         super::a::foo(); // call a's foo function
+///     }
+/// }
+/// ```
+///
+/// It is also possible to use `super` multiple times: `super::super::foo`,
+/// going up the ancestor chain.
+///
+/// See the [Reference] for more information.
 ///
 /// [module]: ../reference/items/modules.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// [Reference]: ../reference/paths.html#super
 mod super_keyword {}
 
 #[doc(keyword = "trait")]
@@ -1194,9 +1536,44 @@ mod true_keyword {}
 //
 /// Define an alias for an existing type.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// The syntax is `type Name = ExistingType;`.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// # Examples
+///
+/// `type` does **not** create a new type:
+///
+/// ```rust
+/// type Meters = u32;
+/// type Kilograms = u32;
+///
+/// let m: Meters = 3;
+/// let k: Kilograms = 3;
+///
+/// assert_eq!(m, k);
+/// ```
+///
+/// In traits, `type` is used to declare an [associated type]:
+///
+/// ```rust
+/// trait Iterator {
+///     // associated type declaration
+///     type Item;
+///     fn next(&mut self) -> Option<Self::Item>;
+/// }
+///
+/// struct Once<T>(Option<T>);
+///
+/// impl<T> Iterator for Once<T> {
+///     // associated type definition
+///     type Item = T;
+///     fn next(&mut self) -> Option<Self::Item> {
+///         self.0.take()
+///     }
+/// }
+/// ```
+///
+/// [`trait`]: keyword.trait.html
+/// [associated type]: ../reference/items/associated-items.html#associated-types
 mod type_keyword {}
 
 #[doc(keyword = "unsafe")]
@@ -1213,9 +1590,61 @@ mod unsafe_keyword {}
 //
 /// Import or rename items from other crates or modules.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// Usually a `use` keyword is used to shorten the path required to refer to a module item.
+/// The keyword may appear in modules, blocks and even functions, usually at the top.
+///
+/// The most basic usage of the keyword is `use path::to::item;`,
+/// though a number of convenient shortcuts are supported:
+///
+///   * Simultaneously binding a list of paths with a common prefix,
+///     using the glob-like brace syntax `use a::b::{c, d, e::f, g::h::i};`
+///   * Simultaneously binding a list of paths with a common prefix and their common parent module,
+///     using the [`self`] keyword, such as `use a::b::{self, c, d::e};`
+///   * Rebinding the target name as a new local name, using the syntax `use p::q::r as x;`.
+///     This can also be used with the last two features: `use a::b::{self as ab, c as abc}`.
+///   * Binding all paths matching a given prefix,
+///     using the asterisk wildcard syntax `use a::b::*;`.
+///   * Nesting groups of the previous features multiple times,
+///     such as `use a::b::{self as ab, c, d::{*, e::f}};`
+///   * Reexporting with visibility modifiers such as `pub use a::b;`
+///   * Importing with `_` to only import the methods of a trait without binding it to a name
+///     (to avoid conflict for example): `use ::std::io::Read as _;`.
+///
+/// Using path qualifiers like [`crate`], [`super`] or [`self`] is supported: `use crate::a::b;`.
+///
+/// Note that when the wildcard `*` is used on a type, it does not import its methods (though
+/// for `enum`s it imports the variants, as shown in the example below).
+///
+/// ```compile_fail,edition2018
+/// enum ExampleEnum {
+///     VariantA,
+///     VariantB,
+/// }
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// impl ExampleEnum {
+///     fn new() -> Self {
+///         Self::VariantA
+///     }
+/// }
+///
+/// use ExampleEnum::*;
+///
+/// // Compiles.
+/// let _ = VariantA;
+///
+/// // Does not compile !
+/// let n = new();
+/// ```
+///
+/// For more information on `use` and paths in general, see the [Reference].
+///
+/// The differences about paths and the `use` keyword between the 2015 and 2018 editions
+/// can also be found in the [Reference].
+///
+/// [`crate`]: keyword.crate.html
+/// [`self`]: keyword.self.html
+/// [`super`]: keyword.super.html
+/// [Reference]: ../reference/items/use-declarations.html
 mod use_keyword {}
 
 #[doc(keyword = "where")]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 9d2810cacc2..bd585d39c24 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -242,10 +242,12 @@
 #![feature(atomic_mut_ptr)]
 #![feature(box_syntax)]
 #![feature(c_variadic)]
-#![cfg_attr(not(bootstrap), feature(cfg_accessible))]
+#![feature(cfg_accessible)]
+#![feature(can_vector)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
+#![feature(char_internals)]
 #![feature(clamp)]
 #![feature(concat_idents)]
 #![feature(const_cstr_unchecked)]
@@ -262,15 +264,19 @@
 #![feature(duration_constants)]
 #![feature(exact_size_is_empty)]
 #![feature(exhaustive_patterns)]
+#![feature(extend_one)]
 #![feature(external_doc)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
+#![feature(future_readiness_fns)]
+#![feature(gen_future)]
 #![feature(generator_trait)]
 #![feature(global_asm)]
 #![feature(hash_raw_entry)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
 #![feature(int_error_matching)]
+#![feature(into_future)]
 #![feature(integer_atomics)]
 #![feature(lang_items)]
 #![feature(libc)]
@@ -281,7 +287,7 @@
 #![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
 #![feature(needs_panic_runtime)]
-#![cfg_attr(not(bootstrap), feature(negative_impls))]
+#![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(optin_builtin_traits)]
@@ -292,14 +298,14 @@
 #![feature(prelude_import)]
 #![feature(ptr_internals)]
 #![feature(raw)]
+#![feature(raw_ref_macros)]
 #![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
 #![feature(shrink_to)]
 #![feature(slice_concat_ext)]
 #![feature(slice_internals)]
-#![cfg_attr(bootstrap, feature(specialization))]
-#![cfg_attr(not(bootstrap), feature(min_specialization))]
+#![feature(min_specialization)]
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stdsimd)]
@@ -308,10 +314,12 @@
 #![feature(test)]
 #![feature(thread_local)]
 #![feature(toowned_clone_into)]
+#![feature(total_cmp)]
 #![feature(trace_macros)]
-#![feature(track_caller)]
+#![cfg_attr(bootstrap, feature(track_caller))]
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
+#![feature(unsafe_block_in_unsafe_fn)]
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
 #![feature(vec_into_raw_parts)]
diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
index de6360cf020..8c8d1aadf48 100644
--- a/src/libstd/net/addr.rs
+++ b/src/libstd/net/addr.rs
@@ -1,7 +1,8 @@
+use crate::cmp::Ordering;
 use crate::convert::TryInto;
 use crate::fmt;
 use crate::hash;
-use crate::io;
+use crate::io::{self, Write};
 use crate::iter;
 use crate::mem;
 use crate::net::{htons, ntohs, IpAddr, Ipv4Addr, Ipv6Addr};
@@ -36,7 +37,7 @@ use crate::vec;
 /// assert_eq!(socket.port(), 8080);
 /// assert_eq!(socket.is_ipv4(), true);
 /// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum SocketAddr {
     /// An IPv4 socket address.
@@ -599,7 +600,26 @@ impl fmt::Display for SocketAddr {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for SocketAddrV4 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}:{}", self.ip(), self.port())
+        // Fast path: if there's no alignment stuff, write to the output buffer
+        // directly
+        if f.precision().is_none() && f.width().is_none() {
+            write!(f, "{}:{}", self.ip(), self.port())
+        } else {
+            const IPV4_SOCKET_BUF_LEN: usize = (3 * 4)  // the segments
+                + 3  // the separators
+                + 1 + 5; // the port
+            let mut buf = [0; IPV4_SOCKET_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+
+            // Unwrap is fine because writing to a sufficiently-sized
+            // buffer is infallible
+            write!(buf_slice, "{}:{}", self.ip(), self.port()).unwrap();
+            let len = IPV4_SOCKET_BUF_LEN - buf_slice.len();
+
+            // This unsafe is OK because we know what is being written to the buffer
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            f.pad(buf)
+        }
     }
 }
 
@@ -613,7 +633,28 @@ impl fmt::Debug for SocketAddrV4 {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for SocketAddrV6 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{}]:{}", self.ip(), self.port())
+        // Fast path: if there's no alignment stuff, write to the output
+        // buffer directly
+        if f.precision().is_none() && f.width().is_none() {
+            write!(f, "[{}]:{}", self.ip(), self.port())
+        } else {
+            const IPV6_SOCKET_BUF_LEN: usize = (4 * 8)  // The address
+            + 7  // The colon separators
+            + 2  // The brackets
+            + 1 + 5; // The port
+
+            let mut buf = [0; IPV6_SOCKET_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+
+            // Unwrap is fine because writing to a sufficiently-sized
+            // buffer is infallible
+            write!(buf_slice, "[{}]:{}", self.ip(), self.port()).unwrap();
+            let len = IPV6_SOCKET_BUF_LEN - buf_slice.len();
+
+            // This unsafe is OK because we know what is being written to the buffer
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            f.pad(buf)
+        }
     }
 }
 
@@ -658,6 +699,34 @@ impl Eq for SocketAddrV4 {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Eq for SocketAddrV6 {}
 
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl PartialOrd for SocketAddrV4 {
+    fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl PartialOrd for SocketAddrV6 {
+    fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl Ord for SocketAddrV4 {
+    fn cmp(&self, other: &SocketAddrV4) -> Ordering {
+        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl Ord for SocketAddrV6 {
+    fn cmp(&self, other: &SocketAddrV6) -> Ordering {
+        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl hash::Hash for SocketAddrV4 {
     fn hash<H: hash::Hasher>(&self, s: &mut H) {
@@ -895,6 +964,14 @@ impl ToSocketAddrs for (&str, u16) {
     }
 }
 
+#[stable(feature = "string_u16_to_socket_addrs", since = "1.46.0")]
+impl ToSocketAddrs for (String, u16) {
+    type Iter = vec::IntoIter<SocketAddr>;
+    fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+        (&*self.0, self.1).to_socket_addrs()
+    }
+}
+
 // accepts strings like 'localhost:12345'
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ToSocketAddrs for str {
@@ -1102,4 +1179,67 @@ mod tests {
         assert!(!v6.is_ipv4());
         assert!(v6.is_ipv6());
     }
+
+    #[test]
+    fn socket_v4_to_str() {
+        let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080);
+
+        assert_eq!(format!("{}", socket), "192.168.0.1:8080");
+        assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080    ");
+        assert_eq!(format!("{:>20}", socket), "    192.168.0.1:8080");
+        assert_eq!(format!("{:^20}", socket), "  192.168.0.1:8080  ");
+        assert_eq!(format!("{:.10}", socket), "192.168.0.");
+    }
+
+    #[test]
+    fn socket_v6_to_str() {
+        let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap();
+
+        assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53");
+        assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53    ");
+        assert_eq!(format!("{:>24}", socket), "    [2a02:6b8:0:1::1]:53");
+        assert_eq!(format!("{:^24}", socket), "  [2a02:6b8:0:1::1]:53  ");
+        assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::");
+    }
+
+    #[test]
+    fn compare() {
+        let v4_1 = "224.120.45.1:23456".parse::<SocketAddrV4>().unwrap();
+        let v4_2 = "224.210.103.5:12345".parse::<SocketAddrV4>().unwrap();
+        let v4_3 = "224.210.103.5:23456".parse::<SocketAddrV4>().unwrap();
+        let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
+        let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
+        let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
+
+        // equality
+        assert_eq!(v4_1, v4_1);
+        assert_eq!(v6_1, v6_1);
+        assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1));
+        assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
+        assert!(v4_1 != v4_2);
+        assert!(v6_1 != v6_2);
+
+        // compare different addresses
+        assert!(v4_1 < v4_2);
+        assert!(v6_1 < v6_2);
+        assert!(v4_2 > v4_1);
+        assert!(v6_2 > v6_1);
+
+        // compare the same address with different ports
+        assert!(v4_2 < v4_3);
+        assert!(v6_2 < v6_3);
+        assert!(v4_3 > v4_2);
+        assert!(v6_3 > v6_2);
+
+        // compare different addresses with the same port
+        assert!(v4_1 < v4_3);
+        assert!(v6_1 < v6_3);
+        assert!(v4_3 > v4_1);
+        assert!(v6_3 > v6_1);
+
+        // compare with an inferred right-hand side
+        assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
+        assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());
+        assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap());
+    }
 }
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index edc28033c9b..0f0be2c4883 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -7,9 +7,9 @@
 )]
 
 use crate::cmp::Ordering;
-use crate::fmt;
+use crate::fmt::{self, Write as FmtWrite};
 use crate::hash;
-use crate::io::Write;
+use crate::io::Write as IoWrite;
 use crate::sys::net::netc as c;
 use crate::sys_common::{AsInner, FromInner};
 
@@ -856,16 +856,23 @@ impl From<Ipv6Addr> for IpAddr {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Ipv4Addr {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address
-        let mut buf = [0u8; IPV4_BUF_LEN];
-        let mut buf_slice = &mut buf[..];
         let octets = self.octets();
-        // Note: The call to write should never fail, hence the unwrap
-        write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
-        let len = IPV4_BUF_LEN - buf_slice.len();
-        // This unsafe is OK because we know what is being written to the buffer
-        let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
-        fmt.pad(buf)
+        // Fast Path: if there's no alignment stuff, write directly to the buffer
+        if fmt.precision().is_none() && fmt.width().is_none() {
+            write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+        } else {
+            const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address
+            let mut buf = [0u8; IPV4_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+
+            // Note: The call to write should never fail, hence the unwrap
+            write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
+            let len = IPV4_BUF_LEN - buf_slice.len();
+
+            // This unsafe is OK because we know what is being written to the buffer
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            fmt.pad(buf)
+        }
     }
 }
 
@@ -1525,102 +1532,100 @@ impl Ipv6Addr {
     }
 }
 
+/// Write an Ipv6Addr, conforming to the canonical style described by
+/// [RFC 5952](https://tools.ietf.org/html/rfc5952).
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Ipv6Addr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Note: The calls to write should never fail, hence the unwraps in the function
-        // Long enough for the longest possible IPv6: 39
-        const IPV6_BUF_LEN: usize = 39;
-        let mut buf = [0u8; IPV6_BUF_LEN];
-        let mut buf_slice = &mut buf[..];
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // If there are no alignment requirements, write out the IP address to
+        // f. Otherwise, write it to a local buffer, then use f.pad.
+        if f.precision().is_none() && f.width().is_none() {
+            let segments = self.segments();
+
+            // Special case for :: and ::1; otherwise they get written with the
+            // IPv4 formatter
+            if self.is_unspecified() {
+                f.write_str("::")
+            } else if self.is_loopback() {
+                f.write_str("::1")
+            } else if let Some(ipv4) = self.to_ipv4() {
+                match segments[5] {
+                    // IPv4 Compatible address
+                    0 => write!(f, "::{}", ipv4),
+                    // IPv4 Mapped address
+                    0xffff => write!(f, "::ffff:{}", ipv4),
+                    _ => unreachable!(),
+                }
+            } else {
+                #[derive(Copy, Clone, Default)]
+                struct Span {
+                    start: usize,
+                    len: usize,
+                }
 
-        match self.segments() {
-            // We need special cases for :: and ::1, otherwise they're formatted
-            // as ::0.0.0.[01]
-            [0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(),
-            [0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(),
-            // Ipv4 Compatible address
-            [0, 0, 0, 0, 0, 0, g, h] => {
-                write!(
-                    buf_slice,
-                    "::{}.{}.{}.{}",
-                    (g >> 8) as u8,
-                    g as u8,
-                    (h >> 8) as u8,
-                    h as u8
-                )
-                .unwrap();
-            }
-            // Ipv4-Mapped address
-            [0, 0, 0, 0, 0, 0xffff, g, h] => {
-                write!(
-                    buf_slice,
-                    "::ffff:{}.{}.{}.{}",
-                    (g >> 8) as u8,
-                    g as u8,
-                    (h >> 8) as u8,
-                    h as u8
-                )
-                .unwrap();
-            }
-            _ => {
-                fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) {
-                    let mut longest_span_len = 0;
-                    let mut longest_span_at = 0;
-                    let mut cur_span_len = 0;
-                    let mut cur_span_at = 0;
-
-                    for i in 0..8 {
-                        if segments[i] == 0 {
-                            if cur_span_len == 0 {
-                                cur_span_at = i;
+                // Find the inner 0 span
+                let zeroes = {
+                    let mut longest = Span::default();
+                    let mut current = Span::default();
+
+                    for (i, &segment) in segments.iter().enumerate() {
+                        if segment == 0 {
+                            if current.len == 0 {
+                                current.start = i;
                             }
 
-                            cur_span_len += 1;
+                            current.len += 1;
 
-                            if cur_span_len > longest_span_len {
-                                longest_span_len = cur_span_len;
-                                longest_span_at = cur_span_at;
+                            if current.len > longest.len {
+                                longest = current;
                             }
                         } else {
-                            cur_span_len = 0;
-                            cur_span_at = 0;
+                            current = Span::default();
                         }
                     }
 
-                    (longest_span_at, longest_span_len)
-                }
-
-                let (zeros_at, zeros_len) = find_zero_slice(&self.segments());
-
-                if zeros_len > 1 {
-                    fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) {
-                        if !segments.is_empty() {
-                            write!(*buf, "{:x}", segments[0]).unwrap();
-                            for &seg in &segments[1..] {
-                                write!(*buf, ":{:x}", seg).unwrap();
-                            }
+                    longest
+                };
+
+                /// Write a colon-separated part of the address
+                #[inline]
+                fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
+                    if let Some(first) = chunk.first() {
+                        fmt::LowerHex::fmt(first, f)?;
+                        for segment in &chunk[1..] {
+                            f.write_char(':')?;
+                            fmt::LowerHex::fmt(segment, f)?;
                         }
                     }
+                    Ok(())
+                }
 
-                    fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice);
-                    write!(buf_slice, "::").unwrap();
-                    fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice);
+                if zeroes.len > 1 {
+                    fmt_subslice(f, &segments[..zeroes.start])?;
+                    f.write_str("::")?;
+                    fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
                 } else {
-                    let &[a, b, c, d, e, f, g, h] = &self.segments();
-                    write!(
-                        buf_slice,
-                        "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
-                        a, b, c, d, e, f, g, h
-                    )
-                    .unwrap();
+                    fmt_subslice(f, &segments)
                 }
             }
+        } else {
+            // Slow path: write the address to a local buffer, the use f.pad.
+            // Defined recursively by using the fast path to write to the
+            // buffer.
+
+            // This is the largest possible size of an IPv6 address
+            const IPV6_BUF_LEN: usize = (4 * 8) + 7;
+            let mut buf = [0u8; IPV6_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+
+            // Note: This call to write should never fail, so unwrap is okay.
+            write!(buf_slice, "{}", self).unwrap();
+            let len = IPV6_BUF_LEN - buf_slice.len();
+
+            // This is safe because we know exactly what can be in this buffer
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            f.pad(buf)
         }
-        let len = IPV6_BUF_LEN - buf_slice.len();
-        // This is safe because we know exactly what can be in this buffer
-        let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
-        fmt.pad(buf)
     }
 }
 
diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs
index 3f38ee54710..12d3baf6333 100644
--- a/src/libstd/net/parser.rs
+++ b/src/libstd/net/parser.rs
@@ -10,163 +10,132 @@ use crate::str::FromStr;
 
 struct Parser<'a> {
     // parsing as ASCII, so can use byte array
-    s: &'a [u8],
-    pos: usize,
+    state: &'a [u8],
 }
 
 impl<'a> Parser<'a> {
-    fn new(s: &'a str) -> Parser<'a> {
-        Parser { s: s.as_bytes(), pos: 0 }
+    fn new(input: &'a str) -> Parser<'a> {
+        Parser { state: input.as_bytes() }
     }
 
     fn is_eof(&self) -> bool {
-        self.pos == self.s.len()
+        self.state.is_empty()
     }
 
-    // Commit only if parser returns Some
-    fn read_atomically<T, F>(&mut self, cb: F) -> Option<T>
+    /// Run a parser, and restore the pre-parse state if it fails
+    fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
     where
         F: FnOnce(&mut Parser<'_>) -> Option<T>,
     {
-        let pos = self.pos;
-        let r = cb(self);
-        if r.is_none() {
-            self.pos = pos;
+        let state = self.state;
+        let result = inner(self);
+        if result.is_none() {
+            self.state = state;
         }
-        r
+        result
     }
 
-    // Commit only if parser read till EOF
-    fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T>
+    /// Run a parser, but fail if the entire input wasn't consumed.
+    /// Doesn't run atomically.
+    fn read_till_eof<T, F>(&mut self, inner: F) -> Option<T>
     where
         F: FnOnce(&mut Parser<'_>) -> Option<T>,
     {
-        self.read_atomically(move |p| cb(p).filter(|_| p.is_eof()))
+        inner(self).filter(|_| self.is_eof())
     }
 
-    // Apply 3 parsers sequentially
-    fn read_seq_3<A, B, C, PA, PB, PC>(&mut self, pa: PA, pb: PB, pc: PC) -> Option<(A, B, C)>
+    /// Same as read_till_eof, but returns a Result<AddrParseError> on failure
+    fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
     where
-        PA: FnOnce(&mut Parser<'_>) -> Option<A>,
-        PB: FnOnce(&mut Parser<'_>) -> Option<B>,
-        PC: FnOnce(&mut Parser<'_>) -> Option<C>,
+        F: FnOnce(&mut Parser<'_>) -> Option<T>,
     {
-        self.read_atomically(move |p| {
-            let a = pa(p);
-            let b = if a.is_some() { pb(p) } else { None };
-            let c = if b.is_some() { pc(p) } else { None };
-            match (a, b, c) {
-                (Some(a), Some(b), Some(c)) => Some((a, b, c)),
-                _ => None,
-            }
-        })
+        self.read_till_eof(inner).ok_or(AddrParseError(()))
     }
 
-    // Read next char
+    /// Read the next character from the input
     fn read_char(&mut self) -> Option<char> {
-        if self.is_eof() {
-            None
-        } else {
-            let r = self.s[self.pos] as char;
-            self.pos += 1;
-            Some(r)
-        }
-    }
-
-    // Return char and advance iff next char is equal to requested
-    fn read_given_char(&mut self, c: char) -> Option<char> {
-        self.read_atomically(|p| match p.read_char() {
-            Some(next) if next == c => Some(next),
-            _ => None,
+        self.state.split_first().map(|(&b, tail)| {
+            self.state = tail;
+            b as char
         })
     }
 
-    // Read digit
-    fn read_digit(&mut self, radix: u8) -> Option<u8> {
-        fn parse_digit(c: char, radix: u8) -> Option<u8> {
-            let c = c as u8;
-            // assuming radix is either 10 or 16
-            if c >= b'0' && c <= b'9' {
-                Some(c - b'0')
-            } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
-                Some(c - b'a' + 10)
-            } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
-                Some(c - b'A' + 10)
-            } else {
-                None
-            }
-        }
-
-        self.read_atomically(|p| p.read_char().and_then(|c| parse_digit(c, radix)))
+    /// Read the next character from the input if it matches the target
+    fn read_given_char(&mut self, target: char) -> Option<char> {
+        self.read_atomically(|p| p.read_char().filter(|&c| c == target))
     }
 
-    fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
-        let mut r = 0;
-        let mut digit_count = 0;
-        loop {
-            match self.read_digit(radix) {
-                Some(d) => {
-                    r = r * (radix as u32) + (d as u32);
-                    digit_count += 1;
-                    if digit_count > max_digits || r >= upto {
-                        return None;
-                    }
-                }
-                None => {
-                    if digit_count == 0 {
-                        return None;
-                    } else {
-                        return Some(r);
-                    }
-                }
-            };
-        }
+    /// Helper for reading separators in an indexed loop. Reads the separator
+    /// character iff index > 0, then runs the parser. When used in a loop,
+    /// the separator character will only be read on index > 0 (see
+    /// read_ipv4_addr for an example)
+    fn read_separator<T, F>(&mut self, sep: char, index: usize, inner: F) -> Option<T>
+    where
+        F: FnOnce(&mut Parser<'_>) -> Option<T>,
+    {
+        self.read_atomically(move |p| {
+            if index > 0 {
+                let _ = p.read_given_char(sep)?;
+            }
+            inner(p)
+        })
     }
 
-    // Read number, failing if max_digits of number value exceeded
-    fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
-        self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
+    // Read a single digit in the given radix. For instance, 0-9 in radix 10;
+    // 0-9A-F in radix 16.
+    fn read_digit(&mut self, radix: u32) -> Option<u32> {
+        self.read_atomically(move |p| p.read_char()?.to_digit(radix))
     }
 
-    fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
-        let mut bs = [0; 4];
-        let mut i = 0;
-        while i < 4 {
-            if i != 0 && self.read_given_char('.').is_none() {
-                return None;
+    // Read a number off the front of the input in the given radix, stopping
+    // at the first non-digit character or eof. Fails if the number has more
+    // digits than max_digits, or the value is >= upto, or if there is no number.
+    fn read_number(&mut self, radix: u32, max_digits: u32, upto: u32) -> Option<u32> {
+        self.read_atomically(move |p| {
+            let mut result = 0;
+            let mut digit_count = 0;
+
+            while let Some(digit) = p.read_digit(radix) {
+                result = (result * radix) + digit;
+                digit_count += 1;
+                if digit_count > max_digits || result >= upto {
+                    return None;
+                }
             }
 
-            bs[i] = self.read_number(10, 3, 0x100).map(|n| n as u8)?;
-            i += 1;
-        }
-        Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
+            if digit_count == 0 { None } else { Some(result) }
+        })
     }
 
-    // Read IPv4 address
+    /// Read an IPv4 address
     fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
-        self.read_atomically(|p| p.read_ipv4_addr_impl())
-    }
+        self.read_atomically(|p| {
+            let mut groups = [0; 4];
 
-    fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
-        fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
-            assert!(head.len() + tail.len() <= 8);
-            let mut gs = [0; 8];
-            gs[..head.len()].copy_from_slice(head);
-            gs[(8 - tail.len())..8].copy_from_slice(tail);
-            Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
-        }
+            for (i, slot) in groups.iter_mut().enumerate() {
+                *slot = p.read_separator('.', i, |p| p.read_number(10, 3, 0x100))? as u8;
+            }
+
+            Some(groups.into())
+        })
+    }
 
-        fn read_groups(p: &mut Parser<'_>, groups: &mut [u16; 8], limit: usize) -> (usize, bool) {
-            let mut i = 0;
-            while i < limit {
+    /// Read an IPV6 Address
+    fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
+        /// Read a chunk of an ipv6 address into `groups`. Returns the number
+        /// of groups read, along with a bool indicating if an embedded
+        /// trailing ipv4 address was read. Specifically, read a series of
+        /// colon-separated ipv6 groups (0x0000 - 0xFFFF), with an optional
+        /// trailing embedded ipv4 address.
+        fn read_groups(p: &mut Parser<'_>, groups: &mut [u16]) -> (usize, bool) {
+            let limit = groups.len();
+
+            for (i, slot) in groups.iter_mut().enumerate() {
+                // Try to read a trailing embedded ipv4 address. There must be
+                // at least two groups left.
                 if i < limit - 1 {
-                    let ipv4 = p.read_atomically(|p| {
-                        if i == 0 || p.read_given_char(':').is_some() {
-                            p.read_ipv4_addr()
-                        } else {
-                            None
-                        }
-                    });
+                    let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr());
+
                     if let Some(v4_addr) = ipv4 {
                         let octets = v4_addr.octets();
                         groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
@@ -175,83 +144,85 @@ impl<'a> Parser<'a> {
                     }
                 }
 
-                let group = p.read_atomically(|p| {
-                    if i == 0 || p.read_given_char(':').is_some() {
-                        p.read_number(16, 4, 0x10000).map(|n| n as u16)
-                    } else {
-                        None
-                    }
-                });
+                let group = p.read_separator(':', i, |p| p.read_number(16, 4, 0x10000));
+
                 match group {
-                    Some(g) => groups[i] = g,
+                    Some(g) => *slot = g as u16,
                     None => return (i, false),
                 }
-                i += 1;
             }
-            (i, false)
+            (groups.len(), false)
         }
 
-        let mut head = [0; 8];
-        let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
+        self.read_atomically(|p| {
+            // Read the front part of the address; either the whole thing, or up
+            // to the first ::
+            let mut head = [0; 8];
+            let (head_size, head_ipv4) = read_groups(p, &mut head);
 
-        if head_size == 8 {
-            return Some(Ipv6Addr::new(
-                head[0], head[1], head[2], head[3], head[4], head[5], head[6], head[7],
-            ));
-        }
+            if head_size == 8 {
+                return Some(head.into());
+            }
 
-        // IPv4 part is not allowed before `::`
-        if head_ipv4 {
-            return None;
-        }
+            // IPv4 part is not allowed before `::`
+            if head_ipv4 {
+                return None;
+            }
 
-        // read `::` if previous code parsed less than 8 groups
-        if self.read_given_char(':').is_none() || self.read_given_char(':').is_none() {
-            return None;
-        }
+            // read `::` if previous code parsed less than 8 groups
+            // `::` indicates one or more groups of 16 bits of zeros
+            let _ = p.read_given_char(':')?;
+            let _ = p.read_given_char(':')?;
 
-        let mut tail = [0; 8];
-        // `::` indicates one or more groups of 16 bits of zeros
-        let limit = 8 - (head_size + 1);
-        let (tail_size, _) = read_groups(self, &mut tail, limit);
-        Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
-    }
+            // Read the back part of the address. The :: must contain at least one
+            // set of zeroes, so our max length is 7.
+            let mut tail = [0; 7];
+            let limit = 8 - (head_size + 1);
+            let (tail_size, _) = read_groups(p, &mut tail[..limit]);
 
-    fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
-        self.read_atomically(|p| p.read_ipv6_addr_impl())
+            // Concat the head and tail of the IP address
+            head[(8 - tail_size)..8].copy_from_slice(&tail[..tail_size]);
+
+            Some(head.into())
+        })
     }
 
+    /// Read an IP Address, either IPV4 or IPV6.
     fn read_ip_addr(&mut self) -> Option<IpAddr> {
-        self.read_ipv4_addr().map(IpAddr::V4).or_else(|| self.read_ipv6_addr().map(IpAddr::V6))
+        self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6))
     }
 
-    fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
-        let ip_addr = |p: &mut Parser<'_>| p.read_ipv4_addr();
-        let colon = |p: &mut Parser<'_>| p.read_given_char(':');
-        let port = |p: &mut Parser<'_>| p.read_number(10, 5, 0x10000).map(|n| n as u16);
+    /// Read a : followed by a port in base 10
+    fn read_port(&mut self) -> Option<u16> {
+        self.read_atomically(|p| {
+            let _ = p.read_given_char(':')?;
+            let port = p.read_number(10, 5, 0x10000)?;
+            Some(port as u16)
+        })
+    }
 
-        self.read_seq_3(ip_addr, colon, port).map(|t| {
-            let (ip, _, port): (Ipv4Addr, char, u16) = t;
-            SocketAddrV4::new(ip, port)
+    /// Read an IPV4 address with a port
+    fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
+        self.read_atomically(|p| {
+            let ip = p.read_ipv4_addr()?;
+            let port = p.read_port()?;
+            Some(SocketAddrV4::new(ip, port))
         })
     }
 
+    /// Read an IPV6 address with a port
     fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> {
-        let ip_addr = |p: &mut Parser<'_>| {
-            let open_br = |p: &mut Parser<'_>| p.read_given_char('[');
-            let ip_addr = |p: &mut Parser<'_>| p.read_ipv6_addr();
-            let clos_br = |p: &mut Parser<'_>| p.read_given_char(']');
-            p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1)
-        };
-        let colon = |p: &mut Parser<'_>| p.read_given_char(':');
-        let port = |p: &mut Parser<'_>| p.read_number(10, 5, 0x10000).map(|n| n as u16);
-
-        self.read_seq_3(ip_addr, colon, port).map(|t| {
-            let (ip, _, port): (Ipv6Addr, char, u16) = t;
-            SocketAddrV6::new(ip, port, 0, 0)
+        self.read_atomically(|p| {
+            let _ = p.read_given_char('[')?;
+            let ip = p.read_ipv6_addr()?;
+            let _ = p.read_given_char(']')?;
+
+            let port = p.read_port()?;
+            Some(SocketAddrV6::new(ip, port, 0, 0))
         })
     }
 
+    /// Read an IP address with a port
     fn read_socket_addr(&mut self) -> Option<SocketAddr> {
         self.read_socket_addr_v4()
             .map(SocketAddr::V4)
@@ -263,10 +234,7 @@ impl<'a> Parser<'a> {
 impl FromStr for IpAddr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
-        match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
-            Some(s) => Ok(s),
-            None => Err(AddrParseError(())),
-        }
+        Parser::new(s).parse_with(|p| p.read_ip_addr())
     }
 }
 
@@ -274,10 +242,7 @@ impl FromStr for IpAddr {
 impl FromStr for Ipv4Addr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
-        match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) {
-            Some(s) => Ok(s),
-            None => Err(AddrParseError(())),
-        }
+        Parser::new(s).parse_with(|p| p.read_ipv4_addr())
     }
 }
 
@@ -285,10 +250,7 @@ impl FromStr for Ipv4Addr {
 impl FromStr for Ipv6Addr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
-        match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) {
-            Some(s) => Ok(s),
-            None => Err(AddrParseError(())),
-        }
+        Parser::new(s).parse_with(|p| p.read_ipv6_addr())
     }
 }
 
@@ -296,10 +258,7 @@ impl FromStr for Ipv6Addr {
 impl FromStr for SocketAddrV4 {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
-        match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) {
-            Some(s) => Ok(s),
-            None => Err(AddrParseError(())),
-        }
+        Parser::new(s).parse_with(|p| p.read_socket_addr_v4())
     }
 }
 
@@ -307,10 +266,7 @@ impl FromStr for SocketAddrV4 {
 impl FromStr for SocketAddrV6 {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
-        match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) {
-            Some(s) => Ok(s),
-            None => Err(AddrParseError(())),
-        }
+        Parser::new(s).parse_with(|p| p.read_socket_addr_v6())
     }
 }
 
@@ -318,10 +274,7 @@ impl FromStr for SocketAddrV6 {
 impl FromStr for SocketAddr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
-        match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
-            Some(s) => Ok(s),
-            None => Err(AddrParseError(())),
-        }
+        Parser::new(s).parse_with(|p| p.read_socket_addr())
     }
 }
 
@@ -376,3 +329,146 @@ impl Error for AddrParseError {
         "invalid IP address syntax"
     }
 }
+
+#[cfg(test)]
+mod tests {
+    // FIXME: These tests are all excellent candidates for AFL fuzz testing
+    use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+    use crate::str::FromStr;
+
+    const PORT: u16 = 8080;
+
+    const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
+    const IPV4_STR: &str = "192.168.0.1";
+    const IPV4_STR_PORT: &str = "192.168.0.1:8080";
+
+    const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1);
+    const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1";
+    const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1";
+    const IPV6_STR_V4: &str = "2001:db8::192.168.0.1";
+    const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080";
+
+    #[test]
+    fn parse_ipv4() {
+        let result: Ipv4Addr = IPV4_STR.parse().unwrap();
+        assert_eq!(result, IPV4);
+
+        assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err());
+        assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err());
+        assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err());
+        assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err());
+        assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err());
+    }
+
+    #[test]
+    fn parse_ipv6() {
+        let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap();
+        assert_eq!(result, IPV6);
+
+        let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap();
+        assert_eq!(result, IPV6);
+
+        let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap();
+        assert_eq!(result, IPV6);
+
+        assert!(Ipv6Addr::from_str(IPV4_STR).is_err());
+        assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err());
+        assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err());
+    }
+
+    #[test]
+    fn parse_ip() {
+        let result: IpAddr = IPV4_STR.parse().unwrap();
+        assert_eq!(result, IpAddr::from(IPV4));
+
+        let result: IpAddr = IPV6_STR_FULL.parse().unwrap();
+        assert_eq!(result, IpAddr::from(IPV6));
+
+        let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap();
+        assert_eq!(result, IpAddr::from(IPV6));
+
+        let result: IpAddr = IPV6_STR_V4.parse().unwrap();
+        assert_eq!(result, IpAddr::from(IPV6));
+
+        assert!(IpAddr::from_str(IPV4_STR_PORT).is_err());
+        assert!(IpAddr::from_str(IPV6_STR_PORT).is_err());
+    }
+
+    #[test]
+    fn parse_socket_v4() {
+        let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap();
+        assert_eq!(result, SocketAddrV4::new(IPV4, PORT));
+
+        assert!(SocketAddrV4::from_str(IPV4_STR).is_err());
+        assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err());
+        assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err());
+        assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err());
+        assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err());
+    }
+
+    #[test]
+    fn parse_socket_v6() {
+        let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap();
+        assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0));
+
+        assert!(SocketAddrV6::from_str(IPV4_STR).is_err());
+        assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err());
+        assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err());
+        assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err());
+        assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err());
+    }
+
+    #[test]
+    fn parse_socket() {
+        let result: SocketAddr = IPV4_STR_PORT.parse().unwrap();
+        assert_eq!(result, SocketAddr::from((IPV4, PORT)));
+
+        let result: SocketAddr = IPV6_STR_PORT.parse().unwrap();
+        assert_eq!(result, SocketAddr::from((IPV6, PORT)));
+
+        assert!(SocketAddr::from_str(IPV4_STR).is_err());
+        assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err());
+        assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err());
+        assert!(SocketAddr::from_str(IPV6_STR_V4).is_err());
+    }
+
+    #[test]
+    fn ipv6_corner_cases() {
+        let result: Ipv6Addr = "1::".parse().unwrap();
+        assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0));
+
+        let result: Ipv6Addr = "1:1::".parse().unwrap();
+        assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0));
+
+        let result: Ipv6Addr = "::1".parse().unwrap();
+        assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+
+        let result: Ipv6Addr = "::1:1".parse().unwrap();
+        assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1));
+
+        let result: Ipv6Addr = "::".parse().unwrap();
+        assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+
+        let result: Ipv6Addr = "::192.168.0.1".parse().unwrap();
+        assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1));
+
+        let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap();
+        assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1));
+
+        let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap();
+        assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1));
+    }
+
+    // Things that might not seem like failures but are
+    #[test]
+    fn ipv6_corner_failures() {
+        // No IP address before the ::
+        assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err());
+
+        // :: must have at least 1 set of zeroes
+        assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err());
+
+        // Need brackets for a port
+        assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err());
+    }
+}
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index 5023d692408..47b8532b7a6 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -1,3 +1,4 @@
+#![deny(unsafe_op_in_unsafe_fn)]
 use crate::io::prelude::*;
 
 use crate::fmt;
@@ -577,8 +578,14 @@ impl Read for TcpStream {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+        // SAFETY: Read is guaranteed to work on uninitialized memory
+        unsafe { Initializer::nop() }
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -591,6 +598,11 @@ impl Write for TcpStream {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -606,8 +618,14 @@ impl Read for &TcpStream {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+        // SAFETY: Read is guaranteed to work on uninitialized memory
+        unsafe { Initializer::nop() }
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -620,6 +638,11 @@ impl Write for &TcpStream {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
diff --git a/src/libstd/num.rs b/src/libstd/num.rs
index de8acf8d9d4..b496c16a749 100644
--- a/src/libstd/num.rs
+++ b/src/libstd/num.rs
@@ -52,52 +52,43 @@ where
 #[cfg(test)]
 mod tests {
     use crate::ops::Mul;
-    use crate::u16;
-    use crate::u32;
-    use crate::u64;
-    use crate::u8;
-    use crate::usize;
 
     #[test]
     fn test_saturating_add_uint() {
-        use crate::usize::MAX;
         assert_eq!(3_usize.saturating_add(5_usize), 8_usize);
-        assert_eq!(3_usize.saturating_add(MAX - 1), MAX);
-        assert_eq!(MAX.saturating_add(MAX), MAX);
-        assert_eq!((MAX - 2).saturating_add(1), MAX - 1);
+        assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX);
+        assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX);
+        assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1);
     }
 
     #[test]
     fn test_saturating_sub_uint() {
-        use crate::usize::MAX;
         assert_eq!(5_usize.saturating_sub(3_usize), 2_usize);
         assert_eq!(3_usize.saturating_sub(5_usize), 0_usize);
         assert_eq!(0_usize.saturating_sub(1_usize), 0_usize);
-        assert_eq!((MAX - 1).saturating_sub(MAX), 0);
+        assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0);
     }
 
     #[test]
     fn test_saturating_add_int() {
-        use crate::isize::{MAX, MIN};
         assert_eq!(3i32.saturating_add(5), 8);
-        assert_eq!(3isize.saturating_add(MAX - 1), MAX);
-        assert_eq!(MAX.saturating_add(MAX), MAX);
-        assert_eq!((MAX - 2).saturating_add(1), MAX - 1);
+        assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX);
+        assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX);
+        assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1);
         assert_eq!(3i32.saturating_add(-5), -2);
-        assert_eq!(MIN.saturating_add(-1), MIN);
-        assert_eq!((-2isize).saturating_add(-MAX), MIN);
+        assert_eq!(isize::MIN.saturating_add(-1), isize::MIN);
+        assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN);
     }
 
     #[test]
     fn test_saturating_sub_int() {
-        use crate::isize::{MAX, MIN};
         assert_eq!(3i32.saturating_sub(5), -2);
-        assert_eq!(MIN.saturating_sub(1), MIN);
-        assert_eq!((-2isize).saturating_sub(MAX), MIN);
+        assert_eq!(isize::MIN.saturating_sub(1), isize::MIN);
+        assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN);
         assert_eq!(3i32.saturating_sub(-5), 8);
-        assert_eq!(3isize.saturating_sub(-(MAX - 1)), MAX);
-        assert_eq!(MAX.saturating_sub(-MAX), MAX);
-        assert_eq!((MAX - 2).saturating_sub(-1), MAX - 1);
+        assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX);
+        assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX);
+        assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1);
     }
 
     #[test]
diff --git a/src/libstd/os/illumos/fs.rs b/src/libstd/os/illumos/fs.rs
index 2abbf1fa9fa..b668aa2595d 100644
--- a/src/libstd/os/illumos/fs.rs
+++ b/src/libstd/os/illumos/fs.rs
@@ -1,7 +1,5 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
-use libc;
-
 use crate::fs::Metadata;
 use crate::sys_common::AsInner;
 
diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs
index 0caec97bb7b..eb8589eb58f 100644
--- a/src/libstd/os/linux/raw.rs
+++ b/src/libstd/os/linux/raw.rs
@@ -170,7 +170,7 @@ mod arch {
 
 #[cfg(target_arch = "hexagon")]
 mod arch {
-    use crate::os::raw::{c_int, c_long, c_longlong, culonglong};
+    use crate::os::raw::{c_int, c_long, c_longlong, c_ulonglong};
 
     #[stable(feature = "raw_ext", since = "1.1.0")]
     pub type blkcnt_t = c_longlong;
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 10078bd4aee..9542e7209b4 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -170,7 +170,7 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
 fn default_hook(info: &PanicInfo<'_>) {
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
-    let backtrace_env = if update_panic_count(0) >= 2 {
+    let backtrace_env = if panic_count::get() >= 2 {
         RustBacktrace::Print(backtrace_rs::PrintFmt::Full)
     } else {
         backtrace::rust_backtrace_env()
@@ -201,8 +201,7 @@ fn default_hook(info: &PanicInfo<'_>) {
                 if FIRST_PANIC.swap(false, Ordering::SeqCst) {
                     let _ = writeln!(
                         err,
-                        "note: run with `RUST_BACKTRACE=1` \
-                                           environment variable to display a backtrace"
+                        "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace"
                     );
                 }
             }
@@ -222,19 +221,71 @@ fn default_hook(info: &PanicInfo<'_>) {
 #[cfg(not(test))]
 #[doc(hidden)]
 #[unstable(feature = "update_panic_count", issue = "none")]
-pub fn update_panic_count(amt: isize) -> usize {
+pub mod panic_count {
     use crate::cell::Cell;
-    thread_local! { static PANIC_COUNT: Cell<usize> = Cell::new(0) }
+    use crate::sync::atomic::{AtomicUsize, Ordering};
+
+    // Panic count for the current thread.
+    thread_local! { static LOCAL_PANIC_COUNT: Cell<usize> = Cell::new(0) }
+
+    // Sum of panic counts from all threads. The purpose of this is to have
+    // a fast path in `is_zero` (which is used by `panicking`). In any particular
+    // thread, if that thread currently views `GLOBAL_PANIC_COUNT` as being zero,
+    // then `LOCAL_PANIC_COUNT` in that thread is zero. This invariant holds before
+    // and after increase and decrease, but not necessarily during their execution.
+    static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
+
+    pub fn increase() -> usize {
+        GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
+        LOCAL_PANIC_COUNT.with(|c| {
+            let next = c.get() + 1;
+            c.set(next);
+            next
+        })
+    }
+
+    pub fn decrease() -> usize {
+        GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed);
+        LOCAL_PANIC_COUNT.with(|c| {
+            let next = c.get() - 1;
+            c.set(next);
+            next
+        })
+    }
 
-    PANIC_COUNT.with(|c| {
-        let next = (c.get() as isize + amt) as usize;
-        c.set(next);
-        next
-    })
+    pub fn get() -> usize {
+        LOCAL_PANIC_COUNT.with(|c| c.get())
+    }
+
+    #[inline]
+    pub fn is_zero() -> bool {
+        if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) == 0 {
+            // Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads
+            // (including the current one) will have `LOCAL_PANIC_COUNT`
+            // equal to zero, so TLS access can be avoided.
+            //
+            // In terms of performance, a relaxed atomic load is similar to a normal
+            // aligned memory read (e.g., a mov instruction in x86), but with some
+            // compiler optimization restrictions. On the other hand, a TLS access
+            // might require calling a non-inlinable function (such as `__tls_get_addr`
+            // when using the GD TLS model).
+            true
+        } else {
+            is_zero_slow_path()
+        }
+    }
+
+    // Slow path is in a separate function to reduce the amount of code
+    // inlined from `is_zero`.
+    #[inline(never)]
+    #[cold]
+    fn is_zero_slow_path() -> bool {
+        LOCAL_PANIC_COUNT.with(|c| c.get() == 0)
+    }
 }
 
 #[cfg(test)]
-pub use realstd::rt::update_panic_count;
+pub use realstd::rt::panic_count;
 
 /// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
 pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
@@ -271,44 +322,12 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     let mut data = Data { f: ManuallyDrop::new(f) };
 
     let data_ptr = &mut data as *mut _ as *mut u8;
-    return if do_try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
+    return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
         Ok(ManuallyDrop::into_inner(data.r))
     } else {
         Err(ManuallyDrop::into_inner(data.p))
     };
 
-    // Compatibility wrapper around the try intrinsic for bootstrap.
-    //
-    // We also need to mark it #[inline(never)] to work around a bug on MinGW
-    // targets: the unwinding implementation was relying on UB, but this only
-    // becomes a problem in practice if inlining is involved.
-    #[cfg(not(bootstrap))]
-    use intrinsics::r#try as do_try;
-    #[cfg(bootstrap)]
-    #[inline(never)]
-    unsafe fn do_try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 {
-        use crate::mem::MaybeUninit;
-        #[cfg(target_env = "msvc")]
-        type TryPayload = [u64; 2];
-        #[cfg(not(target_env = "msvc"))]
-        type TryPayload = *mut u8;
-
-        let mut payload: MaybeUninit<TryPayload> = MaybeUninit::uninit();
-        let payload_ptr = payload.as_mut_ptr() as *mut u8;
-        let r = intrinsics::r#try(try_fn, data, payload_ptr);
-        if r != 0 {
-            #[cfg(target_env = "msvc")]
-            {
-                catch_fn(data, payload_ptr)
-            }
-            #[cfg(not(target_env = "msvc"))]
-            {
-                catch_fn(data, payload.assume_init())
-            }
-        }
-        r
-    }
-
     // We consider unwinding to be rare, so mark this function as cold. However,
     // do not mark it no-inline -- that decision is best to leave to the
     // optimizer (in most cases this function is not inlined even as a normal,
@@ -316,13 +335,11 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     #[cold]
     unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
         let obj = Box::from_raw(__rust_panic_cleanup(payload));
-        update_panic_count(-1);
+        panic_count::decrease();
         obj
     }
 
-    // See comment on do_try above for why #[inline(never)] is needed on bootstrap.
-    #[cfg_attr(bootstrap, inline(never))]
-    #[cfg_attr(not(bootstrap), inline)]
+    #[inline]
     fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
         unsafe {
             let data = data as *mut Data<F, R>;
@@ -347,8 +364,9 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
 }
 
 /// Determines whether the current thread is unwinding because of panic.
+#[inline]
 pub fn panicking() -> bool {
-    update_panic_count(0) != 0
+    !panic_count::is_zero()
 }
 
 /// The entry point for panicking with a formatted message.
@@ -366,7 +384,7 @@ pub fn panicking() -> bool {
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
-        unsafe { intrinsics::abort() }
+        intrinsics::abort()
     }
 
     let info = PanicInfo::internal_constructor(Some(msg), Location::caller());
@@ -432,7 +450,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
 #[track_caller]
 pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
-        unsafe { intrinsics::abort() }
+        intrinsics::abort()
     }
 
     rust_panic_with_hook(&mut PanicPayload::new(msg), None, Location::caller());
@@ -480,7 +498,7 @@ fn rust_panic_with_hook(
     message: Option<&fmt::Arguments<'_>>,
     location: &Location<'_>,
 ) -> ! {
-    let panics = update_panic_count(1);
+    let panics = panic_count::increase();
 
     // If this is the third nested call (e.g., panics == 2, this is 0-indexed),
     // the panic hook probably triggered the last panic, otherwise the
@@ -488,11 +506,8 @@ fn rust_panic_with_hook(
     // process real quickly as we don't want to try calling it again as it'll
     // probably just panic again.
     if panics > 2 {
-        util::dumb_print(format_args!(
-            "thread panicked while processing \
-                                       panic. aborting.\n"
-        ));
-        unsafe { intrinsics::abort() }
+        util::dumb_print(format_args!("thread panicked while processing panic. aborting.\n"));
+        intrinsics::abort()
     }
 
     unsafe {
@@ -523,11 +538,8 @@ fn rust_panic_with_hook(
         // have limited options. Currently our preference is to
         // just abort. In the future we may consider resuming
         // unwinding or otherwise exiting the thread cleanly.
-        util::dumb_print(format_args!(
-            "thread panicked while panicking. \
-                                       aborting.\n"
-        ));
-        unsafe { intrinsics::abort() }
+        util::dumb_print(format_args!("thread panicked while panicking. aborting.\n"));
+        intrinsics::abort()
     }
 
     rust_panic(payload)
@@ -536,7 +548,7 @@ fn rust_panic_with_hook(
 /// This is the entry point for `resume_unwind`.
 /// It just forwards the payload to the panic runtime.
 pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
-    update_panic_count(1);
+    panic_count::increase();
 
     struct RewrapBox(Box<dyn Any + Send>);
 
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 173d6d1cfa7..f14a9ff72f6 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -157,10 +157,10 @@ pub enum Prefix<'a> {
         #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
     ),
 
-    /// Verbatim disk prefix, e.g., `\\?\C:\`.
+    /// Verbatim disk prefix, e.g., `\\?\C:`.
     ///
     /// Verbatim disk prefixes consist of `\\?\` immediately followed by the
-    /// drive letter and `:\`.
+    /// drive letter and `:`.
     #[stable(feature = "rust1", since = "1.0.0")]
     VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8),
 
@@ -1433,6 +1433,17 @@ impl From<&Path> for Box<Path> {
     }
 }
 
+#[stable(feature = "box_from_cow", since = "1.45.0")]
+impl From<Cow<'_, Path>> for Box<Path> {
+    #[inline]
+    fn from(cow: Cow<'_, Path>) -> Box<Path> {
+        match cow {
+            Cow::Borrowed(path) => Box::from(path),
+            Cow::Owned(path) => Box::from(path),
+        }
+    }
+}
+
 #[stable(feature = "path_buf_from_box", since = "1.18.0")]
 impl From<Box<Path>> for PathBuf {
     /// Converts a `Box<Path>` into a `PathBuf`
@@ -1523,6 +1534,11 @@ impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
     fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
         iter.into_iter().for_each(move |p| self.push(p.as_ref()));
     }
+
+    #[inline]
+    fn extend_one(&mut self, p: P) {
+        self.push(p.as_ref());
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2487,11 +2503,20 @@ impl Path {
     /// # See Also
     ///
     /// This is a convenience function that coerces errors to false. If you want to
-    /// check errors, call [fs::metadata] and handle its Result. Then call
-    /// [fs::Metadata::is_file] if it was Ok.
-    ///
-    /// [fs::metadata]: ../../std/fs/fn.metadata.html
-    /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file
+    /// check errors, call [`fs::metadata`] and handle its Result. Then call
+    /// [`fs::Metadata::is_file`] if it was Ok.
+    ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
+    /// [`fs::metadata`]: ../../std/fs/fn.metadata.html
+    /// [`fs::Metadata`]: ../../std/fs/struct.Metadata.html
+    /// [`fs::Metadata::is_file`]: ../../std/fs/struct.Metadata.html#method.is_file
+    /// [`File::open`]: ../../std/fs/struct.File.html#method.open
+    /// [`OpenOptions::open`]: ../../std/fs/struct.OpenOptions.html#method.open
     #[stable(feature = "path_ext", since = "1.5.0")]
     pub fn is_file(&self) -> bool {
         fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs
index 3085c3d8296..48f7cf16988 100644
--- a/src/libstd/prelude/mod.rs
+++ b/src/libstd/prelude/mod.rs
@@ -10,22 +10,6 @@
 //! things, particularly traits, which are used in almost every single Rust
 //! program.
 //!
-//! On a technical level, Rust inserts
-//!
-//! ```
-//! # #[allow(unused_extern_crates)]
-//! extern crate std;
-//! ```
-//!
-//! into the crate root of every crate, and
-//!
-//! ```
-//! # #[allow(unused_imports)]
-//! use std::prelude::v1::*;
-//! ```
-//!
-//! into every module.
-//!
 //! # Other preludes
 //!
 //! Preludes can be seen as a pattern to make using multiple types more
diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs
index 92e3ea84850..0fbd6b62f18 100644
--- a/src/libstd/prelude/v1.rs
+++ b/src/libstd/prelude/v1.rs
@@ -54,7 +54,6 @@ pub use core::prelude::v1::{
     PartialEq, PartialOrd, RustcDecodable, RustcEncodable,
 };
 
-#[cfg(not(bootstrap))]
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 3eee45d000c..4ba1940fd0e 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -245,6 +245,10 @@ impl Write for ChildStdin {
         self.inner.write_vectored(bufs)
     }
 
+    fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -301,6 +305,11 @@ impl Read for ChildStdout {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
@@ -357,6 +366,11 @@ impl Read for ChildStderr {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
@@ -1606,7 +1620,7 @@ pub fn exit(code: i32) -> ! {
 /// [panic hook]: ../../std/panic/fn.set_hook.html
 #[stable(feature = "process_abort", since = "1.17.0")]
 pub fn abort() -> ! {
-    unsafe { crate::sys::abort_internal() };
+    crate::sys::abort_internal();
 }
 
 /// Returns the OS-assigned process identifier associated with this process.
@@ -2091,8 +2105,8 @@ mod tests {
     }
 
     #[test]
-    fn test_command_implements_send() {
-        fn take_send_type<T: Send>(_: T) {}
-        take_send_type(Command::new(""))
+    fn test_command_implements_send_sync() {
+        fn take_send_sync_type<T: Send + Sync>(_: T) {}
+        take_send_sync_type(Command::new(""))
     }
 }
diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs
index 2426b2dead7..fb825ab16eb 100644
--- a/src/libstd/rt.rs
+++ b/src/libstd/rt.rs
@@ -15,7 +15,7 @@
 #![doc(hidden)]
 
 // Re-export some of our utilities which are expected by other crates.
-pub use crate::panicking::{begin_panic, begin_panic_fmt, update_panic_count};
+pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
 
 // To reduce the generated code of the new `lang_start`, this function is doing
 // the real work.
diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 77e521eae9a..2250c0d4203 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -609,7 +609,6 @@ mod tests {
     use crate::sync::{Arc, Condvar, Mutex};
     use crate::thread;
     use crate::time::Duration;
-    use crate::u64;
 
     #[test]
     fn smoke() {
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index e70204d6839..d6cc811154f 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -2176,8 +2176,7 @@ mod tests {
     #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn very_long_recv_timeout_wont_panic() {
         let (tx, rx) = channel::<()>();
-        let join_handle =
-            thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::max_value())));
+        let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
         thread::sleep(Duration::from_secs(1));
         assert!(tx.send(()).is_ok());
         assert_eq!(join_handle.join().unwrap(), Ok(()));
diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs
index c4e929624d7..898654f21f2 100644
--- a/src/libstd/sync/mpsc/shared.rs
+++ b/src/libstd/sync/mpsc/shared.rs
@@ -91,7 +91,7 @@ impl<T> Packet<T> {
     //
     // This can only be called at channel-creation time
     pub fn inherit_blocker(&self, token: Option<SignalToken>, guard: MutexGuard<'_, ()>) {
-        token.map(|token| {
+        if let Some(token) = token {
             assert_eq!(self.cnt.load(Ordering::SeqCst), 0);
             assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
             self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst);
@@ -118,7 +118,7 @@ impl<T> Packet<T> {
             unsafe {
                 *self.steals.get() = -1;
             }
-        });
+        }
 
         // When the shared packet is constructed, we grabbed this lock. The
         // purpose of this lock is to ensure that abort_selection() doesn't
@@ -354,9 +354,7 @@ impl<T> Packet<T> {
 
         // See comments on Arc::clone() on why we do this (for `mem::forget`).
         if old_count > MAX_REFCOUNT {
-            unsafe {
-                abort();
-            }
+            abort();
         }
     }
 
diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs
index 26b4faebd86..9f7c1af8951 100644
--- a/src/libstd/sync/mpsc/stream.rs
+++ b/src/libstd/sync/mpsc/stream.rs
@@ -329,7 +329,7 @@ impl<T> Packet<T> {
             );
             cnt != DISCONNECTED && cnt != steals
         } {
-            while let Some(_) = self.queue.pop() {
+            while self.queue.pop().is_some() {
                 steals += 1;
             }
         }
diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs
index 3e2050799cc..733761671a0 100644
--- a/src/libstd/sync/mpsc/sync.rs
+++ b/src/libstd/sync/mpsc/sync.rs
@@ -343,8 +343,12 @@ impl<T> Packet<T> {
         mem::drop(guard);
 
         // only outside of the lock do we wake up the pending threads
-        pending_sender1.map(|t| t.signal());
-        pending_sender2.map(|t| t.signal());
+        if let Some(token) = pending_sender1 {
+            token.signal();
+        }
+        if let Some(token) = pending_sender2 {
+            token.signal();
+        }
     }
 
     // Prepares this shared packet for a channel clone, essentially just bumping
@@ -354,9 +358,7 @@ impl<T> Packet<T> {
 
         // See comments on Arc::clone() on why we do this (for `mem::forget`).
         if old_count > MAX_REFCOUNT {
-            unsafe {
-                abort();
-            }
+            abort();
         }
     }
 
@@ -410,7 +412,9 @@ impl<T> Packet<T> {
         while let Some(token) = queue.dequeue() {
             token.signal();
         }
-        waiter.map(|t| t.signal());
+        if let Some(token) = waiter {
+            token.signal();
+        }
     }
 }
 
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 0cb16b19d73..8478457eabf 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -107,7 +107,62 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
 ///
 /// *guard += 1;
 /// ```
+///
+/// It is sometimes necessary to manually drop the mutex guard to unlock it
+/// sooner than the end of the enclosing scope.
+///
+/// ```
+/// use std::sync::{Arc, Mutex};
+/// use std::thread;
+///
+/// const N: usize = 3;
+///
+/// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
+/// let res_mutex = Arc::new(Mutex::new(0));
+///
+/// let mut threads = Vec::with_capacity(N);
+/// (0..N).for_each(|_| {
+///     let data_mutex_clone = Arc::clone(&data_mutex);
+///     let res_mutex_clone = Arc::clone(&res_mutex);
+///
+///     threads.push(thread::spawn(move || {
+///         let mut data = data_mutex_clone.lock().unwrap();
+///         // This is the result of some important and long-ish work.
+///         let result = data.iter().fold(0, |acc, x| acc + x * 2);
+///         data.push(result);
+///         drop(data);
+///         *res_mutex_clone.lock().unwrap() += result;
+///     }));
+/// });
+///
+/// let mut data = data_mutex.lock().unwrap();
+/// // This is the result of some important and long-ish work.
+/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
+/// data.push(result);
+/// // We drop the `data` explicitly because it's not necessary anymore and the
+/// // thread still has work to do. This allow other threads to start working on
+/// // the data immediately, without waiting for the rest of the unrelated work
+/// // to be done here.
+/// //
+/// // It's even more important here than in the threads because we `.join` the
+/// // threads after that. If we had not dropped the mutex guard, a thread could
+/// // be waiting forever for it, causing a deadlock.
+/// drop(data);
+/// // Here the mutex guard is not assigned to a variable and so, even if the
+/// // scope does not end after this line, the mutex is still released: there is
+/// // no deadlock.
+/// *res_mutex.lock().unwrap() += result;
+///
+/// threads.into_iter().for_each(|thread| {
+///     thread
+///         .join()
+///         .expect("The thread creating or execution failed !")
+/// });
+///
+/// assert_eq!(*res_mutex.lock().unwrap(), 800);
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")]
 pub struct Mutex<T: ?Sized> {
     // Note that this mutex is in a *box*, not inlined into the struct itself.
     // Once a native mutex has been used once, its address can never change (it
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 1e6b6c430be..7dc822db3d0 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -272,7 +272,7 @@ impl Once {
     /// result in an immediate panic. If `f` panics, the `Once` will remain
     /// in a poison state. If `f` does _not_ panic, the `Once` will no
     /// longer be in a poison state and all future calls to `call_once` or
-    /// `call_one_force` will be no-ops.
+    /// `call_once_force` will be no-ops.
     ///
     /// The closure `f` is yielded a [`OnceState`] structure which can be used
     /// to query the poison status of the `Once`.
@@ -497,7 +497,7 @@ impl Drop for WaiterQueue<'_> {
             let mut queue = (state_and_queue & !STATE_MASK) as *const Waiter;
             while !queue.is_null() {
                 let next = (*queue).next;
-                let thread = (*queue).thread.replace(None).unwrap();
+                let thread = (*queue).thread.take().unwrap();
                 (*queue).signaled.store(true, Ordering::Release);
                 // ^- FIXME (maybe): This is another case of issue #55005
                 // `store()` has a potentially dangling ref to `signaled`.
diff --git a/src/libstd/sys/cloudabi/condvar.rs b/src/libstd/sys/cloudabi/condvar.rs
index 3ba51d77494..dabdc0c9b51 100644
--- a/src/libstd/sys/cloudabi/condvar.rs
+++ b/src/libstd/sys/cloudabi/condvar.rs
@@ -42,7 +42,7 @@ impl Condvar {
             let ret = abi::condvar_signal(
                 condvar as *mut abi::condvar,
                 abi::scope::PRIVATE,
-                abi::nthreads::max_value(),
+                abi::nthreads::MAX,
             );
             assert_eq!(ret, abi::errno::SUCCESS, "Failed to broadcast on condition variable");
         }
diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs
index e5f1dd98435..8dbc31472d6 100644
--- a/src/libstd/sys/cloudabi/mod.rs
+++ b/src/libstd/sys/cloudabi/mod.rs
@@ -51,7 +51,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
     }
 }
 
-pub unsafe fn abort_internal() -> ! {
+pub fn abort_internal() -> ! {
     core::intrinsics::abort();
 }
 
diff --git a/src/libstd/sys/cloudabi/shims/fs.rs b/src/libstd/sys/cloudabi/shims/fs.rs
index e6160d1457d..ecb5b51cccd 100644
--- a/src/libstd/sys/cloudabi/shims/fs.rs
+++ b/src/libstd/sys/cloudabi/shims/fs.rs
@@ -202,6 +202,10 @@ impl File {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -210,6 +214,10 @@ impl File {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn flush(&self) -> io::Result<()> {
         match self.0 {}
     }
diff --git a/src/libstd/sys/cloudabi/shims/net.rs b/src/libstd/sys/cloudabi/shims/net.rs
index 67c436fa795..375aaab405d 100644
--- a/src/libstd/sys/cloudabi/shims/net.rs
+++ b/src/libstd/sys/cloudabi/shims/net.rs
@@ -47,6 +47,10 @@ impl TcpStream {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -55,6 +59,10 @@ impl TcpStream {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         match self.0 {}
     }
diff --git a/src/libstd/sys/cloudabi/shims/pipe.rs b/src/libstd/sys/cloudabi/shims/pipe.rs
index fb14dc59101..10d0925823e 100644
--- a/src/libstd/sys/cloudabi/shims/pipe.rs
+++ b/src/libstd/sys/cloudabi/shims/pipe.rs
@@ -12,6 +12,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -20,6 +24,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn diverge(&self) -> ! {
         match self.0 {}
     }
diff --git a/src/libstd/sys/hermit/condvar.rs b/src/libstd/sys/hermit/condvar.rs
index 5b7f16ce562..132e579b3a5 100644
--- a/src/libstd/sys/hermit/condvar.rs
+++ b/src/libstd/sys/hermit/condvar.rs
@@ -12,9 +12,8 @@ impl Condvar {
         Condvar { identifier: 0 }
     }
 
-    #[inline]
     pub unsafe fn init(&mut self) {
-        // nothing to do
+        let _ = abi::init_queue(self.id());
     }
 
     pub unsafe fn notify_one(&self) {
@@ -36,7 +35,7 @@ impl Condvar {
 
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         let nanos = dur.as_nanos();
-        let nanos = cmp::min(i64::max_value() as u128, nanos);
+        let nanos = cmp::min(i64::MAX as u128, nanos);
 
         // add current task to the wait queue
         let _ = abi::add_queue(self.id(), nanos as i64);
@@ -50,7 +49,6 @@ impl Condvar {
         ret
     }
 
-    #[inline]
     pub unsafe fn destroy(&self) {
         let _ = abi::destroy_queue(self.id());
     }
diff --git a/src/libstd/sys/hermit/fs.rs b/src/libstd/sys/hermit/fs.rs
index 287a0390667..82ccab1462b 100644
--- a/src/libstd/sys/hermit/fs.rs
+++ b/src/libstd/sys/hermit/fs.rs
@@ -301,6 +301,11 @@ impl File {
         crate::io::default_read_vectored(|buf| self.read(buf), bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
@@ -309,6 +314,11 @@ impl File {
         crate::io::default_write_vectored(|buf| self.write(buf), bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
     pub fn flush(&self) -> io::Result<()> {
         Ok(())
     }
diff --git a/src/libstd/sys/hermit/mod.rs b/src/libstd/sys/hermit/mod.rs
index f739df88ea6..7bdc1be3b17 100644
--- a/src/libstd/sys/hermit/mod.rs
+++ b/src/libstd/sys/hermit/mod.rs
@@ -74,8 +74,10 @@ pub extern "C" fn floor(x: f64) -> f64 {
     unsafe { intrinsics::floorf64(x) }
 }
 
-pub unsafe fn abort_internal() -> ! {
-    abi::abort();
+pub fn abort_internal() -> ! {
+    unsafe {
+        abi::abort();
+    }
 }
 
 // FIXME: just a workaround to test the system
@@ -88,7 +90,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 #[cfg(not(test))]
 #[no_mangle]
 // NB. used by both libunwind and libpanic_abort
-pub unsafe extern "C" fn __rust_abort() {
+pub extern "C" fn __rust_abort() {
     abort_internal();
 }
 
diff --git a/src/libstd/sys/hermit/net.rs b/src/libstd/sys/hermit/net.rs
index 377c3132c5a..8a788a9265f 100644
--- a/src/libstd/sys/hermit/net.rs
+++ b/src/libstd/sys/hermit/net.rs
@@ -1,10 +1,13 @@
 use crate::convert::TryFrom;
 use crate::fmt;
 use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
-use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::str;
+use crate::sync::Arc;
 use crate::sys::hermit::abi;
+use crate::sys::hermit::abi::IpAddress::{Ipv4, Ipv6};
 use crate::sys::{unsupported, Void};
+use crate::sys_common::AsInner;
 use crate::time::Duration;
 
 /// Checks whether the HermitCore's socket interface has been started already, and
@@ -17,14 +20,33 @@ pub fn init() -> io::Result<()> {
     Ok(())
 }
 
-pub struct TcpStream(abi::Handle);
+#[derive(Debug, Clone)]
+pub struct Socket(abi::Handle);
+
+impl AsInner<abi::Handle> for Socket {
+    fn as_inner(&self) -> &abi::Handle {
+        &self.0
+    }
+}
+
+impl Drop for Socket {
+    fn drop(&mut self) {
+        let _ = abi::tcpstream::close(self.0);
+    }
+}
+
+// Arc is used to count the number of used sockets.
+// Only if all sockets are released, the drop
+// method will close the socket.
+#[derive(Clone)]
+pub struct TcpStream(Arc<Socket>);
 
 impl TcpStream {
     pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
         let addr = addr?;
 
         match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
-            Ok(handle) => Ok(TcpStream(handle)),
+            Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
             _ => {
                 Err(io::Error::new(ErrorKind::Other, "Unable to initiate a connection on a socket"))
             }
@@ -37,7 +59,7 @@ impl TcpStream {
             saddr.port(),
             Some(duration.as_millis() as u64),
         ) {
-            Ok(handle) => Ok(TcpStream(handle)),
+            Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
             _ => {
                 Err(io::Error::new(ErrorKind::Other, "Unable to initiate a connection on a socket"))
             }
@@ -45,31 +67,34 @@ impl TcpStream {
     }
 
     pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
-        abi::tcpstream::set_read_timeout(self.0, duration.map(|d| d.as_millis() as u64))
+        abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
             .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to set timeout value"))
     }
 
     pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
-        abi::tcpstream::set_write_timeout(self.0, duration.map(|d| d.as_millis() as u64))
-            .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to set timeout value"))
+        abi::tcpstream::set_write_timeout(
+            *self.0.as_inner(),
+            duration.map(|d| d.as_millis() as u64),
+        )
+        .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to set timeout value"))
     }
 
     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        let duration = abi::tcpstream::get_read_timeout(self.0)
+        let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner())
             .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to determine timeout value"))?;
 
         Ok(duration.map(|d| Duration::from_millis(d)))
     }
 
     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        let duration = abi::tcpstream::get_write_timeout(self.0)
+        let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner())
             .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to determine timeout value"))?;
 
         Ok(duration.map(|d| Duration::from_millis(d)))
     }
 
     pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
-        abi::tcpstream::peek(self.0, buf)
+        abi::tcpstream::peek(*self.0.as_inner(), buf)
             .map_err(|_| io::Error::new(ErrorKind::Other, "set_nodelay failed"))
     }
 
@@ -81,24 +106,22 @@ impl TcpStream {
         let mut size: usize = 0;
 
         for i in ioslice.iter_mut() {
-            let mut pos: usize = 0;
-
-            while pos < i.len() {
-                let ret = abi::tcpstream::read(self.0, &mut i[pos..])
-                    .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to read on socket"))?;
-
-                if ret == 0 {
-                    return Ok(size);
-                } else {
-                    size += ret;
-                    pos += ret;
-                }
+            let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..])
+                .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to read on socket"))?;
+
+            if ret != 0 {
+                size += ret;
             }
         }
 
         Ok(size)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        true
+    }
+
     pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
         self.write_vectored(&[IoSlice::new(buffer)])
     }
@@ -107,15 +130,31 @@ impl TcpStream {
         let mut size: usize = 0;
 
         for i in ioslice.iter() {
-            size += abi::tcpstream::write(self.0, i)
+            size += abi::tcpstream::write(*self.0.as_inner(), i)
                 .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to write on socket"))?;
         }
 
         Ok(size)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        Err(io::Error::new(ErrorKind::Other, "peer_addr isn't supported"))
+        let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
+            .map_err(|_| io::Error::new(ErrorKind::Other, "peer_addr failed"))?;
+
+        let saddr = match ipaddr {
+            Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
+            Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
+            _ => {
+                return Err(io::Error::new(ErrorKind::Other, "peer_addr failed"));
+            }
+        };
+
+        Ok(saddr)
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
@@ -123,34 +162,31 @@ impl TcpStream {
     }
 
     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
-        abi::tcpstream::shutdown(self.0, how as i32)
+        abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
             .map_err(|_| io::Error::new(ErrorKind::Other, "unable to shutdown socket"))
     }
 
     pub fn duplicate(&self) -> io::Result<TcpStream> {
-        let handle = abi::tcpstream::duplicate(self.0)
-            .map_err(|_| io::Error::new(ErrorKind::Other, "unable to duplicate stream"))?;
-
-        Ok(TcpStream(handle))
+        Ok(self.clone())
     }
 
     pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
-        abi::tcpstream::set_nodelay(self.0, mode)
+        abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
             .map_err(|_| io::Error::new(ErrorKind::Other, "set_nodelay failed"))
     }
 
     pub fn nodelay(&self) -> io::Result<bool> {
-        abi::tcpstream::nodelay(self.0)
+        abi::tcpstream::nodelay(*self.0.as_inner())
             .map_err(|_| io::Error::new(ErrorKind::Other, "nodelay failed"))
     }
 
     pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
-        abi::tcpstream::set_tll(self.0, tll)
+        abi::tcpstream::set_tll(*self.0.as_inner(), tll)
             .map_err(|_| io::Error::new(ErrorKind::Other, "unable to set TTL"))
     }
 
     pub fn ttl(&self) -> io::Result<u32> {
-        abi::tcpstream::get_tll(self.0)
+        abi::tcpstream::get_tll(*self.0.as_inner())
             .map_err(|_| io::Error::new(ErrorKind::Other, "unable to get TTL"))
     }
 
@@ -159,40 +195,47 @@ impl TcpStream {
     }
 
     pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
-        abi::tcpstream::set_nonblocking(self.0, mode)
+        abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode)
             .map_err(|_| io::Error::new(ErrorKind::Other, "unable to set blocking mode"))
     }
 }
 
-impl Drop for TcpStream {
-    fn drop(&mut self) {
-        let _ = abi::tcpstream::close(self.0);
-    }
-}
-
 impl fmt::Debug for TcpStream {
     fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
         Ok(())
     }
 }
 
-pub struct TcpListener(abi::Handle);
+#[derive(Clone)]
+pub struct TcpListener(SocketAddr);
 
 impl TcpListener {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-        Err(io::Error::new(ErrorKind::Other, "not supported"))
+    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        let addr = addr?;
+
+        Ok(TcpListener(*addr))
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        Err(io::Error::new(ErrorKind::Other, "not supported"))
+        Ok(self.0)
     }
 
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
-        Err(io::Error::new(ErrorKind::Other, "not supported"))
+        let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
+            .map_err(|_| io::Error::new(ErrorKind::Other, "accept failed"))?;
+        let saddr = match ipaddr {
+            Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
+            Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
+            _ => {
+                return Err(io::Error::new(ErrorKind::Other, "accept failed"));
+            }
+        };
+
+        Ok((TcpStream(Arc::new(Socket(handle))), saddr))
     }
 
     pub fn duplicate(&self) -> io::Result<TcpListener> {
-        Err(io::Error::new(ErrorKind::Other, "not supported"))
+        Ok(self.clone())
     }
 
     pub fn set_ttl(&self, _: u32) -> io::Result<()> {
diff --git a/src/libstd/sys/hermit/pipe.rs b/src/libstd/sys/hermit/pipe.rs
index fb14dc59101..10d0925823e 100644
--- a/src/libstd/sys/hermit/pipe.rs
+++ b/src/libstd/sys/hermit/pipe.rs
@@ -12,6 +12,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -20,6 +24,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn diverge(&self) -> ! {
         match self.0 {}
     }
diff --git a/src/libstd/sys/hermit/stdio.rs b/src/libstd/sys/hermit/stdio.rs
index 2eb011ccb39..f3654ee3871 100644
--- a/src/libstd/sys/hermit/stdio.rs
+++ b/src/libstd/sys/hermit/stdio.rs
@@ -10,24 +10,31 @@ impl Stdin {
     pub fn new() -> io::Result<Stdin> {
         Ok(Stdin)
     }
+}
 
-    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+impl io::Read for Stdin {
+    fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
         self.read_vectored(&mut [IoSliceMut::new(data)])
     }
 
-    pub fn read_vectored(&self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        //ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) })
-        //    .read(data)
+    fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         Ok(0)
     }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        true
+    }
 }
 
 impl Stdout {
     pub fn new() -> io::Result<Stdout> {
         Ok(Stdout)
     }
+}
 
-    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+impl io::Write for Stdout {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let len;
 
         unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
@@ -39,7 +46,7 @@ impl Stdout {
         }
     }
 
-    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+    fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         let len;
 
         unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
@@ -51,7 +58,12 @@ impl Stdout {
         }
     }
 
-    pub fn flush(&self) -> io::Result<()> {
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
 }
@@ -60,8 +72,10 @@ impl Stderr {
     pub fn new() -> io::Result<Stderr> {
         Ok(Stderr)
     }
+}
 
-    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+impl io::Write for Stderr {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let len;
 
         unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
@@ -73,7 +87,7 @@ impl Stderr {
         }
     }
 
-    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+    fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         let len;
 
         unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
@@ -85,17 +99,13 @@ impl Stderr {
         }
     }
 
-    pub fn flush(&self) -> io::Result<()> {
-        Ok(())
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
     }
-}
 
-impl io::Write for Stderr {
-    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-        (&*self).write(data)
-    }
     fn flush(&mut self) -> io::Result<()> {
-        (&*self).flush()
+        Ok(())
     }
 }
 
diff --git a/src/libstd/sys/hermit/thread.rs b/src/libstd/sys/hermit/thread.rs
index 7e3fb4c6d20..e11afed6687 100644
--- a/src/libstd/sys/hermit/thread.rs
+++ b/src/libstd/sys/hermit/thread.rs
@@ -16,25 +16,24 @@ pub struct Thread {
 unsafe impl Send for Thread {}
 unsafe impl Sync for Thread {}
 
-pub const DEFAULT_MIN_STACK_SIZE: usize = 262144;
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1 << 20;
 
 impl Thread {
     pub unsafe fn new_with_coreid(
-        _stack: usize,
+        stack: usize,
         p: Box<dyn FnOnce()>,
         core_id: isize,
     ) -> io::Result<Thread> {
         let p = Box::into_raw(box p);
-        let mut tid: Tid = u32::MAX;
-        let ret = abi::spawn(
-            &mut tid as *mut Tid,
+        let tid = abi::spawn2(
             thread_start,
-            &*p as *const _ as *const u8 as usize,
+            p as usize,
             abi::Priority::into(abi::NORMAL_PRIO),
+            stack,
             core_id,
         );
 
-        return if ret != 0 {
+        return if tid == 0 {
             // The thread failed to start and as a result p was not consumed. Therefore, it is
             // safe to reconstruct the box so that it gets deallocated.
             drop(Box::from_raw(p));
diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index 1f06c9da3a9..f61bcf06f08 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -11,7 +11,7 @@ IMAGE_BASE:
     .long 1                    /* type = NT_VERSION */
 0:  .asciz "toolchain-version" /* name */
 1:  .align 4
-2:  .long 0                    /* desc - toolchain version number, 32-bit LE */
+2:  .long 1                    /* desc - toolchain version number, 32-bit LE */
 3:  .align 4
 
 .section .rodata
@@ -26,18 +26,10 @@ IMAGE_BASE:
 .Lxsave_clear:
 .org .+24
 .Lxsave_mxcsr:
-    .int 0
+    .short 0x1f80
 
 /*  We can store a bunch of data in the gap between MXCSR and the XSAVE header */
 
-/* MXCSR initialization value for ABI */
-.Lmxcsr_init:
-    .int 0x1f80
-
-/* x87 FPU control word initialization value for ABI */
-.Lfpucw_init:
-    .int 0x037f
-
 /*  The following symbols point at read-only data that will be filled in by the */
 /*  post-linker. */
 
@@ -68,10 +60,14 @@ IMAGE_BASE:
     globvar TEXT_BASE 8
     /*  The size in bytes of enclacve text section */
     globvar TEXT_SIZE 8
-    /*  The base address (relative to enclave start) of the enclave EH_FRM_HDR section */
-    globvar EH_FRM_HDR_BASE 8
-    /*  The size in bytes of enclacve EH_FRM_HDR section */
-    globvar EH_FRM_HDR_SIZE 8
+    /*  The base address (relative to enclave start) of the enclave .eh_frame_hdr section */
+    globvar EH_FRM_HDR_OFFSET 8
+    /*  The size in bytes of enclave .eh_frame_hdr section */
+    globvar EH_FRM_HDR_LEN 8
+    /*  The base address (relative to enclave start) of the enclave .eh_frame section */
+    globvar EH_FRM_OFFSET 8
+    /*  The size in bytes of enclacve .eh_frame section */
+    globvar EH_FRM_LEN 8
 
 .org .Lxsave_clear+512
 .Lxsave_header:
@@ -177,13 +173,17 @@ sgx_entry:
     jz .Lskip_debug_init
     mov %r10,%gs:tcsls_debug_panic_buf_ptr
 .Lskip_debug_init:
+/*  reset cpu state */
+    mov %rdx, %r10
+    mov $-1, %rax
+    mov $-1, %rdx
+    xrstor .Lxsave_clear(%rip)
+    mov %r10, %rdx
+
 /*  check if returning from usercall */
     mov %gs:tcsls_last_rsp,%r11
     test %r11,%r11
     jnz .Lusercall_ret
-/*  reset user state */
-    ldmxcsr .Lmxcsr_init(%rip)
-    fldcw .Lfpucw_init(%rip)
 /*  setup stack */
     mov %gs:tcsls_tos,%rsp /*  initially, RSP is not set to the correct value */
                            /*  here. This is fixed below under "adjust stack". */
@@ -324,7 +324,9 @@ usercall:
 /*  return */
     mov %rsi,%rax /*  RAX = return value */
     /* NOP: mov %rdx,%rdx */ /*  RDX = return value */
-    ret
+    pop %r11
+    lfence
+    jmp *%r11
 
 /*
 The following functions need to be defined externally:
@@ -343,20 +345,28 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
 .global get_tcs_addr
 get_tcs_addr:
     mov %gs:tcsls_tcs_addr,%rax
-    ret
+    pop %r11
+    lfence
+    jmp *%r11
 
 .global get_tls_ptr
 get_tls_ptr:
     mov %gs:tcsls_tls_ptr,%rax
-    ret
+    pop %r11
+    lfence
+    jmp *%r11
 
 .global set_tls_ptr
 set_tls_ptr:
     mov %rdi,%gs:tcsls_tls_ptr
-    ret
+    pop %r11
+    lfence
+    jmp *%r11
 
 .global take_debug_panic_buf_ptr
 take_debug_panic_buf_ptr:
     xor %rax,%rax
     xchg %gs:tcsls_debug_panic_buf_ptr,%rax
-    ret
+    pop %r11
+    lfence
+    jmp *%r11
diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs
index 87e7a5da2b7..5ef26d4cc4d 100644
--- a/src/libstd/sys/sgx/abi/mod.rs
+++ b/src/libstd/sys/sgx/abi/mod.rs
@@ -56,6 +56,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
 // able to specify this
 #[cfg(not(test))]
 #[no_mangle]
+#[allow(improper_ctypes_definitions)]
 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
     // FIXME: how to support TLS in library mode?
     let tls = Box::new(tls::Tls::new());
diff --git a/src/libstd/sys/sgx/fd.rs b/src/libstd/sys/sgx/fd.rs
index 7da2424a642..90158030c7f 100644
--- a/src/libstd/sys/sgx/fd.rs
+++ b/src/libstd/sys/sgx/fd.rs
@@ -34,6 +34,11 @@ impl FileDesc {
         usercalls::read(self.fd, bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        true
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         usercalls::write(self.fd, &[IoSlice::new(buf)])
     }
@@ -42,6 +47,11 @@ impl FileDesc {
         usercalls::write(self.fd, bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     pub fn flush(&self) -> io::Result<()> {
         usercalls::flush(self.fd)
     }
diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs
index e6160d1457d..ecb5b51cccd 100644
--- a/src/libstd/sys/sgx/fs.rs
+++ b/src/libstd/sys/sgx/fs.rs
@@ -202,6 +202,10 @@ impl File {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -210,6 +214,10 @@ impl File {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn flush(&self) -> io::Result<()> {
         match self.0 {}
     }
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
index 83cee0cf35a..397dd496ae8 100644
--- a/src/libstd/sys/sgx/mod.rs
+++ b/src/libstd/sys/sgx/mod.rs
@@ -124,7 +124,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
     return n;
 }
 
-pub unsafe fn abort_internal() -> ! {
+pub fn abort_internal() -> ! {
     abi::usercalls::exit(true)
 }
 
@@ -133,7 +133,7 @@ pub unsafe fn abort_internal() -> ! {
 #[cfg(not(test))]
 #[no_mangle]
 // NB. used by both libunwind and libpanic_abort
-pub unsafe extern "C" fn __rust_abort() {
+pub extern "C" fn __rust_abort() {
     abort_internal();
 }
 
diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs
index bd0652ab464..666a157b09c 100644
--- a/src/libstd/sys/sgx/net.rs
+++ b/src/libstd/sys/sgx/net.rs
@@ -149,6 +149,11 @@ impl TcpStream {
         self.inner.inner.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.inner.inner.is_read_vectored()
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.inner.inner.write(buf)
     }
@@ -157,6 +162,11 @@ impl TcpStream {
         self.inner.inner.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.inner.inner.is_write_vectored()
+    }
+
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         addr_to_sockaddr(&self.peer_addr)
     }
diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs
index fb14dc59101..10d0925823e 100644
--- a/src/libstd/sys/sgx/pipe.rs
+++ b/src/libstd/sys/sgx/pipe.rs
@@ -12,6 +12,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -20,6 +24,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn diverge(&self) -> ! {
         match self.0 {}
     }
diff --git a/src/libstd/sys/unix/android.rs b/src/libstd/sys/unix/android.rs
index 8fc2599f0d7..ea05ee3d7ce 100644
--- a/src/libstd/sys/unix/android.rs
+++ b/src/libstd/sys/unix/android.rs
@@ -95,7 +95,7 @@ pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
         match ftruncate64.get() {
             Some(f) => cvt_r(|| f(fd, size as i64)).map(drop),
             None => {
-                if size > i32::max_value() as u64 {
+                if size > i32::MAX as u64 {
                     Err(io::Error::new(io::ErrorKind::InvalidInput, "cannot truncate >2GB"))
                 } else {
                     cvt_r(|| ftruncate(fd, size as i32)).map(drop)
diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs
index 4c3e8542d57..5b712e20242 100644
--- a/src/libstd/sys/unix/args.rs
+++ b/src/libstd/sys/unix/args.rs
@@ -78,19 +78,20 @@ mod imp {
     use crate::marker::PhantomData;
     use crate::os::unix::prelude::*;
     use crate::ptr;
+    use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
 
     use crate::sys_common::mutex::Mutex;
 
-    static mut ARGC: isize = 0;
-    static mut ARGV: *const *const u8 = ptr::null();
+    static ARGC: AtomicIsize = AtomicIsize::new(0);
+    static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
     // We never call `ENV_LOCK.init()`, so it is UB to attempt to
     // acquire this mutex reentrantly!
     static LOCK: Mutex = Mutex::new();
 
     unsafe fn really_init(argc: isize, argv: *const *const u8) {
         let _guard = LOCK.lock();
-        ARGC = argc;
-        ARGV = argv;
+        ARGC.store(argc, Ordering::Relaxed);
+        ARGV.store(argv as *mut _, Ordering::Relaxed);
     }
 
     #[inline(always)]
@@ -126,8 +127,8 @@ mod imp {
 
     pub unsafe fn cleanup() {
         let _guard = LOCK.lock();
-        ARGC = 0;
-        ARGV = ptr::null();
+        ARGC.store(0, Ordering::Relaxed);
+        ARGV.store(ptr::null_mut(), Ordering::Relaxed);
     }
 
     pub fn args() -> Args {
@@ -137,9 +138,11 @@ mod imp {
     fn clone() -> Vec<OsString> {
         unsafe {
             let _guard = LOCK.lock();
-            (0..ARGC)
+            let argc = ARGC.load(Ordering::Relaxed);
+            let argv = ARGV.load(Ordering::Relaxed);
+            (0..argc)
                 .map(|i| {
-                    let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
+                    let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
                     OsStringExt::from_vec(cstr.to_bytes().to_vec())
                 })
                 .collect()
@@ -205,6 +208,7 @@ mod imp {
         #[cfg(target_arch = "aarch64")]
         extern "C" {
             fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
+            #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
             #[link_name = "objc_msgSend"]
             fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
         }
@@ -212,6 +216,7 @@ mod imp {
         #[cfg(not(target_arch = "aarch64"))]
         extern "C" {
             fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
+            #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
             #[link_name = "objc_msgSend"]
             fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
         }
diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs
index b4896b7ad74..9f1847943f3 100644
--- a/src/libstd/sys/unix/condvar.rs
+++ b/src/libstd/sys/unix/condvar.rs
@@ -10,14 +10,10 @@ unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
 const TIMESPEC_MAX: libc::timespec =
-    libc::timespec { tv_sec: <libc::time_t>::max_value(), tv_nsec: 1_000_000_000 - 1 };
+    libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
 
 fn saturating_cast_to_time_t(value: u64) -> libc::time_t {
-    if value > <libc::time_t>::max_value() as u64 {
-        <libc::time_t>::max_value()
-    } else {
-        value as libc::time_t
-    }
+    if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t }
 }
 
 impl Condvar {
diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs
index 732cd677a18..2b2bbc6e9d6 100644
--- a/src/libstd/sys/unix/ext/fs.rs
+++ b/src/libstd/sys/unix/ext/fs.rs
@@ -133,7 +133,7 @@ pub trait FileExt {
     /// Note that similar to [`File::write`], it is not an error to return a
     /// short write.
     ///
-    /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
+    /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write
     ///
     /// # Examples
     ///
@@ -242,7 +242,8 @@ pub trait PermissionsExt {
     ///     let permissions = metadata.permissions();
     ///
     ///     println!("permissions: {:o}", permissions.mode());
-    ///     Ok(()) }
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "fs_ext", since = "1.1.0")]
     fn mode(&self) -> u32;
@@ -262,7 +263,8 @@ pub trait PermissionsExt {
     ///
     ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
     ///     assert_eq!(permissions.mode(), 0o644);
-    ///     Ok(()) }
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "fs_ext", since = "1.1.0")]
     fn set_mode(&mut self, mode: u32);
diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs
index 4c3cb67c9ee..ada8eaa1c97 100644
--- a/src/libstd/sys/unix/ext/net.rs
+++ b/src/libstd/sys/unix/ext/net.rs
@@ -2,11 +2,9 @@
 
 //! Unix-specific networking functionality
 
-#[cfg(unix)]
-use libc;
-
 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
 #[cfg(not(unix))]
+#[allow(non_camel_case_types)]
 mod libc {
     pub use libc::c_int;
     pub type socklen_t = u32;
@@ -614,6 +612,11 @@ impl io::Read for UnixStream {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        io::Read::is_read_vectored(&&*self)
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
@@ -630,6 +633,11 @@ impl<'a> io::Read for &'a UnixStream {
     }
 
     #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
+    #[inline]
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
@@ -645,6 +653,11 @@ impl io::Write for UnixStream {
         io::Write::write_vectored(&mut &*self, bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        io::Write::is_write_vectored(&&*self)
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         io::Write::flush(&mut &*self)
     }
@@ -660,6 +673,11 @@ impl<'a> io::Write for &'a UnixStream {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -1069,7 +1087,7 @@ impl<'a> Iterator for Incoming<'a> {
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        (usize::max_value(), None)
+        (usize::MAX, None)
     }
 }
 
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs
index fa8670b4aec..048ce24d6ba 100644
--- a/src/libstd/sys/unix/ext/process.rs
+++ b/src/libstd/sys/unix/ext/process.rs
@@ -111,7 +111,7 @@ pub trait CommandExt {
     ///
     /// Set the first process argument, `argv[0]`, to something other than the
     /// default executable path.
-    #[unstable(feature = "process_set_argv0", issue = "66510")]
+    #[stable(feature = "process_set_argv0", since = "1.45.0")]
     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
     where
         S: AsRef<OsStr>;
diff --git a/src/libstd/sys/unix/ext/raw.rs b/src/libstd/sys/unix/ext/raw.rs
index d81368a18b4..40fa53d484f 100644
--- a/src/libstd/sys/unix/ext/raw.rs
+++ b/src/libstd/sys/unix/ext/raw.rs
@@ -11,10 +11,15 @@
 #![allow(deprecated)]
 
 #[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
 pub type uid_t = u32;
+
 #[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
 pub type gid_t = u32;
+
 #[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
 pub type pid_t = i32;
 
 #[doc(inline)]
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index 1bba56e334a..c481ca8961f 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -23,11 +23,7 @@ fn max_len() -> usize {
     // intentionally showing odd behavior by rejecting any read with a size
     // larger than or equal to INT_MAX. To handle both of these the read
     // size is capped on both platforms.
-    if cfg!(target_os = "macos") {
-        <c_int>::max_value() as usize - 1
-    } else {
-        <ssize_t>::max_value() as usize
-    }
+    if cfg!(target_os = "macos") { <c_int>::MAX as usize - 1 } else { <ssize_t>::MAX as usize }
 }
 
 impl FileDesc {
@@ -58,12 +54,17 @@ impl FileDesc {
             libc::readv(
                 self.fd,
                 bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::max_value() as usize) as c_int,
+                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
             )
         })?;
         Ok(ret as usize)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        true
+    }
+
     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
         let mut me = self;
         (&mut me).read_to_end(buf)
@@ -110,12 +111,17 @@ impl FileDesc {
             libc::writev(
                 self.fd,
                 bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::max_value() as usize) as c_int,
+                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
             )
         })?;
         Ok(ret as usize)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         #[cfg(target_os = "android")]
         use super::android::cvt_pwrite64;
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index a233aa47dff..29cdbf05354 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -703,6 +703,10 @@ impl File {
             | opts.get_access_mode()?
             | opts.get_creation_mode()?
             | (opts.custom_flags as c_int & !libc::O_ACCMODE);
+        // The third argument of `open64` is documented to have type `mode_t`. On
+        // some platforms (like macOS, where `open64` is actually `open`), `mode_t` is `u16`.
+        // However, since this is a variadic function, C integer promotion rules mean that on
+        // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms).
         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
         let fd = FileDesc::new(fd);
 
@@ -828,6 +832,11 @@ impl File {
         self.0.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         self.0.read_at(buf, offset)
     }
@@ -840,6 +849,11 @@ impl File {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         self.0.write_at(buf, offset)
     }
@@ -1182,7 +1196,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     let mut written = 0u64;
     while written < len {
         let copy_result = if has_copy_file_range {
-            let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize;
+            let bytes_to_copy = cmp::min(len - written, usize::MAX as u64) as usize;
             let copy_result = unsafe {
                 // We actually don't have to adjust the offsets,
                 // because copy_file_range adjusts the file offset automatically
diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs
index c6e4f5693ed..a2912387108 100644
--- a/src/libstd/sys/unix/l4re.rs
+++ b/src/libstd/sys/unix/l4re.rs
@@ -55,6 +55,10 @@ pub mod net {
             unimpl!();
         }
 
+        pub fn is_read_vectored(&self) -> bool {
+            unimpl!();
+        }
+
         pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
             unimpl!();
         }
@@ -75,6 +79,10 @@ pub mod net {
             unimpl!();
         }
 
+        pub fn is_write_vectored(&self) -> bool {
+            unimpl!();
+        }
+
         pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
             unimpl!();
         }
@@ -171,6 +179,10 @@ pub mod net {
             unimpl!();
         }
 
+        pub fn is_read_vectored(&self) -> bool {
+            unimpl!();
+        }
+
         pub fn write(&self, _: &[u8]) -> io::Result<usize> {
             unimpl!();
         }
@@ -179,6 +191,10 @@ pub mod net {
             unimpl!();
         }
 
+        pub fn is_write_vectored(&self) -> bool {
+            unimpl!();
+        }
+
         pub fn peer_addr(&self) -> io::Result<SocketAddr> {
             unimpl!();
         }
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 0154609d939..b1688e74173 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -163,6 +163,6 @@ where
 // understandable error message like "Abort trap" rather than "Illegal
 // instruction" that intrinsics::abort would cause, as intrinsics::abort is
 // implemented as an illegal instruction.
-pub unsafe fn abort_internal() -> ! {
-    libc::abort()
+pub fn abort_internal() -> ! {
+    unsafe { libc::abort() }
 }
diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs
index 103d87e3d2f..45c600f75f5 100644
--- a/src/libstd/sys/unix/mutex.rs
+++ b/src/libstd/sys/unix/mutex.rs
@@ -28,14 +28,20 @@ impl Mutex {
         //
         // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
         // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you
-        // try to re-lock it from the same thread when you already hold a lock.
+        // try to re-lock it from the same thread when you already hold a lock
+        // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html).
+        // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL
+        // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521) -- in that
+        // case, `pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT)` will of course be the same
+        // as setting it to `PTHREAD_MUTEX_NORMAL`, but not setting any mode will result in
+        // a Mutex where re-locking is UB.
         //
         // In practice, glibc takes advantage of this undefined behavior to
         // implement hardware lock elision, which uses hardware transactional
         // memory to avoid acquiring the lock. While a transaction is in
         // progress, the lock appears to be unlocked. This isn't a problem for
         // other threads since the transactional memory will abort if a conflict
-        // is detected, however no abort is generated if re-locking from the
+        // is detected, however no abort is generated when re-locking from the
         // same thread.
         //
         // Since locking the same mutex twice will result in two aliasing &mut
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index d18c22b0573..3717c660b57 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -148,7 +148,7 @@ impl Socket {
                 timeout = 1;
             }
 
-            let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int;
+            let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
 
             match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
                 -1 => {
@@ -226,6 +226,11 @@ impl Socket {
         self.0.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
     fn recv_from_with_flags(
         &self,
         buf: &mut [u8],
@@ -263,6 +268,11 @@ impl Socket {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
         let timeout = match dur {
             Some(dur) => {
@@ -273,8 +283,8 @@ impl Socket {
                     ));
                 }
 
-                let secs = if dur.as_secs() > libc::time_t::max_value() as u64 {
-                    libc::time_t::max_value()
+                let secs = if dur.as_secs() > libc::time_t::MAX as u64 {
+                    libc::time_t::MAX
                 } else {
                     dur.as_secs() as libc::time_t
                 };
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index 2a861c87801..f2a2eabef91 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -64,6 +64,11 @@ impl AnonPipe {
         self.0.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
@@ -72,6 +77,11 @@ impl AnonPipe {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     pub fn fd(&self) -> &FileDesc {
         &self.0
     }
diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs
index 859da691ad2..6e33cdd3c48 100644
--- a/src/libstd/sys/unix/process/process_common.rs
+++ b/src/libstd/sys/unix/process/process_common.rs
@@ -86,11 +86,13 @@ pub struct Command {
     stderr: Option<Stdio>,
 }
 
-// Create a new type for argv, so that we can make it `Send`
+// Create a new type for argv, so that we can make it `Send` and `Sync`
 struct Argv(Vec<*const c_char>);
 
-// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
+// It is safe to make `Argv` `Send` and `Sync`, because it contains
+// pointers to memory owned by `Command.args`
 unsafe impl Send for Argv {}
+unsafe impl Sync for Argv {}
 
 // passed back to std::process with the pipes connected to the child, if any
 // were requested
@@ -426,6 +428,7 @@ mod tests {
     // ignored there.
     #[cfg_attr(target_arch = "arm", ignore)]
     #[cfg_attr(target_arch = "aarch64", ignore)]
+    #[cfg_attr(target_arch = "riscv64", ignore)]
     fn test_process_mask() {
         unsafe {
             // Test to make sure that a signal mask does not get inherited.
diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs
index 079dea671ef..2b5067a34f6 100644
--- a/src/libstd/sys/unix/rwlock.rs
+++ b/src/libstd/sys/unix/rwlock.rs
@@ -22,32 +22,33 @@ impl RWLock {
     pub unsafe fn read(&self) {
         let r = libc::pthread_rwlock_rdlock(self.inner.get());
 
-        // According to the pthread_rwlock_rdlock spec, this function **may**
-        // fail with EDEADLK if a deadlock is detected. On the other hand
-        // pthread mutexes will *never* return EDEADLK if they are initialized
-        // as the "fast" kind (which ours always are). As a result, a deadlock
-        // situation may actually return from the call to pthread_rwlock_rdlock
-        // instead of blocking forever (as mutexes and Windows rwlocks do). Note
-        // that not all unix implementations, however, will return EDEADLK for
-        // their rwlocks.
+        // According to POSIX, when a thread tries to acquire this read lock
+        // while it already holds the write lock
+        // (or vice versa, or tries to acquire the write lock twice),
+        // "the call shall either deadlock or return [EDEADLK]"
+        // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html,
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html).
+        // So, in principle, all we have to do here is check `r == 0` to be sure we properly
+        // got the lock.
         //
-        // We roughly maintain the deadlocking behavior by panicking to ensure
-        // that this lock acquisition does not succeed.
-        //
-        // We also check whether this lock is already write locked. This
-        // is only possible if it was write locked by the current thread and
-        // the implementation allows recursive locking. The POSIX standard
-        // doesn't require recursively locking a rwlock to deadlock, but we can't
-        // allow that because it could lead to aliasing issues.
+        // However, (at least) glibc before version 2.25 does not conform to this spec,
+        // and can return `r == 0` even when this thread already holds the write lock.
+        // We thus check for this situation ourselves and panic when detecting that a thread
+        // got the write lock more than once, or got a read and a write lock.
         if r == libc::EAGAIN {
             panic!("rwlock maximum reader count exceeded");
         } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) {
+            // Above, we make sure to only access `write_locked` when `r == 0` to avoid
+            // data races.
             if r == 0 {
+                // `pthread_rwlock_rdlock` succeeded when it should not have.
                 self.raw_unlock();
             }
             panic!("rwlock read lock would result in deadlock");
         } else {
-            assert_eq!(r, 0);
+            // According to POSIX, for a properly initialized rwlock this can only
+            // return EAGAIN or EDEADLK or 0. We rely on that.
+            debug_assert_eq!(r, 0);
             self.num_readers.fetch_add(1, Ordering::Relaxed);
         }
     }
@@ -56,6 +57,7 @@ impl RWLock {
         let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
         if r == 0 {
             if *self.write_locked.get() {
+                // `pthread_rwlock_tryrdlock` succeeded when it should not have.
                 self.raw_unlock();
                 false
             } else {
@@ -69,17 +71,22 @@ impl RWLock {
     #[inline]
     pub unsafe fn write(&self) {
         let r = libc::pthread_rwlock_wrlock(self.inner.get());
-        // See comments above for why we check for EDEADLK and write_locked. We
-        // also need to check that num_readers is 0.
+        // See comments above for why we check for EDEADLK and write_locked. For the same reason,
+        // we also need to check that there are no readers (tracked in `num_readers`).
         if r == libc::EDEADLK
-            || *self.write_locked.get()
+            || (r == 0 && *self.write_locked.get())
             || self.num_readers.load(Ordering::Relaxed) != 0
         {
+            // Above, we make sure to only access `write_locked` when `r == 0` to avoid
+            // data races.
             if r == 0 {
+                // `pthread_rwlock_wrlock` succeeded when it should not have.
                 self.raw_unlock();
             }
             panic!("rwlock write lock would result in deadlock");
         } else {
+            // According to POSIX, for a properly initialized rwlock this can only
+            // return EDEADLK or 0. We rely on that.
             debug_assert_eq!(r, 0);
         }
         *self.write_locked.get() = true;
@@ -89,6 +96,7 @@ impl RWLock {
         let r = libc::pthread_rwlock_trywrlock(self.inner.get());
         if r == 0 {
             if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
+                // `pthread_rwlock_trywrlock` succeeded when it should not have.
                 self.raw_unlock();
                 false
             } else {
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index 5e103578350..c74fc2b5903 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -48,6 +48,7 @@ mod imp {
     use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
     use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};
 
+    use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
     use crate::sys::unix::os::page_size;
     use crate::sys_common::thread_info;
 
@@ -113,8 +114,8 @@ mod imp {
         }
     }
 
-    static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
-    static mut NEED_ALTSTACK: bool = false;
+    static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
+    static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);
 
     pub unsafe fn init() {
         let mut action: sigaction = mem::zeroed();
@@ -125,17 +126,17 @@ mod imp {
                 action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                 action.sa_sigaction = signal_handler as sighandler_t;
                 sigaction(signal, &action, ptr::null_mut());
-                NEED_ALTSTACK = true;
+                NEED_ALTSTACK.store(true, Ordering::Relaxed);
             }
         }
 
         let handler = make_handler();
-        MAIN_ALTSTACK = handler._data;
+        MAIN_ALTSTACK.store(handler._data, Ordering::Relaxed);
         mem::forget(handler);
     }
 
     pub unsafe fn cleanup() {
-        Handler { _data: MAIN_ALTSTACK };
+        Handler { _data: MAIN_ALTSTACK.load(Ordering::Relaxed) };
     }
 
     unsafe fn get_stackp() -> *mut libc::c_void {
@@ -176,7 +177,7 @@ mod imp {
     }
 
     pub unsafe fn make_handler() -> Handler {
-        if !NEED_ALTSTACK {
+        if !NEED_ALTSTACK.load(Ordering::Relaxed) {
             return Handler::null();
         }
         let mut stack = mem::zeroed();
diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs
index b9c56963885..f8353214cbc 100644
--- a/src/libstd/sys/unix/stdio.rs
+++ b/src/libstd/sys/unix/stdio.rs
@@ -20,6 +20,11 @@ impl io::Read for Stdin {
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs)
     }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        true
+    }
 }
 
 impl Stdout {
@@ -37,6 +42,11 @@ impl io::Write for Stdout {
         ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
@@ -57,6 +67,11 @@ impl io::Write for Stderr {
         ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs)
     }
 
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index 895ea48e2b4..c1bda6b430e 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -171,7 +171,7 @@ impl Thread {
         unsafe {
             while secs > 0 || nsecs > 0 {
                 let mut ts = libc::timespec {
-                    tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
+                    tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
                     tv_nsec: nsecs,
                 };
                 secs -= ts.tv_sec as u64;
@@ -246,10 +246,11 @@ pub mod guard {
     use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
 
     use crate::ops::Range;
+    use crate::sync::atomic::{AtomicUsize, Ordering};
     use crate::sys::os;
 
     // This is initialized in init() and only read from after
-    static mut PAGE_SIZE: usize = 0;
+    static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
 
     pub type Guard = Range<usize>;
 
@@ -275,7 +276,7 @@ pub mod guard {
 
         let stackaddr = if libc::pthread_main_np() == 1 {
             // main thread
-            current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE
+            current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
         } else {
             // new thread
             current_stack.ss_sp as usize - current_stack.ss_size
@@ -310,7 +311,8 @@ pub mod guard {
 
     // Precondition: PAGE_SIZE is initialized.
     unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
-        assert!(PAGE_SIZE != 0);
+        let page_size = PAGE_SIZE.load(Ordering::Relaxed);
+        assert!(page_size != 0);
         let stackaddr = get_stack_start()?;
 
         // Ensure stackaddr is page aligned! A parent process might
@@ -319,16 +321,17 @@ pub mod guard {
         // stackaddr < stackaddr + stacksize, so if stackaddr is not
         // page-aligned, calculate the fix such that stackaddr <
         // new_page_aligned_stackaddr < stackaddr + stacksize
-        let remainder = (stackaddr as usize) % PAGE_SIZE;
+        let remainder = (stackaddr as usize) % page_size;
         Some(if remainder == 0 {
             stackaddr
         } else {
-            ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void
+            ((stackaddr as usize) + page_size - remainder) as *mut libc::c_void
         })
     }
 
     pub unsafe fn init() -> Option<Guard> {
-        PAGE_SIZE = os::page_size();
+        let page_size = os::page_size();
+        PAGE_SIZE.store(page_size, Ordering::Relaxed);
 
         let stackaddr = get_stack_start_aligned()?;
 
@@ -344,7 +347,7 @@ pub mod guard {
             // faulting, so our handler can report "stack overflow", and
             // trust that the kernel's own stack guard will work.
             let stackaddr = stackaddr as usize;
-            Some(stackaddr - PAGE_SIZE..stackaddr)
+            Some(stackaddr - page_size..stackaddr)
         } else {
             // Reallocate the last page of the stack.
             // This ensures SIGBUS will be raised on
@@ -356,7 +359,7 @@ pub mod guard {
             // no permissions at all. See issue #50313.
             let result = mmap(
                 stackaddr,
-                PAGE_SIZE,
+                page_size,
                 PROT_READ | PROT_WRITE,
                 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                 -1,
@@ -366,7 +369,7 @@ pub mod guard {
                 panic!("failed to allocate a guard page");
             }
 
-            let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE);
+            let result = mprotect(stackaddr, page_size, PROT_NONE);
             if result != 0 {
                 panic!("failed to protect the guard page");
             }
@@ -374,14 +377,14 @@ pub mod guard {
             let guardaddr = stackaddr as usize;
             let offset = if cfg!(target_os = "freebsd") { 2 } else { 1 };
 
-            Some(guardaddr..guardaddr + offset * PAGE_SIZE)
+            Some(guardaddr..guardaddr + offset * page_size)
         }
     }
 
     #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
     pub unsafe fn current() -> Option<Guard> {
         let stackaddr = get_stack_start()? as usize;
-        Some(stackaddr - PAGE_SIZE..stackaddr)
+        Some(stackaddr - PAGE_SIZE.load(Ordering::Relaxed)..stackaddr)
     }
 
     #[cfg(any(
@@ -413,7 +416,7 @@ pub mod guard {
             ret = if cfg!(target_os = "freebsd") {
                 // FIXME does freebsd really fault *below* the guard addr?
                 let guardaddr = stackaddr - guardsize;
-                Some(guardaddr - PAGE_SIZE..guardaddr)
+                Some(guardaddr - PAGE_SIZE.load(Ordering::Relaxed)..guardaddr)
             } else if cfg!(target_os = "netbsd") {
                 Some(stackaddr - guardsize..stackaddr)
             } else if cfg!(all(target_os = "linux", target_env = "gnu")) {
diff --git a/src/libstd/sys/vxworks/args.rs b/src/libstd/sys/vxworks/args.rs
index efd615f404d..adff6c489bb 100644
--- a/src/libstd/sys/vxworks/args.rs
+++ b/src/libstd/sys/vxworks/args.rs
@@ -56,7 +56,6 @@ mod imp {
     use crate::ffi::{CStr, OsString};
     use crate::marker::PhantomData;
     use crate::ptr;
-    use libc;
 
     use crate::sys_common::mutex::Mutex;
 
diff --git a/src/libstd/sys/vxworks/condvar.rs b/src/libstd/sys/vxworks/condvar.rs
index f2a1d681529..5a77966d974 100644
--- a/src/libstd/sys/vxworks/condvar.rs
+++ b/src/libstd/sys/vxworks/condvar.rs
@@ -10,14 +10,10 @@ unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
 const TIMESPEC_MAX: libc::timespec =
-    libc::timespec { tv_sec: <libc::time_t>::max_value(), tv_nsec: 1_000_000_000 - 1 };
+    libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
 
 fn saturating_cast_to_time_t(value: u64) -> libc::time_t {
-    if value > <libc::time_t>::max_value() as u64 {
-        <libc::time_t>::max_value()
-    } else {
-        value as libc::time_t
-    }
+    if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t }
 }
 
 impl Condvar {
diff --git a/src/libstd/sys/vxworks/ext/fs.rs b/src/libstd/sys/vxworks/ext/fs.rs
index 9864a855df7..b479fbaf346 100644
--- a/src/libstd/sys/vxworks/ext/fs.rs
+++ b/src/libstd/sys/vxworks/ext/fs.rs
@@ -6,7 +6,6 @@ use crate::path::Path;
 use crate::sys;
 use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-use libc;
 
 /// Unix-specific extensions to [`File`].
 ///
@@ -133,7 +132,7 @@ pub trait FileExt {
     /// Note that similar to [`File::write`], it is not an error to return a
     /// short write.
     ///
-    /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
+    /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write
     ///
     /// # Examples
     ///
diff --git a/src/libstd/sys/vxworks/ext/process.rs b/src/libstd/sys/vxworks/ext/process.rs
index 31e691dd136..c3710f4b912 100644
--- a/src/libstd/sys/vxworks/ext/process.rs
+++ b/src/libstd/sys/vxworks/ext/process.rs
@@ -111,7 +111,7 @@ pub trait CommandExt {
     ///
     /// Set the first process argument, `argv[0]`, to something other than the
     /// default executable path.
-    #[unstable(feature = "process_set_argv0", issue = "66510")]
+    #[stable(feature = "process_set_argv0", since = "1.45.0")]
     fn arg0<S>(&mut self, arg: S) -> &mut process::Command
     where
         S: AsRef<OsStr>;
diff --git a/src/libstd/sys/vxworks/fd.rs b/src/libstd/sys/vxworks/fd.rs
index 65c67dabc1a..7fa86f0db04 100644
--- a/src/libstd/sys/vxworks/fd.rs
+++ b/src/libstd/sys/vxworks/fd.rs
@@ -17,7 +17,7 @@ fn max_len() -> usize {
     // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
     // with the man page quoting that if the count of bytes to read is
     // greater than `SSIZE_MAX` the result is "unspecified".
-    <ssize_t>::max_value() as usize
+    <ssize_t>::MAX as usize
 }
 
 impl FileDesc {
@@ -48,12 +48,17 @@ impl FileDesc {
             libc::readv(
                 self.fd,
                 bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::max_value() as usize) as c_int,
+                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
             )
         })?;
         Ok(ret as usize)
     }
 
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        true
+    }
+
     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
         let mut me = self;
         (&mut me).read_to_end(buf)
@@ -93,12 +98,17 @@ impl FileDesc {
             libc::writev(
                 self.fd,
                 bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::max_value() as usize) as c_int,
+                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
             )
         })?;
         Ok(ret as usize)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         unsafe fn cvt_pwrite(
             fd: c_int,
diff --git a/src/libstd/sys/vxworks/fs.rs b/src/libstd/sys/vxworks/fs.rs
index 68f2c133170..557e65ca01b 100644
--- a/src/libstd/sys/vxworks/fs.rs
+++ b/src/libstd/sys/vxworks/fs.rs
@@ -351,6 +351,11 @@ impl File {
         self.0.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         self.0.read_at(buf, offset)
     }
@@ -363,6 +368,11 @@ impl File {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         self.0.write_at(buf, offset)
     }
diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs
index e23191c9431..0787e709898 100644
--- a/src/libstd/sys/vxworks/mod.rs
+++ b/src/libstd/sys/vxworks/mod.rs
@@ -108,6 +108,6 @@ where
 // understandable error message like "Abort trap" rather than "Illegal
 // instruction" that intrinsics::abort would cause, as intrinsics::abort is
 // implemented as an illegal instruction.
-pub unsafe fn abort_internal() -> ! {
-    libc::abort()
+pub fn abort_internal() -> ! {
+    unsafe { libc::abort() }
 }
diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs
index 7d4e5624f7e..32c27ab6e9e 100644
--- a/src/libstd/sys/vxworks/net.rs
+++ b/src/libstd/sys/vxworks/net.rs
@@ -107,7 +107,7 @@ impl Socket {
                 timeout = 1;
             }
 
-            let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int;
+            let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
 
             match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
                 -1 => {
@@ -163,6 +163,11 @@ impl Socket {
         self.0.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
     fn recv_from_with_flags(
         &self,
         buf: &mut [u8],
@@ -200,6 +205,11 @@ impl Socket {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
         let timeout = match dur {
             Some(dur) => {
@@ -210,8 +220,8 @@ impl Socket {
                     ));
                 }
 
-                let secs = if dur.as_secs() > libc::time_t::max_value() as u64 {
-                    libc::time_t::max_value()
+                let secs = if dur.as_secs() > libc::time_t::MAX as u64 {
+                    libc::time_t::MAX
                 } else {
                     dur.as_secs() as libc::time_t
                 };
diff --git a/src/libstd/sys/vxworks/pipe.rs b/src/libstd/sys/vxworks/pipe.rs
index 0990cb8e83c..a18376212af 100644
--- a/src/libstd/sys/vxworks/pipe.rs
+++ b/src/libstd/sys/vxworks/pipe.rs
@@ -24,10 +24,16 @@ impl AnonPipe {
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         self.0.read(buf)
     }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.0.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
@@ -36,6 +42,11 @@ impl AnonPipe {
         self.0.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
     pub fn fd(&self) -> &FileDesc {
         &self.0
     }
diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs
index 6d5506bec5f..78b6e9a4db7 100644
--- a/src/libstd/sys/vxworks/process/process_common.rs
+++ b/src/libstd/sys/vxworks/process/process_common.rs
@@ -49,11 +49,13 @@ pub struct Command {
     stderr: Option<Stdio>,
 }
 
-// Create a new type for argv, so that we can make it `Send`
+// Create a new type for `Argv`, so that we can make it `Send` and `Sync`
 struct Argv(Vec<*const c_char>);
 
-// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
+// It is safe to make `Argv` `Send` and `Sync`, because it contains
+// pointers to memory owned by `Command.args`
 unsafe impl Send for Argv {}
+unsafe impl Sync for Argv {}
 
 // passed back to std::process with the pipes connected to the child, if any
 // were requested
diff --git a/src/libstd/sys/vxworks/rand.rs b/src/libstd/sys/vxworks/rand.rs
index 87ebd2c9593..3a1ff5fd3b9 100644
--- a/src/libstd/sys/vxworks/rand.rs
+++ b/src/libstd/sys/vxworks/rand.rs
@@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 mod imp {
     use crate::io;
     use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
-    use libc;
 
     pub fn fill_bytes(v: &mut [u8]) {
         static RNG_INIT: AtomicBool = AtomicBool::new(false);
diff --git a/src/libstd/sys/vxworks/rwlock.rs b/src/libstd/sys/vxworks/rwlock.rs
index fd2e1a6e7bc..c90304c2b4a 100644
--- a/src/libstd/sys/vxworks/rwlock.rs
+++ b/src/libstd/sys/vxworks/rwlock.rs
@@ -1,6 +1,5 @@
 use crate::cell::UnsafeCell;
 use crate::sync::atomic::{AtomicUsize, Ordering};
-use libc;
 
 pub struct RWLock {
     inner: UnsafeCell<libc::pthread_rwlock_t>,
diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs
index 4d0196e4b4d..24a2e0f965d 100644
--- a/src/libstd/sys/vxworks/thread.rs
+++ b/src/libstd/sys/vxworks/thread.rs
@@ -96,7 +96,7 @@ impl Thread {
         unsafe {
             while secs > 0 || nsecs > 0 {
                 let mut ts = libc::timespec {
-                    tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
+                    tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
                     tv_nsec: nsecs,
                 };
                 secs -= ts.tv_sec as u64;
diff --git a/src/libstd/sys/vxworks/time.rs b/src/libstd/sys/vxworks/time.rs
index 8ebbf89213f..8365c9ee9c9 100644
--- a/src/libstd/sys/vxworks/time.rs
+++ b/src/libstd/sys/vxworks/time.rs
@@ -1,7 +1,6 @@
 use crate::cmp::Ordering;
 use crate::time::Duration;
 use ::core::hash::{Hash, Hasher};
-use libc;
 
 pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
 use crate::convert::TryInto;
@@ -104,7 +103,6 @@ mod inner {
     use crate::fmt;
     use crate::sys::cvt;
     use crate::time::Duration;
-    use libc;
 
     use super::Timespec;
 
diff --git a/src/libstd/sys/wasi/alloc.rs b/src/libstd/sys/wasi/alloc.rs
index bc614162784..57187851a14 100644
--- a/src/libstd/sys/wasi/alloc.rs
+++ b/src/libstd/sys/wasi/alloc.rs
@@ -1,7 +1,6 @@
 use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ptr;
 use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
-use libc;
 
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
 unsafe impl GlobalAlloc for System {
diff --git a/src/libstd/sys/wasi/ext/fs.rs b/src/libstd/sys/wasi/ext/fs.rs
index 6696efa8871..f41c6626ccf 100644
--- a/src/libstd/sys/wasi/ext/fs.rs
+++ b/src/libstd/sys/wasi/ext/fs.rs
@@ -21,11 +21,102 @@ pub trait FileExt {
     ///
     /// The current file cursor is not affected by this function.
     ///
+    /// Note that similar to [`File::read`], it is not an error to return with a
+    /// short read.
+    ///
+    /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read
+    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        let bufs = &mut [IoSliceMut::new(buf)];
+        self.read_vectored_at(bufs, offset)
+    }
+
+    /// Reads a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes read.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
     /// Note that similar to [`File::read_vectored`], it is not an error to
     /// return with a short read.
     ///
     /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read_vectored
-    fn read_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
+    fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
+
+    /// Reads the exact number of byte required to fill `buf` from the given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+    ///
+    /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
+    /// [`read_at`]: #tymethod.read_at
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If this function encounters an "end of file" before completely filling
+    /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+    /// The contents of `buf` are unspecified in this case.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. The contents of `buf` are unspecified in this case.
+    ///
+    /// If this function returns an error, it is unspecified how many bytes it
+    /// has read, but it will never read more than would be necessary to
+    /// completely fill the buffer.
+    ///
+    /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
+    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.read_at(buf, offset) {
+                Ok(0) => break,
+                Ok(n) => {
+                    let tmp = buf;
+                    buf = &mut tmp[n..];
+                    offset += n as u64;
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        if !buf.is_empty() {
+            Err(io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Writes a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes written.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// When writing beyond the end of the file, the file is appropriately
+    /// extended and the intermediate bytes are initialized with the value 0.
+    ///
+    /// Note that similar to [`File::write`], it is not an error to return a
+    /// short write.
+    ///
+    /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        let bufs = &[IoSlice::new(buf)];
+        self.write_vectored_at(bufs, offset)
+    }
 
     /// Writes a number of bytes starting from a given offset.
     ///
@@ -43,7 +134,49 @@ pub trait FileExt {
     /// short write.
     ///
     /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write_vectored
-    fn write_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>;
+    fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>;
+
+    /// Attempts to write an entire buffer starting from a given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// This method will continuously call [`write_at`] until there is no more data
+    /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+    /// returned. This method will not return until the entire buffer has been
+    /// successfully written or such an error occurs. The first error that is
+    /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+    /// returned.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the first error of
+    /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
+    ///
+    /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`write_at`]: #tymethod.write_at
+    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.write_at(buf, offset) {
+                Ok(0) => {
+                    return Err(io::Error::new(
+                        io::ErrorKind::WriteZero,
+                        "failed to write whole buffer",
+                    ));
+                }
+                Ok(n) => {
+                    buf = &buf[n..];
+                    offset += n as u64
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
 
     /// Returns the current position within the file.
     ///
@@ -105,11 +238,11 @@ pub trait FileExt {
 // FIXME: bind random_get maybe? - on crates.io for unix
 
 impl FileExt for fs::File {
-    fn read_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+    fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
         self.as_inner().fd().pread(bufs, offset)
     }
 
-    fn write_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+    fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
         self.as_inner().fd().pwrite(bufs, offset)
     }
 
diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs
index a11f61fdd69..793daea43c2 100644
--- a/src/libstd/sys/wasi/fs.rs
+++ b/src/libstd/sys/wasi/fs.rs
@@ -399,6 +399,11 @@ impl File {
         self.fd.read(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        true
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.write_vectored(&[IoSlice::new(buf)])
     }
@@ -407,6 +412,11 @@ impl File {
         self.fd.write(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     pub fn flush(&self) -> io::Result<()> {
         Ok(())
     }
diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs
index 241d499ca3b..4fe9661421b 100644
--- a/src/libstd/sys/wasi/mod.rs
+++ b/src/libstd/sys/wasi/mod.rs
@@ -64,7 +64,7 @@ pub fn unsupported_err() -> std_io::Error {
 
 pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
     use std_io::ErrorKind::*;
-    if errno > u16::max_value() as i32 || errno < 0 {
+    if errno > u16::MAX as i32 || errno < 0 {
         return Other;
     }
     match errno as u16 {
@@ -100,8 +100,8 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
     return n;
 }
 
-pub unsafe fn abort_internal() -> ! {
-    libc::abort()
+pub fn abort_internal() -> ! {
+    unsafe { libc::abort() }
 }
 
 pub fn hashmap_random_keys() -> (u64, u64) {
diff --git a/src/libstd/sys/wasi/net.rs b/src/libstd/sys/wasi/net.rs
index 8a69028ff1d..e186453588d 100644
--- a/src/libstd/sys/wasi/net.rs
+++ b/src/libstd/sys/wasi/net.rs
@@ -48,6 +48,10 @@ impl TcpStream {
         unsupported()
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        true
+    }
+
     pub fn write(&self, _: &[u8]) -> io::Result<usize> {
         unsupported()
     }
@@ -56,6 +60,10 @@ impl TcpStream {
         unsupported()
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         unsupported()
     }
diff --git a/src/libstd/sys/wasi/pipe.rs b/src/libstd/sys/wasi/pipe.rs
index fb14dc59101..10d0925823e 100644
--- a/src/libstd/sys/wasi/pipe.rs
+++ b/src/libstd/sys/wasi/pipe.rs
@@ -12,6 +12,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -20,6 +24,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn diverge(&self) -> ! {
         match self.0 {}
     }
diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs
index 1d53884f2d6..78e3911dc4e 100644
--- a/src/libstd/sys/wasi/stdio.rs
+++ b/src/libstd/sys/wasi/stdio.rs
@@ -11,16 +11,24 @@ impl Stdin {
         Ok(Stdin)
     }
 
-    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+    #[inline]
+    pub fn as_raw_fd(&self) -> u32 {
+        0
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
         self.read_vectored(&mut [IoSliceMut::new(data)])
     }
 
-    pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+    fn read_vectored(&mut self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data)
     }
 
-    pub fn as_raw_fd(&self) -> u32 {
-        0
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        true
     }
 }
 
@@ -29,20 +37,27 @@ impl Stdout {
         Ok(Stdout)
     }
 
-    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+    #[inline]
+    pub fn as_raw_fd(&self) -> u32 {
+        1
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         self.write_vectored(&[IoSlice::new(data)])
     }
 
-    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+    fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
     }
 
-    pub fn flush(&self) -> io::Result<()> {
-        Ok(())
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
     }
-
-    pub fn as_raw_fd(&self) -> u32 {
-        1
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
     }
 }
 
@@ -51,18 +66,7 @@ impl Stderr {
         Ok(Stderr)
     }
 
-    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        self.write_vectored(&[IoSlice::new(data)])
-    }
-
-    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
-    }
-
-    pub fn flush(&self) -> io::Result<()> {
-        Ok(())
-    }
-
+    #[inline]
     pub fn as_raw_fd(&self) -> u32 {
         2
     }
@@ -70,11 +74,20 @@ impl Stderr {
 
 impl io::Write for Stderr {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-        (&*self).write(data)
+        self.write_vectored(&[IoSlice::new(data)])
+    }
+
+    fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+        ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
     }
 
     fn flush(&mut self) -> io::Result<()> {
-        (&*self).flush()
+        Ok(())
     }
 }
 
diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs
index 0986759b89b..0d39b1cec32 100644
--- a/src/libstd/sys/wasi/thread.rs
+++ b/src/libstd/sys/wasi/thread.rs
@@ -25,7 +25,7 @@ impl Thread {
 
     pub fn sleep(dur: Duration) {
         let nanos = dur.as_nanos();
-        assert!(nanos <= u64::max_value() as u128);
+        assert!(nanos <= u64::MAX as u128);
 
         const USERDATA: wasi::Userdata = 0x0123_45678;
 
diff --git a/src/libstd/sys/wasm/condvar_atomics.rs b/src/libstd/sys/wasm/condvar_atomics.rs
index a4021c0ee83..1859cdd5a0e 100644
--- a/src/libstd/sys/wasm/condvar_atomics.rs
+++ b/src/libstd/sys/wasm/condvar_atomics.rs
@@ -48,7 +48,7 @@ impl Condvar {
     #[inline]
     pub unsafe fn notify_all(&self) {
         self.cnt.fetch_add(1, SeqCst);
-        wasm32::atomic_notify(self.ptr(), u32::max_value()); // -1 == "wake everyone"
+        wasm32::atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
     }
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
@@ -72,7 +72,7 @@ impl Condvar {
         let ticket = self.cnt.load(SeqCst) as i32;
         mutex.unlock();
         let nanos = dur.as_nanos();
-        let nanos = cmp::min(i64::max_value() as u128, nanos);
+        let nanos = cmp::min(i64::MAX as u128, nanos);
 
         // If the return value is 2 then a timeout happened, so we return
         // `false` as we weren't actually notified.
diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs
index e6160d1457d..ecb5b51cccd 100644
--- a/src/libstd/sys/wasm/fs.rs
+++ b/src/libstd/sys/wasm/fs.rs
@@ -202,6 +202,10 @@ impl File {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -210,6 +214,10 @@ impl File {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn flush(&self) -> io::Result<()> {
         match self.0 {}
     }
diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs
index c115f756450..050e8099af4 100644
--- a/src/libstd/sys/wasm/mod.rs
+++ b/src/libstd/sys/wasm/mod.rs
@@ -81,8 +81,8 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
     return n;
 }
 
-pub unsafe fn abort_internal() -> ! {
-    crate::arch::wasm32::unreachable()
+pub fn abort_internal() -> ! {
+    unsafe { crate::arch::wasm32::unreachable() }
 }
 
 // We don't have randomness yet, but I totally used a random number generator to
diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs
index b7c3108f172..5c9f1098f9b 100644
--- a/src/libstd/sys/wasm/net.rs
+++ b/src/libstd/sys/wasm/net.rs
@@ -44,6 +44,10 @@ impl TcpStream {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -52,6 +56,10 @@ impl TcpStream {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         match self.0 {}
     }
diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs
index fb14dc59101..10d0925823e 100644
--- a/src/libstd/sys/wasm/pipe.rs
+++ b/src/libstd/sys/wasm/pipe.rs
@@ -12,6 +12,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
@@ -20,6 +24,10 @@ impl AnonPipe {
         match self.0 {}
     }
 
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
     pub fn diverge(&self) -> ! {
         match self.0 {}
     }
diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs
index 0e0e78a8276..0a11896a004 100644
--- a/src/libstd/sys/wasm/thread.rs
+++ b/src/libstd/sys/wasm/thread.rs
@@ -38,7 +38,7 @@ impl Thread {
         // 2).
         let mut nanos = dur.as_nanos();
         while nanos > 0 {
-            let amt = cmp::min(i64::max_value() as u128, nanos);
+            let amt = cmp::min(i64::MAX as u128, nanos);
             let mut x = 0;
             let val = unsafe { wasm32::i32_atomic_wait(&mut x, 0, amt as i64) };
             debug_assert_eq!(val, 2);
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 134f508dfab..f440442ca30 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -161,6 +161,8 @@ pub const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
 
 pub const PROGRESS_CONTINUE: DWORD = 0;
 
+// List of Windows system error codes with descriptions:
+// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes
 pub const ERROR_FILE_NOT_FOUND: DWORD = 2;
 pub const ERROR_PATH_NOT_FOUND: DWORD = 3;
 pub const ERROR_ACCESS_DENIED: DWORD = 5;
@@ -171,13 +173,26 @@ pub const ERROR_FILE_EXISTS: DWORD = 80;
 pub const ERROR_INVALID_PARAMETER: DWORD = 87;
 pub const ERROR_BROKEN_PIPE: DWORD = 109;
 pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120;
+pub const ERROR_SEM_TIMEOUT: DWORD = 121;
 pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122;
 pub const ERROR_ALREADY_EXISTS: DWORD = 183;
-pub const ERROR_NO_DATA: DWORD = 232;
 pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203;
+pub const ERROR_NO_DATA: DWORD = 232;
+pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594;
 pub const ERROR_OPERATION_ABORTED: DWORD = 995;
 pub const ERROR_IO_PENDING: DWORD = 997;
-pub const ERROR_TIMEOUT: DWORD = 0x5B4;
+pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053;
+pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121;
+pub const ERROR_TIMEOUT: DWORD = 1460;
+pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910;
+pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012;
+pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040;
+pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014;
+pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226;
+pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705;
+pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805;
+pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402;
+pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403;
 
 pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
 
@@ -216,7 +231,6 @@ pub const SOCK_STREAM: c_int = 1;
 pub const SOL_SOCKET: c_int = 0xffff;
 pub const SO_RCVTIMEO: c_int = 0x1006;
 pub const SO_SNDTIMEO: c_int = 0x1005;
-pub const SO_REUSEADDR: c_int = 0x0004;
 pub const IPPROTO_IP: c_int = 0;
 pub const IPPROTO_TCP: c_int = 6;
 pub const IPPROTO_IPV6: c_int = 41;
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index f85120d170f..81b2bf99872 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -259,7 +259,7 @@ pub trait OpenOptionsExt {
     /// [Impersonation Levels]:
     ///     https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
     #[stable(feature = "open_options_ext", since = "1.10.0")]
-    fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions;
+    fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
 }
 
 #[stable(feature = "open_options_ext", since = "1.10.0")]
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 427f4b684e1..cdbfac267b9 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -409,6 +409,11 @@ impl File {
         self.handle.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.handle.is_read_vectored()
+    }
+
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         self.handle.read_at(buf, offset)
     }
@@ -421,6 +426,11 @@ impl File {
         self.handle.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.handle.is_write_vectored()
+    }
+
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         self.handle.write_at(buf, offset)
     }
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
index d00381792e3..0d4baa3b340 100644
--- a/src/libstd/sys/windows/handle.rs
+++ b/src/libstd/sys/windows/handle.rs
@@ -70,7 +70,7 @@ impl RawHandle {
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let mut read = 0;
-        let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+        let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
         let res = cvt(unsafe {
             c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, ptr::null_mut())
         });
@@ -92,9 +92,14 @@ impl RawHandle {
         crate::io::default_read_vectored(|buf| self.read(buf), bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         let mut read = 0;
-        let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+        let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
         let res = unsafe {
             let mut overlapped: c::OVERLAPPED = mem::zeroed();
             overlapped.Offset = offset as u32;
@@ -113,7 +118,7 @@ impl RawHandle {
         buf: &mut [u8],
         overlapped: *mut c::OVERLAPPED,
     ) -> io::Result<Option<usize>> {
-        let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+        let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
         let mut amt = 0;
         let res = cvt(c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, overlapped));
         match res {
@@ -160,7 +165,7 @@ impl RawHandle {
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let mut amt = 0;
-        let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+        let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
         cvt(unsafe {
             c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, ptr::null_mut())
         })?;
@@ -171,9 +176,14 @@ impl RawHandle {
         crate::io::default_write_vectored(|buf| self.write(buf), bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         let mut written = 0;
-        let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+        let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
         unsafe {
             let mut overlapped: c::OVERLAPPED = mem::zeroed();
             overlapped.Offset = offset as u32;
diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs
index 5525d283252..fb06df1f80c 100644
--- a/src/libstd/sys/windows/io.rs
+++ b/src/libstd/sys/windows/io.rs
@@ -12,7 +12,7 @@ pub struct IoSlice<'a> {
 impl<'a> IoSlice<'a> {
     #[inline]
     pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
-        assert!(buf.len() <= c::ULONG::max_value() as usize);
+        assert!(buf.len() <= c::ULONG::MAX as usize);
         IoSlice {
             vec: c::WSABUF {
                 len: buf.len() as c::ULONG,
@@ -49,7 +49,7 @@ pub struct IoSliceMut<'a> {
 impl<'a> IoSliceMut<'a> {
     #[inline]
     pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
-        assert!(buf.len() <= c::ULONG::max_value() as usize);
+        assert!(buf.len() <= c::ULONG::MAX as usize);
         IoSliceMut {
             vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_mut_ptr() as *mut c::CHAR },
             _p: PhantomData,
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index d745e87a072..193ab5b47ef 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -61,7 +61,23 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
-        c::ERROR_OPERATION_ABORTED => return ErrorKind::TimedOut,
+        c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput,
+        c::ERROR_SEM_TIMEOUT
+        | c::WAIT_TIMEOUT
+        | c::ERROR_DRIVER_CANCEL_TIMEOUT
+        | c::ERROR_OPERATION_ABORTED
+        | c::ERROR_SERVICE_REQUEST_TIMEOUT
+        | c::ERROR_COUNTER_TIMEOUT
+        | c::ERROR_TIMEOUT
+        | c::ERROR_RESOURCE_CALL_TIMED_OUT
+        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
+        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
+        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
+        | c::ERROR_DS_TIMELIMIT_EXCEEDED
+        | c::DNS_ERROR_RECORD_TIMED_OUT
+        | c::ERROR_IPSEC_IKE_TIMED_OUT
+        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
+        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut,
         _ => {}
     }
 
@@ -295,7 +311,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
         .checked_mul(1000)
         .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
         .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
-        .map(|ms| if ms > <c::DWORD>::max_value() as u64 { c::INFINITE } else { ms as c::DWORD })
+        .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD })
         .unwrap_or(c::INFINITE)
 }
 
@@ -308,9 +324,9 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
 //
 // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
 #[allow(unreachable_code)]
-pub unsafe fn abort_internal() -> ! {
+pub fn abort_internal() -> ! {
     #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-    {
+    unsafe {
         llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
         crate::intrinsics::unreachable();
     }
diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs
index d8d4fdfce2f..9e74454bc23 100644
--- a/src/libstd/sys/windows/net.rs
+++ b/src/libstd/sys/windows/net.rs
@@ -228,7 +228,7 @@ impl Socket {
     fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        let len = cmp::min(buf.len(), i32::max_value() as usize) as i32;
+        let len = cmp::min(buf.len(), i32::MAX as usize) as i32;
         unsafe {
             match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) {
                 -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
@@ -245,7 +245,7 @@ impl Socket {
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD;
+        let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
         let mut nread = 0;
         let mut flags = 0;
         unsafe {
@@ -266,6 +266,11 @@ impl Socket {
         }
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        true
+    }
+
     pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
         self.recv_with_flags(buf, c::MSG_PEEK)
     }
@@ -277,7 +282,7 @@ impl Socket {
     ) -> io::Result<(usize, SocketAddr)> {
         let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() };
         let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
-        let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
 
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
@@ -308,7 +313,7 @@ impl Socket {
     }
 
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD;
+        let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
         let mut nwritten = 0;
         unsafe {
             cvt(c::WSASend(
@@ -324,6 +329,11 @@ impl Socket {
         Ok(nwritten as usize)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        true
+    }
+
     pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
         let timeout = match dur {
             Some(dur) => {
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
index 992e634dea5..104a8db4659 100644
--- a/src/libstd/sys/windows/pipe.rs
+++ b/src/libstd/sys/windows/pipe.rs
@@ -182,6 +182,11 @@ impl AnonPipe {
         self.inner.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.inner.write(buf)
     }
@@ -189,6 +194,11 @@ impl AnonPipe {
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         self.inner.write_vectored(bufs)
     }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
 }
 
 pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> {
diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs
index cdd3d2edf1f..81a5ef95e82 100644
--- a/src/libstd/sys_common/net.rs
+++ b/src/libstd/sys_common/net.rs
@@ -265,8 +265,13 @@ impl TcpStream {
         self.inner.read_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
         let ret = cvt(unsafe {
             c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
         })?;
@@ -277,6 +282,11 @@ impl TcpStream {
         self.inner.write_vectored(bufs)
     }
 
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) })
     }
@@ -358,12 +368,15 @@ impl TcpListener {
 
         let sock = Socket::new(addr, c::SOCK_STREAM)?;
 
-        // On platforms with Berkeley-derived sockets, this allows
-        // to quickly rebind a socket, without needing to wait for
-        // the OS to clean up the previous one.
-        if !cfg!(windows) {
-            setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?;
-        }
+        // On platforms with Berkeley-derived sockets, this allows to quickly
+        // rebind a socket, without needing to wait for the OS to clean up the
+        // previous one.
+        //
+        // On Windows, this allows rebinding sockets which are actively in use,
+        // which allows “socket hijacking”, so we explicitly don't set it here.
+        // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
+        #[cfg(not(windows))]
+        setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?;
 
         // Bind our new socket
         let (addrp, len) = addr.into_inner();
@@ -489,7 +502,7 @@ impl UdpSocket {
     }
 
     pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
-        let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
         let (dstp, dstlen) = dst.into_inner();
         let ret = cvt(unsafe {
             c::sendto(
@@ -628,7 +641,7 @@ impl UdpSocket {
     }
 
     pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
-        let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
         let ret = cvt(unsafe {
             c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
         })?;
diff --git a/src/libstd/sys_common/util.rs b/src/libstd/sys_common/util.rs
index 00f7db4c037..9f7c3bd8795 100644
--- a/src/libstd/sys_common/util.rs
+++ b/src/libstd/sys_common/util.rs
@@ -16,9 +16,7 @@ pub fn dumb_print(args: fmt::Arguments<'_>) {
 
 pub fn abort(args: fmt::Arguments<'_>) -> ! {
     dumb_print(format_args!("fatal runtime error: {}\n", args));
-    unsafe {
-        crate::sys::abort_internal();
-    }
+    crate::sys::abort_internal();
 }
 
 #[allow(dead_code)] // stack overflow detection not enabled on all platforms
diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs
index a98407da448..bdb6a05464e 100644
--- a/src/libstd/sys_common/wtf8.rs
+++ b/src/libstd/sys_common/wtf8.rs
@@ -201,9 +201,8 @@ impl Wtf8Buf {
     /// Copied from String::push
     /// This does **not** include the WTF-8 concatenation check.
     fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
-        let c = unsafe { char::from_u32_unchecked(code_point.value) };
         let mut bytes = [0; 4];
-        let bytes = c.encode_utf8(&mut bytes).as_bytes();
+        let bytes = char::encode_utf8_raw(code_point.value, &mut bytes);
         self.bytes.extend_from_slice(bytes)
     }
 
@@ -386,6 +385,17 @@ impl Extend<CodePoint> for Wtf8Buf {
         self.bytes.reserve(low);
         iterator.for_each(move |code_point| self.push(code_point));
     }
+
+    #[inline]
+    fn extend_one(&mut self, code_point: CodePoint) {
+        self.push(code_point);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        // Lower bound of one byte per code point (ASCII only)
+        self.bytes.reserve(additional);
+    }
 }
 
 /// A borrowed slice of well-formed WTF-8 data.
@@ -829,8 +839,7 @@ impl<'a> Iterator for EncodeWide<'a> {
 
         let mut buf = [0; 2];
         self.code_points.next().map(|code_point| {
-            let c = unsafe { char::from_u32_unchecked(code_point.value) };
-            let n = c.encode_utf16(&mut buf).len();
+            let n = char::encode_utf16_raw(code_point.value, &mut buf).len();
             if n == 2 {
                 self.extra = buf[1];
             }
diff --git a/src/libstd/tests/run-time-detect.rs b/src/libstd/tests/run-time-detect.rs
index 2e6d1bc8efd..8dd1a8ac0d2 100644
--- a/src/libstd/tests/run-time-detect.rs
+++ b/src/libstd/tests/run-time-detect.rs
@@ -32,6 +32,7 @@ fn aarch64_linux() {
     println!("rdm: {}", is_aarch64_feature_detected!("rdm"));
     println!("rcpc: {}", is_aarch64_feature_detected!("rcpc"));
     println!("dotprod: {}", is_aarch64_feature_detected!("dotprod"));
+    println!("tme: {}", is_aarch64_feature_detected!("tme"));
 }
 
 #[test]
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index 29e99c0afd2..094c468a677 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -301,7 +301,7 @@ mod lazy {
             // value (an aliasing violation). To avoid setting the "I'm running a
             // destructor" flag we just use `mem::replace` which should sequence the
             // operations a little differently and make this safe to call.
-            mem::replace(&mut *ptr, Some(value));
+            let _ = mem::replace(&mut *ptr, Some(value));
 
             // After storing `Some` we want to get a reference to the contents of
             // what we just stored. While we could use `unwrap` here and it should
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 282e268efd2..d435ca68425 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -737,6 +737,8 @@ pub fn panicking() -> bool {
 /// The thread may sleep longer than the duration specified due to scheduling
 /// specifics or platform-dependent functionality. It will never sleep less.
 ///
+/// This function is blocking, and should not be used in `async` functions.
+///
 /// # Platform-specific behavior
 ///
 /// On Unix platforms, the underlying syscall may be interrupted by a
@@ -763,6 +765,8 @@ pub fn sleep_ms(ms: u32) {
 /// The thread may sleep longer than the duration specified due to scheduling
 /// specifics or platform-dependent functionality. It will never sleep less.
 ///
+/// This function is blocking, and should not be used in `async` functions.
+///
 /// # Platform-specific behavior
 ///
 /// On Unix platforms, the underlying syscall may be interrupted by a
@@ -1062,7 +1066,7 @@ impl ThreadId {
 
             // If we somehow use up all our bits, panic so that we're not
             // covering up subtle bugs of IDs being reused.
-            if COUNTER == crate::u64::MAX {
+            if COUNTER == u64::MAX {
                 panic!("failed to generate unique thread ID: bitspace exhausted");
             }
 
@@ -1272,7 +1276,7 @@ impl Thread {
     }
 
     fn cname(&self) -> Option<&CStr> {
-        self.inner.name.as_ref().map(|s| &**s)
+        self.inner.name.as_deref()
     }
 }
 
@@ -1526,7 +1530,6 @@ mod tests {
     use crate::sync::mpsc::{channel, Sender};
     use crate::thread::{self, ThreadId};
     use crate::time::Duration;
-    use crate::u32;
 
     // !!! These tests are dangerous. If something is buggy, they will hang, !!!
     // !!! instead of exiting cleanly. This might wedge the buildbots.       !!!
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index c36e78b1d00..9f4fa89cd55 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -60,6 +60,21 @@ pub use core::time::Duration;
 /// }
 /// ```
 ///
+/// # OS-specific behaviors
+///
+/// An `Instant` is a wrapper around system-specific types and it may behave
+/// differently depending on the underlying operating system. For example,
+/// the following snippet is fine on Linux but panics on macOS:
+///
+/// ```no_run
+/// use std::time::{Instant, Duration};
+///
+/// let now = Instant::now();
+/// let max_nanoseconds = u64::MAX / 1_000_000_000;
+/// let duration = Duration::new(max_nanoseconds, 0);
+/// println!("{:?}", now + duration);
+/// ```
+///
 /// # Underlying System calls
 /// Currently, the following system calls are being used to get the current time using `now()`:
 ///
@@ -226,7 +241,7 @@ impl Instant {
         // returned instead of what the OS says if the OS goes backwards.
         //
         // To hopefully mitigate the impact of this, a few platforms are
-        // whitelisted as "these at least haven't gone backwards yet".
+        // excluded as "these at least haven't gone backwards yet".
         if time::Instant::actually_monotonic() {
             return Instant(os_now);
         }
@@ -686,7 +701,7 @@ mod tests {
 
         // checked_add_duration will not panic on overflow
         let mut maybe_t = Some(Instant::now());
-        let max_duration = Duration::from_secs(u64::max_value());
+        let max_duration = Duration::from_secs(u64::MAX);
         // in case `Instant` can store `>= now + max_duration`.
         for _ in 0..2 {
             maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
@@ -766,7 +781,7 @@ mod tests {
 
         // checked_add_duration will not panic on overflow
         let mut maybe_t = Some(SystemTime::UNIX_EPOCH);
-        let max_duration = Duration::from_secs(u64::max_value());
+        let max_duration = Duration::from_secs(u64::MAX);
         // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`.
         for _ in 0..2 {
             maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration));
@@ -796,11 +811,11 @@ mod tests {
 
         // Right now for CI this test is run in an emulator, and apparently the
         // aarch64 emulator's sense of time is that we're still living in the
-        // 70s.
+        // 70s. This is also true for riscv (also qemu)
         //
         // Otherwise let's assume that we're all running computers later than
         // 2000.
-        if !cfg!(target_arch = "aarch64") {
+        if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") {
             assert!(a > thirty_years);
         }