about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/collections/hash/map.rs125
-rw-r--r--library/std/src/collections/hash/set.rs77
-rw-r--r--library/std/src/env.rs21
-rw-r--r--library/std/src/ffi/c_str.rs2
-rw-r--r--library/std/src/ffi/mod.rs23
-rw-r--r--library/std/src/fs.rs24
-rw-r--r--library/std/src/fs/tests.rs11
-rw-r--r--library/std/src/io/buffered/bufreader.rs59
-rw-r--r--library/std/src/io/buffered/tests.rs52
-rw-r--r--library/std/src/io/copy.rs81
-rw-r--r--library/std/src/io/cursor.rs17
-rw-r--r--library/std/src/io/error.rs35
-rw-r--r--library/std/src/io/impls.rs38
-rw-r--r--library/std/src/io/mod.rs241
-rw-r--r--library/std/src/io/readbuf.rs245
-rw-r--r--library/std/src/io/readbuf/tests.rs181
-rw-r--r--library/std/src/io/stdio.rs18
-rw-r--r--library/std/src/io/tests.rs45
-rw-r--r--library/std/src/io/util.rs29
-rw-r--r--library/std/src/io/util/tests.rs29
-rw-r--r--library/std/src/lib.rs29
-rw-r--r--library/std/src/net/ip/tests.rs2
-rw-r--r--library/std/src/net/tcp.rs14
-rw-r--r--library/std/src/os/fortanix_sgx/arch.rs1
-rw-r--r--library/std/src/os/raw/mod.rs6
-rw-r--r--library/std/src/os/unix/net/stream.rs12
-rw-r--r--library/std/src/os/windows/fs.rs20
-rw-r--r--library/std/src/panicking.rs6
-rw-r--r--library/std/src/path.rs9
-rw-r--r--library/std/src/prelude/v1.rs17
-rw-r--r--library/std/src/primitive_docs.rs3
-rw-r--r--library/std/src/process.rs15
-rw-r--r--library/std/src/process/tests.rs64
-rw-r--r--library/std/src/sys/hermit/fd.rs2
-rw-r--r--library/std/src/sys/hermit/fs.rs6
-rw-r--r--library/std/src/sys/hermit/mutex.rs11
-rw-r--r--library/std/src/sys/itron/thread.rs4
-rw-r--r--library/std/src/sys/sgx/abi/mem.rs2
-rw-r--r--library/std/src/sys/sgx/abi/mod.rs1
-rw-r--r--library/std/src/sys/solid/abi/mod.rs8
-rw-r--r--library/std/src/sys/unix/android.rs90
-rw-r--r--library/std/src/sys/unix/fd.rs72
-rw-r--r--library/std/src/sys/unix/fs.rs26
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs14
-rw-r--r--library/std/src/sys/unix/net.rs4
-rw-r--r--library/std/src/sys/unix/os.rs30
-rw-r--r--library/std/src/sys/unix/os/tests.rs10
-rw-r--r--library/std/src/sys/unix/process/process_fuchsia.rs2
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs17
-rw-r--r--library/std/src/sys/unix/weak.rs104
-rw-r--r--library/std/src/sys/unsupported/fs.rs6
-rw-r--r--library/std/src/sys/wasi/fs.rs6
-rw-r--r--library/std/src/sys/wasm/alloc.rs8
-rw-r--r--library/std/src/sys/wasm/atomics/mutex.rs6
-rw-r--r--library/std/src/sys/windows/c.rs6
-rw-r--r--library/std/src/sys/windows/fs.rs6
-rw-r--r--library/std/src/sys/windows/handle.rs35
-rw-r--r--library/std/src/sys/windows/mod.rs6
-rw-r--r--library/std/src/sys/windows/os.rs2
-rw-r--r--library/std/src/sys/windows/stdio.rs2
-rw-r--r--library/std/src/sys/windows/thread_parker.rs2
-rw-r--r--library/std/src/sys_common/thread_parker/generic.rs6
-rw-r--r--library/std/src/thread/local.rs19
-rw-r--r--library/std/src/thread/mod.rs16
-rw-r--r--library/std/src/thread/tests.rs15
-rw-r--r--library/std/src/time.rs2
67 files changed, 1379 insertions, 722 deletions
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 12246b5173d..35f17aa781f 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -334,10 +334,11 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// for key in map.keys() {
     ///     println!("{}", key);
@@ -356,10 +357,11 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// for val in map.values() {
     ///     println!("{}", val);
@@ -378,11 +380,11 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    ///
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let mut map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// for val in map.values_mut() {
     ///     *val = *val + 10;
@@ -405,10 +407,11 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// for (key, val) in map.iter() {
     ///     println!("key: {} val: {}", key, val);
@@ -428,10 +431,11 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let mut map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// // Update all values
     /// for (_, val) in map.iter_mut() {
@@ -966,10 +970,11 @@ where
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// let mut vec: Vec<&str> = map.into_keys().collect();
     /// // The `IntoKeys` iterator produces keys in arbitrary order, so the
@@ -992,10 +997,11 @@ where
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// let mut vec: Vec<i32> = map.into_values().collect();
     /// // The `IntoValues` iterator produces values in arbitrary order, so
@@ -1186,7 +1192,7 @@ where
     /// assert_eq!(map1, map2);
     /// ```
     fn from(arr: [(K, V); N]) -> Self {
-        crate::array::IntoIter::new(arr).collect()
+        Self::from_iter(arr)
     }
 }
 
@@ -1202,8 +1208,9 @@ where
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.iter();
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1239,8 +1246,9 @@ impl<K: Debug, V: Debug> fmt::Debug for Iter<'_, K, V> {
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.iter_mut();
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1269,8 +1277,9 @@ impl<'a, K, V> IterMut<'a, K, V> {
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.into_iter();
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1298,8 +1307,9 @@ impl<K, V> IntoIter<K, V> {
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_keys = map.keys();
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1335,8 +1345,9 @@ impl<K: Debug, V> fmt::Debug for Keys<'_, K, V> {
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_values = map.values();
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1372,8 +1383,9 @@ impl<K, V: Debug> fmt::Debug for Values<'_, K, V> {
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.drain();
 /// ```
 #[stable(feature = "drain", since = "1.6.0")]
@@ -1402,8 +1414,9 @@ impl<'a, K, V> Drain<'a, K, V> {
 ///
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter = map.drain_filter(|_k, v| *v % 2 == 0);
 /// ```
 #[unstable(feature = "hash_drain_filter", issue = "59618")]
@@ -1426,8 +1439,9 @@ where
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_values = map.values_mut();
 /// ```
 #[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1447,8 +1461,9 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_keys = map.into_keys();
 /// ```
 #[stable(feature = "map_into_keys_values", since = "1.54.0")]
@@ -1468,8 +1483,9 @@ pub struct IntoKeys<K, V> {
 /// ```
 /// use std::collections::HashMap;
 ///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+///     ("a", 1),
+/// ]);
 /// let iter_keys = map.into_values();
 /// ```
 #[stable(feature = "map_into_keys_values", since = "1.54.0")]
@@ -2004,10 +2020,11 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S> {
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map = HashMap::new();
-    /// map.insert("a", 1);
-    /// map.insert("b", 2);
-    /// map.insert("c", 3);
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
     ///
     /// // Not possible with .iter()
     /// let vec: Vec<(&str, i32)> = map.into_iter().collect();
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index 1fc1d39b181..a1e28c0b0a6 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -233,7 +233,7 @@ impl<T, S> HashSet<T, S> {
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set = HashSet::from([1, 2, 3]);
     /// assert!(!set.is_empty());
     ///
     /// // print 1, 2, 3 in an arbitrary order
@@ -489,8 +489,8 @@ where
     ///
     /// ```
     /// use std::collections::HashSet;
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([4, 2, 3, 4]);
     ///
     /// // Can be seen as `a - b`.
     /// for x in a.difference(&b) {
@@ -518,8 +518,8 @@ where
     ///
     /// ```
     /// use std::collections::HashSet;
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([4, 2, 3, 4]);
     ///
     /// // Print 1, 4 in arbitrary order.
     /// for x in a.symmetric_difference(&b) {
@@ -548,8 +548,8 @@ where
     ///
     /// ```
     /// use std::collections::HashSet;
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([4, 2, 3, 4]);
     ///
     /// // Print 2, 3 in arbitrary order.
     /// for x in a.intersection(&b) {
@@ -576,8 +576,8 @@ where
     ///
     /// ```
     /// use std::collections::HashSet;
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([4, 2, 3, 4]);
     ///
     /// // Print 1, 2, 3, 4 in arbitrary order.
     /// for x in a.union(&b) {
@@ -608,7 +608,7 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let set = HashSet::from([1, 2, 3]);
     /// assert_eq!(set.contains(&1), true);
     /// assert_eq!(set.contains(&4), false);
     /// ```
@@ -633,7 +633,7 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let set = HashSet::from([1, 2, 3]);
     /// assert_eq!(set.get(&2), Some(&2));
     /// assert_eq!(set.get(&4), None);
     /// ```
@@ -657,7 +657,7 @@ where
     ///
     /// use std::collections::HashSet;
     ///
-    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set = HashSet::from([1, 2, 3]);
     /// assert_eq!(set.len(), 3);
     /// assert_eq!(set.get_or_insert(2), &2);
     /// assert_eq!(set.get_or_insert(100), &100);
@@ -744,7 +744,7 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let a = HashSet::from([1, 2, 3]);
     /// let mut b = HashSet::new();
     ///
     /// assert_eq!(a.is_disjoint(&b), true);
@@ -770,7 +770,7 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let sup = HashSet::from([1, 2, 3]);
     /// let mut set = HashSet::new();
     ///
     /// assert_eq!(set.is_subset(&sup), true);
@@ -792,7 +792,7 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let sub: HashSet<_> = [1, 2].iter().cloned().collect();
+    /// let sub = HashSet::from([1, 2]);
     /// let mut set = HashSet::new();
     ///
     /// assert_eq!(set.is_superset(&sub), false);
@@ -893,7 +893,7 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set = HashSet::from([1, 2, 3]);
     /// assert_eq!(set.take(&2), Some(2));
     /// assert_eq!(set.take(&2), None);
     /// ```
@@ -917,8 +917,7 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let xs = [1, 2, 3, 4, 5, 6];
-    /// let mut set: HashSet<i32> = xs.iter().cloned().collect();
+    /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
     /// set.retain(|&k| k % 2 == 0);
     /// assert_eq!(set.len(), 3);
     /// ```
@@ -1022,7 +1021,7 @@ where
     /// assert_eq!(set1, set2);
     /// ```
     fn from(arr: [T; N]) -> Self {
-        crate::array::IntoIter::new(arr).collect()
+        Self::from_iter(arr)
     }
 }
 
@@ -1097,8 +1096,8 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([3, 4, 5]);
     ///
     /// let set = &a | &b;
     ///
@@ -1130,8 +1129,8 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([2, 3, 4]);
     ///
     /// let set = &a & &b;
     ///
@@ -1163,8 +1162,8 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([3, 4, 5]);
     ///
     /// let set = &a ^ &b;
     ///
@@ -1196,8 +1195,8 @@ where
     /// ```
     /// use std::collections::HashSet;
     ///
-    /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+    /// let a = HashSet::from([1, 2, 3]);
+    /// let b = HashSet::from([3, 4, 5]);
     ///
     /// let set = &a - &b;
     ///
@@ -1226,7 +1225,7 @@ where
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let a = HashSet::from([1, 2, 3]);
 ///
 /// let mut iter = a.iter();
 /// ```
@@ -1248,7 +1247,7 @@ pub struct Iter<'a, K: 'a> {
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let a = HashSet::from([1, 2, 3]);
 ///
 /// let mut iter = a.into_iter();
 /// ```
@@ -1269,7 +1268,7 @@ pub struct IntoIter<K> {
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let mut a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let mut a = HashSet::from([1, 2, 3]);
 ///
 /// let mut drain = a.drain();
 /// ```
@@ -1291,7 +1290,7 @@ pub struct Drain<'a, K: 'a> {
 ///
 /// use std::collections::HashSet;
 ///
-/// let mut a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let mut a = HashSet::from([1, 2, 3]);
 ///
 /// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0);
 /// ```
@@ -1315,8 +1314,8 @@ where
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
 ///
 /// let mut intersection = a.intersection(&b);
 /// ```
@@ -1342,8 +1341,8 @@ pub struct Intersection<'a, T: 'a, S: 'a> {
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
 ///
 /// let mut difference = a.difference(&b);
 /// ```
@@ -1369,8 +1368,8 @@ pub struct Difference<'a, T: 'a, S: 'a> {
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
 ///
 /// let mut intersection = a.symmetric_difference(&b);
 /// ```
@@ -1393,8 +1392,8 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
 /// ```
 /// use std::collections::HashSet;
 ///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
 ///
 /// let mut union_iter = a.union(&b);
 /// ```
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index c6af708f6cd..c06928647d3 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -583,28 +583,25 @@ pub fn home_dir() -> Option<PathBuf> {
 /// may result in "insecure temporary file" security vulnerabilities. Consider
 /// using a crate that securely creates temporary files or directories.
 ///
-/// # Unix
+/// # Platform-specific behavior
 ///
-/// Returns the value of the `TMPDIR` environment variable if it is
+/// On Unix, returns the value of the `TMPDIR` environment variable if it is
 /// set, otherwise for non-Android it returns `/tmp`. If Android, since there
 /// is no global temporary folder (it is usually allocated per-app), it returns
 /// `/data/local/tmp`.
+/// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] /
+/// [`GetTempPath`][GetTempPath], which this function uses internally.
+/// Note that, this [may change in the future][changes].
 ///
-/// # Windows
-///
-/// Returns the value of, in order, the `TMP`, `TEMP`,
-/// `USERPROFILE` environment variable if any are set and not the empty
-/// string. Otherwise, `temp_dir` returns the path of the Windows directory.
-/// This behavior is identical to that of [`GetTempPath`][msdn], which this
-/// function uses internally.
-///
-/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
+/// [changes]: io#platform-specific-behavior
+/// [GetTempPath2]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
+/// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
 ///
 /// ```no_run
 /// use std::env;
 ///
 /// fn main() {
-///     let mut dir = env::temp_dir();
+///     let dir = env::temp_dir();
 ///     println!("Temporary directory: {}", dir.display());
 /// }
 /// ```
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 465bbae8631..9c1b79d6966 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -1259,7 +1259,7 @@ impl CStr {
     #[inline]
     #[must_use]
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-    #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")]
+    #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
         // SAFETY: Casting to CStr is safe because its internal representation
         // is a [u8] too (safe only inside std).
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 7f3bb836754..019b64c395e 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -81,9 +81,9 @@
 //! [`OsStr`] and Rust strings work similarly to those for [`CString`]
 //! and [`CStr`].
 //!
-//! * [`OsString`] represents an owned string in whatever
-//! representation the operating system prefers. In the Rust standard
-//! library, various APIs that transfer strings to/from the operating
+//! * [`OsString`] losslessly represents an owned platform string. However, this
+//! representation is not necessarily in a form native to the platform.
+//! In the Rust standard library, various APIs that transfer strings to/from the operating
 //! system use [`OsString`] instead of plain strings. For example,
 //! [`env::var_os()`] is used to query environment variables; it
 //! returns an <code>[Option]<[OsString]></code>. If the environment variable
@@ -92,9 +92,9 @@
 //! your code can detect errors in case the environment variable did
 //! not in fact contain valid Unicode data.
 //!
-//! * [`OsStr`] represents a borrowed reference to a string in a
-//! format that can be passed to the operating system. It can be
-//! converted into a UTF-8 Rust string slice in a similar way to
+//! * [`OsStr`] losslessly represents a borrowed reference to a platform string.
+//! However, this representation is not necessarily in a form native to the platform.
+//! It can be converted into a UTF-8 Rust string slice in a similar way to
 //! [`OsString`].
 //!
 //! # Conversions
@@ -113,16 +113,19 @@
 //!
 //! ## On Windows
 //!
+//! An [`OsStr`] can be losslessly converted to a native Windows string. And
+//! a native Windows string can be losslessly converted to an [`OsString`].
+//!
 //! On Windows, [`OsStr`] implements the
 //! <code>std::os::windows::ffi::[OsStrExt][windows.OsStrExt]</code> trait,
 //! which provides an [`encode_wide`] method. This provides an
-//! iterator that can be [`collect`]ed into a vector of [`u16`].
+//! iterator that can be [`collect`]ed into a vector of [`u16`]. After a nul
+//! characters is appended, this is the same as a native Windows string.
 //!
 //! Additionally, on Windows [`OsString`] implements the
 //! <code>std::os::windows:ffi::[OsStringExt][windows.OsStringExt]</code>
-//! trait, which provides a [`from_wide`] method. The result of this
-//! method is an [`OsString`] which can be round-tripped to a Windows
-//! string losslessly.
+//! trait, which provides a [`from_wide`] method to convert a native Windows
+//! string (without the terminating nul character) to an [`OsString`].
 //!
 //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
 //! [Unicode code point]: https://www.unicode.org/glossary/#code_point
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index a14f1e2ecb2..dae85027b6c 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -13,7 +13,7 @@ mod tests;
 
 use crate::ffi::OsString;
 use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
+use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write};
 use crate::path::{Path, PathBuf};
 use crate::sys::fs as fs_imp;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@@ -623,15 +623,13 @@ impl Read for File {
         self.inner.read_vectored(bufs)
     }
 
-    #[inline]
-    fn is_read_vectored(&self) -> bool {
-        self.inner.is_read_vectored()
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        unsafe { Initializer::nop() }
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
     }
 
     // Reserves space in the buffer based on the file size when available.
@@ -677,6 +675,10 @@ impl Read for &File {
         self.inner.read(buf)
     }
 
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         self.inner.read_vectored(bufs)
     }
@@ -686,12 +688,6 @@ impl Read for &File {
         self.inner.is_read_vectored()
     }
 
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        unsafe { Initializer::nop() }
-    }
-
     // Reserves space in the buffer based on the file size when available.
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         buf.reserve(buffer_capacity_required(self));
@@ -1062,7 +1058,7 @@ impl Metadata {
     /// }
     /// ```
     #[must_use]
-    #[stable(feature = "is_symlink", since = "1.57.0")]
+    #[stable(feature = "is_symlink", since = "1.58.0")]
     pub fn is_symlink(&self) -> bool {
         self.file_type().is_symlink()
     }
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 9a8f1e44f1f..749d51d4981 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -38,10 +38,9 @@ macro_rules! error {
     ($e:expr, $s:expr) => {
         match $e {
             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
-            Err(ref err) => assert!(
-                err.raw_os_error() == Some($s),
-                format!("`{}` did not have a code of `{}`", err, $s)
-            ),
+            Err(ref err) => {
+                assert!(err.raw_os_error() == Some($s), "`{}` did not have a code of `{}`", err, $s)
+            }
         }
     };
 }
@@ -58,7 +57,7 @@ macro_rules! error_contains {
         match $e {
             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
             Err(ref err) => {
-                assert!(err.to_string().contains($s), format!("`{}` did not contain `{}`", err, $s))
+                assert!(err.to_string().contains($s), "`{}` did not contain `{}`", err, $s)
             }
         }
     };
@@ -1369,7 +1368,7 @@ fn symlink_hard_link() {
     // "hard_link" should appear as a symlink.
     assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
 
-    // We sould be able to open "file" via any of the above names.
+    // We should be able to open "file" via any of the above names.
     let _ = check!(fs::File::open(tmpdir.join("file")));
     assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
     let _ = check!(fs::File::open(tmpdir.join("symlink")));
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 2864e94f60f..b56dc65f0b2 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -1,8 +1,9 @@
 use crate::cmp;
 use crate::fmt;
 use crate::io::{
-    self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
+    self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
 };
+use crate::mem::MaybeUninit;
 
 /// The `BufReader<R>` struct adds buffering to any reader.
 ///
@@ -47,9 +48,10 @@ use crate::io::{
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufReader<R> {
     inner: R,
-    buf: Box<[u8]>,
+    buf: Box<[MaybeUninit<u8>]>,
     pos: usize,
     cap: usize,
+    init: usize,
 }
 
 impl<R: Read> BufReader<R> {
@@ -91,11 +93,8 @@ impl<R: Read> BufReader<R> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
-        unsafe {
-            let mut buf = Box::new_uninit_slice(capacity).assume_init();
-            inner.initializer().initialize(&mut buf);
-            BufReader { inner, buf, pos: 0, cap: 0 }
-        }
+        let buf = Box::new_uninit_slice(capacity);
+        BufReader { inner, buf, pos: 0, cap: 0, init: 0 }
     }
 }
 
@@ -171,7 +170,8 @@ impl<R> BufReader<R> {
     /// ```
     #[stable(feature = "bufreader_buffer", since = "1.37.0")]
     pub fn buffer(&self) -> &[u8] {
-        &self.buf[self.pos..self.cap]
+        // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init
+        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) }
     }
 
     /// Returns the number of bytes the internal buffer can hold at once.
@@ -271,6 +271,25 @@ impl<R: Read> Read for BufReader<R> {
         Ok(nread)
     }
 
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        // If we don't have any buffered data and we're doing a massive read
+        // (larger than our internal buffer), bypass our internal buffer
+        // entirely.
+        if self.pos == self.cap && buf.remaining() >= self.buf.len() {
+            self.discard_buffer();
+            return self.inner.read_buf(buf);
+        }
+
+        let prev = buf.filled_len();
+
+        let mut rem = self.fill_buf()?;
+        rem.read_buf(buf)?;
+
+        self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf
+
+        Ok(())
+    }
+
     // Small read_exacts from a BufReader are extremely common when used with a deserializer.
     // The default implementation calls read in a loop, which results in surprisingly poor code
     // generation for the common path where the buffer has enough bytes to fill the passed-in
@@ -303,16 +322,11 @@ impl<R: Read> Read for BufReader<R> {
         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()
-    }
-
     // The inner reader might have an optimized `read_to_end`. Drain our buffer and then
     // delegate to the inner implementation.
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         let nread = self.cap - self.pos;
-        buf.extend_from_slice(&self.buf[self.pos..self.cap]);
+        buf.extend_from_slice(&self.buffer());
         self.discard_buffer();
         Ok(nread + self.inner.read_to_end(buf)?)
     }
@@ -363,10 +377,23 @@ impl<R: Read> BufRead for BufReader<R> {
         // to tell the compiler that the pos..cap slice is always valid.
         if self.pos >= self.cap {
             debug_assert!(self.pos == self.cap);
-            self.cap = self.inner.read(&mut self.buf)?;
+
+            let mut readbuf = ReadBuf::uninit(&mut self.buf);
+
+            // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()`
+            // from the last time this function was called
+            unsafe {
+                readbuf.assume_init(self.init);
+            }
+
+            self.inner.read_buf(&mut readbuf)?;
+
+            self.cap = readbuf.filled_len();
+            self.init = readbuf.initialized_len();
+
             self.pos = 0;
         }
-        Ok(&self.buf[self.pos..self.cap])
+        Ok(self.buffer())
     }
 
     fn consume(&mut self, amt: usize) {
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index feb149c07a5..9d429e7090e 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -1,5 +1,6 @@
 use crate::io::prelude::*;
-use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom};
+use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom};
+use crate::mem::MaybeUninit;
 use crate::panic;
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::thread;
@@ -56,6 +57,55 @@ fn test_buffered_reader() {
 }
 
 #[test]
+fn test_buffered_reader_read_buf() {
+    let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+    let mut reader = BufReader::with_capacity(2, inner);
+
+    let mut buf = [MaybeUninit::uninit(); 3];
+    let mut buf = ReadBuf::uninit(&mut buf);
+
+    reader.read_buf(&mut buf).unwrap();
+
+    assert_eq!(buf.filled(), [5, 6, 7]);
+    assert_eq!(reader.buffer(), []);
+
+    let mut buf = [MaybeUninit::uninit(); 2];
+    let mut buf = ReadBuf::uninit(&mut buf);
+
+    reader.read_buf(&mut buf).unwrap();
+
+    assert_eq!(buf.filled(), [0, 1]);
+    assert_eq!(reader.buffer(), []);
+
+    let mut buf = [MaybeUninit::uninit(); 1];
+    let mut buf = ReadBuf::uninit(&mut buf);
+
+    reader.read_buf(&mut buf).unwrap();
+
+    assert_eq!(buf.filled(), [2]);
+    assert_eq!(reader.buffer(), [3]);
+
+    let mut buf = [MaybeUninit::uninit(); 3];
+    let mut buf = ReadBuf::uninit(&mut buf);
+
+    reader.read_buf(&mut buf).unwrap();
+
+    assert_eq!(buf.filled(), [3]);
+    assert_eq!(reader.buffer(), []);
+
+    reader.read_buf(&mut buf).unwrap();
+
+    assert_eq!(buf.filled(), [3, 4]);
+    assert_eq!(reader.buffer(), []);
+
+    buf.clear();
+
+    reader.read_buf(&mut buf).unwrap();
+
+    assert_eq!(buf.filled_len(), 0);
+}
+
+#[test]
 fn test_buffered_reader_seek() {
     let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
     let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index eb60df214c4..6ab96662305 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,4 +1,4 @@
-use super::{BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE};
 use crate::mem::MaybeUninit;
 
 /// Copies the entire contents of a reader into a writer.
@@ -82,33 +82,30 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
             return stack_buffer_copy(reader, writer);
         }
 
-        // FIXME: #42788
-        //
-        //   - This creates a (mut) reference to a slice of
-        //     _uninitialized_ integers, which is **undefined behavior**
-        //
-        //   - Only the standard library gets to soundly "ignore" this,
-        //     based on its privileged knowledge of unstable rustc
-        //     internals;
-        unsafe {
-            let spare_cap = writer.buffer_mut().spare_capacity_mut();
-            reader.initializer().initialize(MaybeUninit::slice_assume_init_mut(spare_cap));
-        }
-
         let mut len = 0;
+        let mut init = 0;
 
         loop {
             let buf = writer.buffer_mut();
-            let spare_cap = buf.spare_capacity_mut();
-
-            if spare_cap.len() >= DEFAULT_BUF_SIZE {
-                match reader.read(unsafe { MaybeUninit::slice_assume_init_mut(spare_cap) }) {
-                    Ok(0) => return Ok(len), // EOF reached
-                    Ok(bytes_read) => {
-                        assert!(bytes_read <= spare_cap.len());
-                        // SAFETY: The initializer contract guarantees that either it or `read`
-                        // will have initialized these bytes. And we just checked that the number
-                        // of bytes is within the buffer capacity.
+            let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+
+            // SAFETY: init is either 0 or the initialized_len of the previous iteration
+            unsafe {
+                read_buf.assume_init(init);
+            }
+
+            if read_buf.capacity() >= DEFAULT_BUF_SIZE {
+                match reader.read_buf(&mut read_buf) {
+                    Ok(()) => {
+                        let bytes_read = read_buf.filled_len();
+
+                        if bytes_read == 0 {
+                            return Ok(len);
+                        }
+
+                        init = read_buf.initialized_len() - bytes_read;
+
+                        // SAFETY: ReadBuf guarantees all of its filled bytes are init
                         unsafe { buf.set_len(buf.len() + bytes_read) };
                         len += bytes_read as u64;
                         // Read again if the buffer still has enough capacity, as BufWriter itself would do
@@ -129,28 +126,26 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
     reader: &mut R,
     writer: &mut W,
 ) -> Result<u64> {
-    let mut buf = MaybeUninit::<[u8; DEFAULT_BUF_SIZE]>::uninit();
-    // FIXME: #42788
-    //
-    //   - This creates a (mut) reference to a slice of
-    //     _uninitialized_ integers, which is **undefined behavior**
-    //
-    //   - Only the standard library gets to soundly "ignore" this,
-    //     based on its privileged knowledge of unstable rustc
-    //     internals;
-    unsafe {
-        reader.initializer().initialize(buf.assume_init_mut());
-    }
+    let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
+    let mut buf = ReadBuf::uninit(&mut buf);
+
+    let mut len = 0;
 
-    let mut written = 0;
     loop {
-        let len = match reader.read(unsafe { buf.assume_init_mut() }) {
-            Ok(0) => return Ok(written),
-            Ok(len) => len,
-            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+        match reader.read_buf(&mut buf) {
+            Ok(()) => {}
+            Err(e) if e.kind() == ErrorKind::Interrupted => continue,
             Err(e) => return Err(e),
         };
-        writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?;
-        written += len as u64;
+
+        if buf.filled().is_empty() {
+            break;
+        }
+
+        len += buf.filled().len() as u64;
+        writer.write_all(buf.filled())?;
+        buf.clear();
     }
+
+    Ok(len)
 }
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 980b2531192..416cc906e65 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -4,7 +4,7 @@ mod tests;
 use crate::io::prelude::*;
 
 use crate::cmp;
-use crate::io::{self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 
 use core::convert::TryInto;
 
@@ -324,6 +324,16 @@ where
         Ok(n)
     }
 
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        let prev_filled = buf.filled_len();
+
+        Read::read_buf(&mut self.fill_buf()?, buf)?;
+
+        self.pos += (buf.filled_len() - prev_filled) as u64;
+
+        Ok(())
+    }
+
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let mut nread = 0;
         for buf in bufs {
@@ -346,11 +356,6 @@ where
         self.pos += n as u64;
         Ok(())
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index d93c6172cfc..210a9ec7183 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -417,6 +417,33 @@ impl Error {
         Self::_new(kind, error.into())
     }
 
+    /// Creates a new I/O error from an arbitrary error payload.
+    ///
+    /// This function is used to generically create I/O errors which do not
+    /// originate from the OS itself. It is a shortcut for [`Error::new`]
+    /// with [`ErrorKind::Other`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(io_error_other)]
+    ///
+    /// use std::io::Error;
+    ///
+    /// // errors can be created from strings
+    /// let custom_error = Error::other("oh no!");
+    ///
+    /// // errors can also be created from other errors
+    /// let custom_error2 = Error::other(custom_error);
+    /// ```
+    #[unstable(feature = "io_error_other", issue = "91946")]
+    pub fn other<E>(error: E) -> Error
+    where
+        E: Into<Box<dyn error::Error + Send + Sync>>,
+    {
+        Self::_new(ErrorKind::Other, error.into())
+    }
+
     fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
         Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
     }
@@ -440,12 +467,18 @@ impl Error {
     /// `GetLastError` on Windows) and will return a corresponding instance of
     /// [`Error`] for the error code.
     ///
+    /// This should be called immediately after a call to a platform function,
+    /// otherwise the state of the error value is indeterminate. In particular,
+    /// other standard library functions may call platform functions that may
+    /// (or may not) reset the error value even if they succeed.
+    ///
     /// # Examples
     ///
     /// ```
     /// use std::io::Error;
     ///
-    /// println!("last OS error: {:?}", Error::last_os_error());
+    /// let os_error = Error::last_os_error();
+    /// println!("last OS error: {:?}", os_error);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 7a2a49ba7d7..23201f9fc5c 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -5,7 +5,7 @@ use crate::alloc::Allocator;
 use crate::cmp;
 use crate::fmt;
 use crate::io::{
-    self, BufRead, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
+    self, BufRead, Error, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
 };
 use crate::mem;
 
@@ -20,6 +20,11 @@ impl<R: Read + ?Sized> Read for &mut R {
     }
 
     #[inline]
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        (**self).read_buf(buf)
+    }
+
+    #[inline]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         (**self).read_vectored(bufs)
     }
@@ -30,11 +35,6 @@ impl<R: Read + ?Sized> Read for &mut R {
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        (**self).initializer()
-    }
-
-    #[inline]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         (**self).read_to_end(buf)
     }
@@ -124,6 +124,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
     }
 
     #[inline]
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        (**self).read_buf(buf)
+    }
+
+    #[inline]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         (**self).read_vectored(bufs)
     }
@@ -134,11 +139,6 @@ impl<R: Read + ?Sized> Read for Box<R> {
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        (**self).initializer()
-    }
-
-    #[inline]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         (**self).read_to_end(buf)
     }
@@ -248,6 +248,17 @@ impl Read for &[u8] {
     }
 
     #[inline]
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        let amt = cmp::min(buf.remaining(), self.len());
+        let (a, b) = self.split_at(amt);
+
+        buf.append(a);
+
+        *self = b;
+        Ok(())
+    }
+
+    #[inline]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let mut nread = 0;
         for buf in bufs {
@@ -266,11 +277,6 @@ impl Read for &[u8] {
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
-
-    #[inline]
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         if buf.len() > self.len() {
             return Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"));
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 8cc91566418..ecc9e91b6bd 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -256,7 +256,6 @@ use crate::convert::TryInto;
 use crate::fmt;
 use crate::mem::replace;
 use crate::ops::{Deref, DerefMut};
-use crate::ptr;
 use crate::slice;
 use crate::str;
 use crate::sys;
@@ -288,12 +287,16 @@ pub use self::stdio::{_eprint, _print};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
 
+#[unstable(feature = "read_buf", issue = "78485")]
+pub use self::readbuf::ReadBuf;
+
 mod buffered;
 pub(crate) mod copy;
 mod cursor;
 mod error;
 mod impls;
 pub mod prelude;
+mod readbuf;
 mod stdio;
 mod util;
 
@@ -355,52 +358,43 @@ where
 // of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
 // time is 4,500 times (!) slower than a default reservation size of 32 if the
 // reader has a very small amount of data to return.
-//
-// Because we're extending the buffer with uninitialized data for trusted
-// readers, we need to make sure to truncate that if any of this panics.
 pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
     let start_len = buf.len();
     let start_cap = buf.capacity();
-    let mut g = Guard { len: buf.len(), buf };
+
+    let mut initialized = 0; // Extra initialized bytes from previous loop iteration
     loop {
-        // If we've read all the way up to the capacity, reserve more space.
-        if g.len == g.buf.capacity() {
-            g.buf.reserve(32);
+        if buf.len() == buf.capacity() {
+            buf.reserve(32); // buf is full, need more space
         }
 
-        // Initialize any excess capacity and adjust the length so we can write
-        // to it.
-        if g.buf.len() < g.buf.capacity() {
-            unsafe {
-                // FIXME(danielhenrymantilla): #42788
-                //
-                //   - This creates a (mut) reference to a slice of
-                //     _uninitialized_ integers, which is **undefined behavior**
-                //
-                //   - Only the standard library gets to soundly "ignore" this,
-                //     based on its privileged knowledge of unstable rustc
-                //     internals;
-                let capacity = g.buf.capacity();
-                g.buf.set_len(capacity);
-                r.initializer().initialize(&mut g.buf[g.len..]);
-            }
+        let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+
+        // SAFETY: These bytes were initialized but not filled in the previous loop
+        unsafe {
+            read_buf.assume_init(initialized);
         }
 
-        let buf = &mut g.buf[g.len..];
-        match r.read(buf) {
-            Ok(0) => return Ok(g.len - start_len),
-            Ok(n) => {
-                // We can't allow bogus values from read. If it is too large, the returned vec could have its length
-                // set past its capacity, or if it overflows the vec could be shortened which could create an invalid
-                // string if this is called via read_to_string.
-                assert!(n <= buf.len());
-                g.len += n;
-            }
-            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+        match r.read_buf(&mut read_buf) {
+            Ok(()) => {}
+            Err(e) if e.kind() == ErrorKind::Interrupted => continue,
             Err(e) => return Err(e),
         }
 
-        if g.len == g.buf.capacity() && g.buf.capacity() == start_cap {
+        if read_buf.filled_len() == 0 {
+            return Ok(buf.len() - start_len);
+        }
+
+        // store how much was initialized but not filled
+        initialized = read_buf.initialized_len() - read_buf.filled_len();
+        let new_len = read_buf.filled_len() + buf.len();
+
+        // SAFETY: ReadBuf's invariants mean this much memory is init
+        unsafe {
+            buf.set_len(new_len);
+        }
+
+        if buf.len() == buf.capacity() && buf.capacity() == start_cap {
             // The buffer might be an exact fit. Let's read into a probe buffer
             // and see if it returns `Ok(0)`. If so, we've avoided an
             // unnecessary doubling of the capacity. But if not, append the
@@ -409,10 +403,9 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>
 
             loop {
                 match r.read(&mut probe) {
-                    Ok(0) => return Ok(g.len - start_len),
+                    Ok(0) => return Ok(buf.len() - start_len),
                     Ok(n) => {
-                        g.buf.extend_from_slice(&probe[..n]);
-                        g.len += n;
+                        buf.extend_from_slice(&probe[..n]);
                         break;
                     }
                     Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
@@ -474,6 +467,15 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
     }
 }
 
+pub(crate) fn default_read_buf<F>(read: F, buf: &mut ReadBuf<'_>) -> Result<()>
+where
+    F: FnOnce(&mut [u8]) -> Result<usize>,
+{
+    let n = read(buf.initialize_unfilled())?;
+    buf.add_filled(n);
+    Ok(())
+}
+
 /// The `Read` trait allows for reading bytes from a source.
 ///
 /// Implementors of the `Read` trait are called 'readers'.
@@ -656,31 +658,6 @@ pub trait Read {
         false
     }
 
-    /// Determines if this `Read`er can work with buffers of uninitialized
-    /// memory.
-    ///
-    /// The default implementation returns an initializer which will zero
-    /// buffers.
-    ///
-    /// If a `Read`er guarantees that it can work properly with uninitialized
-    /// memory, it should call [`Initializer::nop()`]. See the documentation for
-    /// [`Initializer`] for details.
-    ///
-    /// The behavior of this method must be independent of the state of the
-    /// `Read`er - the method only takes `&self` so that it can be used through
-    /// trait objects.
-    ///
-    /// # Safety
-    ///
-    /// This method is unsafe because a `Read`er could otherwise return a
-    /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
-    /// block.
-    #[unstable(feature = "read_initializer", issue = "42788")]
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::zeroing()
-    }
-
     /// Read all bytes until EOF in this source, placing them into `buf`.
     ///
     /// All bytes read from this source will be appended to the specified buffer
@@ -830,7 +807,40 @@ pub trait Read {
         default_read_exact(self, buf)
     }
 
-    /// Creates a "by reference" adapter for this instance of `Read`.
+    /// Pull some bytes from this source into the specified buffer.
+    ///
+    /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to allow use
+    /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.
+    ///
+    /// The default implementation delegates to `read`.
+    #[unstable(feature = "read_buf", issue = "78485")]
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+        default_read_buf(|b| self.read(b), buf)
+    }
+
+    /// Read the exact number of bytes required to fill `buf`.
+    ///
+    /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to
+    /// allow use with uninitialized buffers.
+    #[unstable(feature = "read_buf", issue = "78485")]
+    fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+        while buf.remaining() > 0 {
+            let prev_filled = buf.filled().len();
+            match self.read_buf(buf) {
+                Ok(()) => {}
+                Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+                Err(e) => return Err(e),
+            }
+
+            if buf.filled().len() == prev_filled {
+                return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer"));
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Creates a "by reference" adaptor for this instance of `Read`.
     ///
     /// The returned adapter also implements `Read` and will simply borrow this
     /// current reader.
@@ -1300,53 +1310,6 @@ impl<'a> Deref for IoSlice<'a> {
     }
 }
 
-/// A type used to conditionally initialize buffers passed to `Read` methods.
-#[unstable(feature = "read_initializer", issue = "42788")]
-#[derive(Debug)]
-pub struct Initializer(bool);
-
-impl Initializer {
-    /// Returns a new `Initializer` which will zero out buffers.
-    #[unstable(feature = "read_initializer", issue = "42788")]
-    #[must_use]
-    #[inline]
-    pub fn zeroing() -> Initializer {
-        Initializer(true)
-    }
-
-    /// Returns a new `Initializer` which will not zero out buffers.
-    ///
-    /// # Safety
-    ///
-    /// This may only be called by `Read`ers which guarantee that they will not
-    /// read from buffers passed to `Read` methods, and that the return value of
-    /// the method accurately reflects the number of bytes that have been
-    /// written to the head of the buffer.
-    #[unstable(feature = "read_initializer", issue = "42788")]
-    #[must_use]
-    #[inline]
-    pub unsafe fn nop() -> Initializer {
-        Initializer(false)
-    }
-
-    /// Indicates if a buffer should be initialized.
-    #[unstable(feature = "read_initializer", issue = "42788")]
-    #[must_use]
-    #[inline]
-    pub fn should_initialize(&self) -> bool {
-        self.0
-    }
-
-    /// Initializes a buffer if necessary.
-    #[unstable(feature = "read_initializer", issue = "42788")]
-    #[inline]
-    pub fn initialize(&self, buf: &mut [u8]) {
-        if self.should_initialize() {
-            unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
-        }
-    }
-}
-
 /// A trait for objects which are byte-oriented sinks.
 ///
 /// Implementors of the `Write` trait are sometimes called 'writers'.
@@ -2403,11 +2366,6 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
         }
         self.second.read_vectored(bufs)
     }
-
-    unsafe fn initializer(&self) -> Initializer {
-        let initializer = self.first.initializer();
-        if initializer.should_initialize() { initializer } else { self.second.initializer() }
-    }
 }
 
 #[stable(feature = "chain_bufread", since = "1.9.0")]
@@ -2610,8 +2568,53 @@ impl<T: Read> Read for Take<T> {
         Ok(n)
     }
 
-    unsafe fn initializer(&self) -> Initializer {
-        self.inner.initializer()
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+        // Don't call into inner reader at all at EOF because it may still block
+        if self.limit == 0 {
+            return Ok(());
+        }
+
+        let prev_filled = buf.filled_len();
+
+        if self.limit <= buf.remaining() as u64 {
+            // if we just use an as cast to convert, limit may wrap around on a 32 bit target
+            let limit = cmp::min(self.limit, usize::MAX as u64) as usize;
+
+            let extra_init = cmp::min(limit as usize, buf.initialized_len() - buf.filled_len());
+
+            // SAFETY: no uninit data is written to ibuf
+            let ibuf = unsafe { &mut buf.unfilled_mut()[..limit] };
+
+            let mut sliced_buf = ReadBuf::uninit(ibuf);
+
+            // SAFETY: extra_init bytes of ibuf are known to be initialized
+            unsafe {
+                sliced_buf.assume_init(extra_init);
+            }
+
+            self.inner.read_buf(&mut sliced_buf)?;
+
+            let new_init = sliced_buf.initialized_len();
+            let filled = sliced_buf.filled_len();
+
+            // sliced_buf / ibuf must drop here
+
+            // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
+            unsafe {
+                buf.assume_init(new_init);
+            }
+
+            buf.add_filled(filled);
+
+            self.limit -= filled as u64;
+        } else {
+            self.inner.read_buf(buf)?;
+
+            //inner may unfill
+            self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64;
+        }
+
+        Ok(())
     }
 }
 
diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs
new file mode 100644
index 00000000000..d84a500e078
--- /dev/null
+++ b/library/std/src/io/readbuf.rs
@@ -0,0 +1,245 @@
+#![unstable(feature = "read_buf", issue = "78485")]
+
+#[cfg(test)]
+mod tests;
+
+use crate::cmp;
+use crate::fmt::{self, Debug, Formatter};
+use crate::mem::MaybeUninit;
+
+/// A wrapper around a byte buffer that is incrementally filled and initialized.
+///
+/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the
+/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet
+/// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a
+/// subset of the initialized region.
+///
+/// In summary, the contents of the buffer can be visualized as:
+/// ```not_rust
+/// [             capacity              ]
+/// [ filled |         unfilled         ]
+/// [    initialized    | uninitialized ]
+/// ```
+pub struct ReadBuf<'a> {
+    buf: &'a mut [MaybeUninit<u8>],
+    filled: usize,
+    initialized: usize,
+}
+
+impl Debug for ReadBuf<'_> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ReadBuf")
+            .field("init", &self.initialized())
+            .field("filled", &self.filled)
+            .field("capacity", &self.capacity())
+            .finish()
+    }
+}
+
+impl<'a> ReadBuf<'a> {
+    /// Creates a new `ReadBuf` from a fully initialized buffer.
+    #[inline]
+    pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
+        let len = buf.len();
+
+        ReadBuf {
+            //SAFETY: initialized data never becoming uninitialized is an invariant of ReadBuf
+            buf: unsafe { (buf as *mut [u8]).as_uninit_slice_mut().unwrap() },
+            filled: 0,
+            initialized: len,
+        }
+    }
+
+    /// Creates a new `ReadBuf` from a fully uninitialized buffer.
+    ///
+    /// Use `assume_init` if part of the buffer is known to be already inintialized.
+    #[inline]
+    pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
+        ReadBuf { buf, filled: 0, initialized: 0 }
+    }
+
+    /// Returns the total capacity of the buffer.
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.buf.len()
+    }
+
+    /// Returns a shared reference to the filled portion of the buffer.
+    #[inline]
+    pub fn filled(&self) -> &[u8] {
+        //SAFETY: We only slice the filled part of the buffer, which is always valid
+        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
+    }
+
+    /// Returns a mutable reference to the filled portion of the buffer.
+    #[inline]
+    pub fn filled_mut(&mut self) -> &mut [u8] {
+        //SAFETY: We only slice the filled part of the buffer, which is always valid
+        unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
+    }
+
+    /// Returns a shared reference to the initialized portion of the buffer.
+    ///
+    /// This includes the filled portion.
+    #[inline]
+    pub fn initialized(&self) -> &[u8] {
+        //SAFETY: We only slice the initialized part of the buffer, which is always valid
+        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.initialized]) }
+    }
+
+    /// Returns a mutable reference to the initialized portion of the buffer.
+    ///
+    /// This includes the filled portion.
+    #[inline]
+    pub fn initialized_mut(&mut self) -> &mut [u8] {
+        //SAFETY: We only slice the initialized part of the buffer, which is always valid
+        unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.initialized]) }
+    }
+
+    /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
+    /// initialized.
+    ///
+    /// # Safety
+    ///
+    /// The caller must not de-initialize portions of the buffer that have already been initialized.
+    #[inline]
+    pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+        &mut self.buf[self.filled..]
+    }
+
+    /// Returns a mutable reference to the uninitialized part of the buffer.
+    ///
+    /// It is safe to uninitialize any of these bytes.
+    #[inline]
+    pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+        &mut self.buf[self.initialized..]
+    }
+
+    /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
+    ///
+    /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
+    /// the first use.
+    #[inline]
+    pub fn initialize_unfilled(&mut self) -> &mut [u8] {
+        // should optimize out the assertion
+        self.initialize_unfilled_to(self.remaining())
+    }
+
+    /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
+    /// fully initialized.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `self.remaining()` is less than `n`.
+    #[inline]
+    pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
+        assert!(self.remaining() >= n);
+
+        let extra_init = self.initialized - self.filled;
+        // If we don't have enough initialized, do zeroing
+        if n > extra_init {
+            let uninit = n - extra_init;
+            let unfilled = &mut self.uninitialized_mut()[0..uninit];
+
+            for byte in unfilled.iter_mut() {
+                byte.write(0);
+            }
+
+            // SAFETY: we just inintialized uninit bytes, and the previous bytes were already init
+            unsafe {
+                self.assume_init(n);
+            }
+        }
+
+        let filled = self.filled;
+
+        &mut self.initialized_mut()[filled..filled + n]
+    }
+
+    /// Returns the number of bytes at the end of the slice that have not yet been filled.
+    #[inline]
+    pub fn remaining(&self) -> usize {
+        self.capacity() - self.filled
+    }
+
+    /// Clears the buffer, resetting the filled region to empty.
+    ///
+    /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
+    #[inline]
+    pub fn clear(&mut self) {
+        self.set_filled(0); // The assertion in `set_filled` is optimized out
+    }
+
+    /// Increases the size of the filled region of the buffer.
+    ///
+    /// The number of initialized bytes is not changed.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the filled region of the buffer would become larger than the initialized region.
+    #[inline]
+    pub fn add_filled(&mut self, n: usize) {
+        self.set_filled(self.filled + n);
+    }
+
+    /// Sets the size of the filled region of the buffer.
+    ///
+    /// The number of initialized bytes is not changed.
+    ///
+    /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
+    /// example, by a `Read` implementation that compresses data in-place).
+    ///
+    /// # Panics
+    ///
+    /// Panics if the filled region of the buffer would become larger than the initialized region.
+    #[inline]
+    pub fn set_filled(&mut self, n: usize) {
+        assert!(n <= self.initialized);
+
+        self.filled = n;
+    }
+
+    /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
+    ///
+    /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
+    /// bytes than are already known to be initialized.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
+    #[inline]
+    pub unsafe fn assume_init(&mut self, n: usize) {
+        self.initialized = cmp::max(self.initialized, self.filled + n);
+    }
+
+    /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `self.remaining()` is less than `buf.len()`.
+    #[inline]
+    pub fn append(&mut self, buf: &[u8]) {
+        assert!(self.remaining() >= buf.len());
+
+        // SAFETY: we do not de-initialize any of the elements of the slice
+        unsafe {
+            MaybeUninit::write_slice(&mut self.unfilled_mut()[..buf.len()], buf);
+        }
+
+        // SAFETY: We just added the entire contents of buf to the filled section.
+        unsafe { self.assume_init(buf.len()) }
+        self.add_filled(buf.len());
+    }
+
+    /// Returns the amount of bytes that have been filled.
+    #[inline]
+    pub fn filled_len(&self) -> usize {
+        self.filled
+    }
+
+    /// Returns the amount of bytes that have been initialized.
+    #[inline]
+    pub fn initialized_len(&self) -> usize {
+        self.initialized
+    }
+}
diff --git a/library/std/src/io/readbuf/tests.rs b/library/std/src/io/readbuf/tests.rs
new file mode 100644
index 00000000000..3b7a5a56d22
--- /dev/null
+++ b/library/std/src/io/readbuf/tests.rs
@@ -0,0 +1,181 @@
+use super::ReadBuf;
+use crate::mem::MaybeUninit;
+
+/// Test that ReadBuf has the correct numbers when created with new
+#[test]
+fn new() {
+    let mut buf = [0; 16];
+    let rbuf = ReadBuf::new(&mut buf);
+
+    assert_eq!(rbuf.filled_len(), 0);
+    assert_eq!(rbuf.initialized_len(), 16);
+    assert_eq!(rbuf.capacity(), 16);
+    assert_eq!(rbuf.remaining(), 16);
+}
+
+/// Test that ReadBuf has the correct numbers when created with uninit
+#[test]
+fn uninit() {
+    let mut buf = [MaybeUninit::uninit(); 16];
+    let rbuf = ReadBuf::uninit(&mut buf);
+
+    assert_eq!(rbuf.filled_len(), 0);
+    assert_eq!(rbuf.initialized_len(), 0);
+    assert_eq!(rbuf.capacity(), 16);
+    assert_eq!(rbuf.remaining(), 16);
+}
+
+#[test]
+fn initialize_unfilled() {
+    let mut buf = [MaybeUninit::uninit(); 16];
+    let mut rbuf = ReadBuf::uninit(&mut buf);
+
+    rbuf.initialize_unfilled();
+
+    assert_eq!(rbuf.initialized_len(), 16);
+}
+
+#[test]
+fn initialize_unfilled_to() {
+    let mut buf = [MaybeUninit::uninit(); 16];
+    let mut rbuf = ReadBuf::uninit(&mut buf);
+
+    rbuf.initialize_unfilled_to(8);
+
+    assert_eq!(rbuf.initialized_len(), 8);
+
+    rbuf.initialize_unfilled_to(4);
+
+    assert_eq!(rbuf.initialized_len(), 8);
+
+    rbuf.set_filled(8);
+
+    rbuf.initialize_unfilled_to(6);
+
+    assert_eq!(rbuf.initialized_len(), 14);
+
+    rbuf.initialize_unfilled_to(8);
+
+    assert_eq!(rbuf.initialized_len(), 16);
+}
+
+#[test]
+fn add_filled() {
+    let mut buf = [0; 16];
+    let mut rbuf = ReadBuf::new(&mut buf);
+
+    rbuf.add_filled(1);
+
+    assert_eq!(rbuf.filled_len(), 1);
+    assert_eq!(rbuf.remaining(), 15);
+}
+
+#[test]
+#[should_panic]
+fn add_filled_panic() {
+    let mut buf = [MaybeUninit::uninit(); 16];
+    let mut rbuf = ReadBuf::uninit(&mut buf);
+
+    rbuf.add_filled(1);
+}
+
+#[test]
+fn set_filled() {
+    let mut buf = [0; 16];
+    let mut rbuf = ReadBuf::new(&mut buf);
+
+    rbuf.set_filled(16);
+
+    assert_eq!(rbuf.filled_len(), 16);
+    assert_eq!(rbuf.remaining(), 0);
+
+    rbuf.set_filled(6);
+
+    assert_eq!(rbuf.filled_len(), 6);
+    assert_eq!(rbuf.remaining(), 10);
+}
+
+#[test]
+#[should_panic]
+fn set_filled_panic() {
+    let mut buf = [MaybeUninit::uninit(); 16];
+    let mut rbuf = ReadBuf::uninit(&mut buf);
+
+    rbuf.set_filled(16);
+}
+
+#[test]
+fn clear() {
+    let mut buf = [255; 16];
+    let mut rbuf = ReadBuf::new(&mut buf);
+
+    rbuf.set_filled(16);
+
+    assert_eq!(rbuf.filled_len(), 16);
+    assert_eq!(rbuf.remaining(), 0);
+
+    rbuf.clear();
+
+    assert_eq!(rbuf.filled_len(), 0);
+    assert_eq!(rbuf.remaining(), 16);
+
+    assert_eq!(rbuf.initialized(), [255; 16]);
+}
+
+#[test]
+fn assume_init() {
+    let mut buf = [MaybeUninit::uninit(); 16];
+    let mut rbuf = ReadBuf::uninit(&mut buf);
+
+    unsafe {
+        rbuf.assume_init(8);
+    }
+
+    assert_eq!(rbuf.initialized_len(), 8);
+
+    rbuf.add_filled(4);
+
+    unsafe {
+        rbuf.assume_init(2);
+    }
+
+    assert_eq!(rbuf.initialized_len(), 8);
+
+    unsafe {
+        rbuf.assume_init(8);
+    }
+
+    assert_eq!(rbuf.initialized_len(), 12);
+}
+
+#[test]
+fn append() {
+    let mut buf = [MaybeUninit::new(255); 16];
+    let mut rbuf = ReadBuf::uninit(&mut buf);
+
+    rbuf.append(&[0; 8]);
+
+    assert_eq!(rbuf.initialized_len(), 8);
+    assert_eq!(rbuf.filled_len(), 8);
+    assert_eq!(rbuf.filled(), [0; 8]);
+
+    rbuf.clear();
+
+    rbuf.append(&[1; 16]);
+
+    assert_eq!(rbuf.initialized_len(), 16);
+    assert_eq!(rbuf.filled_len(), 16);
+    assert_eq!(rbuf.filled(), [1; 16]);
+}
+
+#[test]
+fn filled_mut() {
+    let mut buf = [0; 16];
+    let mut rbuf = ReadBuf::new(&mut buf);
+
+    rbuf.add_filled(8);
+
+    let filled = rbuf.filled().to_vec();
+
+    assert_eq!(&*filled, &*rbuf.filled_mut());
+}
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index f7fc23c1e82..c072f0cafe4 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -7,7 +7,7 @@ use crate::io::prelude::*;
 
 use crate::cell::{Cell, RefCell};
 use crate::fmt;
-use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Lines, Split};
+use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, Split};
 use crate::lazy::SyncOnceCell;
 use crate::pin::Pin;
 use crate::sync::atomic::{AtomicBool, Ordering};
@@ -108,11 +108,6 @@ impl Read for StdinRaw {
         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> {
         handle_ebadf(self.0.read_to_end(buf), 0)
     }
@@ -514,10 +509,6 @@ impl Read for Stdin {
     fn is_read_vectored(&self) -> bool {
         self.lock().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.lock().read_to_end(buf)
     }
@@ -552,11 +543,6 @@ impl Read for StdinLock<'_> {
         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)
     }
@@ -1193,7 +1179,7 @@ where
             })
         }) == Ok(Some(()))
     {
-        // Succesfully wrote to capture buffer.
+        // Successfully wrote to capture buffer.
         return;
     }
 
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 0321a2b60b1..ea49bfe3421 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -1,7 +1,8 @@
-use super::{repeat, Cursor, SeekFrom};
+use super::{repeat, Cursor, ReadBuf, SeekFrom};
 use crate::cmp::{self, min};
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::io::{BufRead, BufReader, Read, Seek, Write};
+use crate::mem::MaybeUninit;
 use crate::ops::Deref;
 
 #[test]
@@ -157,6 +158,28 @@ fn read_exact_slice() {
 }
 
 #[test]
+fn read_buf_exact() {
+    let mut buf = [0; 4];
+    let mut buf = ReadBuf::new(&mut buf);
+
+    let mut c = Cursor::new(&b""[..]);
+    assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+
+    let mut c = Cursor::new(&b"123456789"[..]);
+    c.read_buf_exact(&mut buf).unwrap();
+    assert_eq!(buf.filled(), b"1234");
+
+    buf.clear();
+
+    c.read_buf_exact(&mut buf).unwrap();
+    assert_eq!(buf.filled(), b"5678");
+
+    buf.clear();
+
+    assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+}
+
+#[test]
 fn take_eof() {
     struct R;
 
@@ -559,3 +582,23 @@ fn test_write_all_vectored() {
         }
     }
 }
+
+#[bench]
+fn bench_take_read(b: &mut test::Bencher) {
+    b.iter(|| {
+        let mut buf = [0; 64];
+
+        [255; 128].take(64).read(&mut buf).unwrap();
+    });
+}
+
+#[bench]
+fn bench_take_read_buf(b: &mut test::Bencher) {
+    b.iter(|| {
+        let mut buf = [MaybeUninit::uninit(); 64];
+
+        let mut rbuf = ReadBuf::uninit(&mut buf);
+
+        [255; 128].take(64).read_buf(&mut rbuf).unwrap();
+    });
+}
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index 9cd7c514849..c1300cd67c0 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -5,7 +5,7 @@ mod tests;
 
 use crate::fmt;
 use crate::io::{
-    self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
+    self, BufRead, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, Write,
 };
 
 /// A reader which is always at EOF.
@@ -47,8 +47,8 @@ impl Read for Empty {
     }
 
     #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
+    fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        Ok(())
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -130,6 +130,24 @@ impl Read for Repeat {
         Ok(buf.len())
     }
 
+    fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        // SAFETY: No uninit bytes are being written
+        for slot in unsafe { buf.unfilled_mut() } {
+            slot.write(self.byte);
+        }
+
+        let remaining = buf.remaining();
+
+        // SAFETY: the entire unfilled portion of buf has been initialized
+        unsafe {
+            buf.assume_init(remaining);
+        }
+
+        buf.add_filled(remaining);
+
+        Ok(())
+    }
+
     #[inline]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let mut nwritten = 0;
@@ -143,11 +161,6 @@ impl Read for Repeat {
     fn is_read_vectored(&self) -> bool {
         true
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl SizeHint for Repeat {
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index 7632eaf872a..08972a59a83 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,9 +1,12 @@
 use crate::cmp::{max, min};
 use crate::io::prelude::*;
 use crate::io::{
-    copy, empty, repeat, sink, BufWriter, Empty, Repeat, Result, SeekFrom, Sink, DEFAULT_BUF_SIZE,
+    copy, empty, repeat, sink, BufWriter, Empty, ReadBuf, Repeat, Result, SeekFrom, Sink,
+    DEFAULT_BUF_SIZE,
 };
 
+use crate::mem::MaybeUninit;
+
 #[test]
 fn copy_copies() {
     let mut r = repeat(0).take(4);
@@ -75,6 +78,30 @@ fn empty_reads() {
     assert_eq!(e.read(&mut [0]).unwrap(), 0);
     assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
     assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
+
+    let mut buf = [];
+    let mut buf = ReadBuf::uninit(&mut buf);
+    e.read_buf(&mut buf).unwrap();
+    assert_eq!(buf.filled_len(), 0);
+    assert_eq!(buf.initialized_len(), 0);
+
+    let mut buf = [MaybeUninit::uninit()];
+    let mut buf = ReadBuf::uninit(&mut buf);
+    e.read_buf(&mut buf).unwrap();
+    assert_eq!(buf.filled_len(), 0);
+    assert_eq!(buf.initialized_len(), 0);
+
+    let mut buf = [MaybeUninit::uninit(); 1024];
+    let mut buf = ReadBuf::uninit(&mut buf);
+    e.read_buf(&mut buf).unwrap();
+    assert_eq!(buf.filled_len(), 0);
+    assert_eq!(buf.initialized_len(), 0);
+
+    let mut buf = [MaybeUninit::uninit(); 1024];
+    let mut buf = ReadBuf::uninit(&mut buf);
+    e.by_ref().read_buf(&mut buf).unwrap();
+    assert_eq!(buf.filled_len(), 0);
+    assert_eq!(buf.initialized_len(), 0);
 }
 
 #[test]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index afd8d8edaa1..22e721d79bf 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -216,10 +216,7 @@
 // std may use features in a platform-specific way
 #![allow(unused_features)]
 #![feature(rustc_allow_const_fn_unstable)]
-#![cfg_attr(
-    test,
-    feature(internal_output_capture, print_internals, update_panic_count, thread_local_const_init)
-)]
+#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
 #![cfg_attr(
     all(target_vendor = "fortanix", target_env = "sgx"),
     feature(slice_index_methods, coerce_unsized, sgx_platform)
@@ -236,7 +233,6 @@
 #![feature(allow_internal_unstable)]
 #![feature(arbitrary_self_types)]
 #![feature(array_error_internals)]
-#![feature(asm)]
 #![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(async_stream)]
@@ -253,8 +249,8 @@
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
 #![feature(char_internals)]
+#![cfg_attr(not(bootstrap), feature(concat_bytes))]
 #![feature(concat_idents)]
-#![feature(const_cstr_unchecked)]
 #![feature(const_fn_floating_point_arithmetic)]
 #![feature(const_fn_fn_ptr_basics)]
 #![feature(const_fn_trait_bound)]
@@ -264,8 +260,7 @@
 #![feature(const_ipv4)]
 #![feature(const_ipv6)]
 #![feature(const_option)]
-#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
-#![cfg_attr(not(bootstrap), feature(const_mut_refs))]
+#![feature(const_mut_refs)]
 #![feature(const_socketaddr)]
 #![feature(const_trait_impl)]
 #![feature(container_error_extra)]
@@ -275,10 +270,9 @@
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
 #![feature(doc_cfg_hide)]
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
-#![feature(doc_primitive)]
 #![feature(dropck_eyepatch)]
 #![feature(duration_checked_float)]
 #![feature(duration_constants)]
@@ -292,14 +286,12 @@
 #![feature(gen_future)]
 #![feature(generator_trait)]
 #![feature(get_mut_unchecked)]
-#![feature(global_asm)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
 #![feature(integer_atomics)]
 #![feature(int_log)]
 #![feature(into_future)]
 #![feature(intra_doc_pointers)]
-#![feature(iter_zip)]
 #![feature(lang_items)]
 #![feature(linkage)]
 #![feature(llvm_asm)]
@@ -308,6 +300,7 @@
 #![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
+#![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
 #![feature(mixed_integer_ops)]
 #![feature(must_not_suspend)]
@@ -322,8 +315,9 @@
 #![feature(panic_internals)]
 #![feature(panic_unwind)]
 #![feature(pin_static_ref)]
-#![cfg_attr(not(bootstrap), feature(portable_simd))]
+#![feature(portable_simd)]
 #![feature(prelude_import)]
+#![feature(ptr_as_uninit)]
 #![feature(ptr_internals)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
@@ -475,7 +469,6 @@ pub use core::ptr;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::result;
 #[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(bootstrap))]
 pub use core::simd;
 #[unstable(feature = "async_stream", issue = "79024")]
 pub use core::stream;
@@ -582,6 +575,14 @@ pub use core::{
     log_syntax, module_path, option_env, stringify, trace_macros,
 };
 
+#[unstable(
+    feature = "concat_bytes",
+    issue = "87555",
+    reason = "`concat_bytes` is not stable enough for use and is subject to change"
+)]
+#[cfg(not(bootstrap))]
+pub use core::concat_bytes;
+
 #[stable(feature = "core_primitive", since = "1.43.0")]
 pub use core::primitive;
 
diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs
index 17581f33026..632d4683b41 100644
--- a/library/std/src/net/ip/tests.rs
+++ b/library/std/src/net/ip/tests.rs
@@ -749,7 +749,7 @@ fn ipv4_from_constructors() {
 }
 
 #[test]
-fn ipv6_from_contructors() {
+fn ipv6_from_constructors() {
     assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
     assert!(Ipv6Addr::LOCALHOST.is_loopback());
     assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 5738862fb58..1ba54d892e3 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -6,7 +6,7 @@ mod tests;
 use crate::io::prelude::*;
 
 use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sys_common::net as net_imp;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -626,12 +626,6 @@ impl Read for TcpStream {
     fn is_read_vectored(&self) -> bool {
         self.0.is_read_vectored()
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        unsafe { Initializer::nop() }
-    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for TcpStream {
@@ -666,12 +660,6 @@ impl Read for &TcpStream {
     fn is_read_vectored(&self) -> bool {
         self.0.is_read_vectored()
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        unsafe { Initializer::nop() }
-    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for &TcpStream {
diff --git a/library/std/src/os/fortanix_sgx/arch.rs b/library/std/src/os/fortanix_sgx/arch.rs
index 4ce482e23cb..8358cb9e81b 100644
--- a/library/std/src/os/fortanix_sgx/arch.rs
+++ b/library/std/src/os/fortanix_sgx/arch.rs
@@ -5,6 +5,7 @@
 #![unstable(feature = "sgx_platform", issue = "56975")]
 
 use crate::mem::MaybeUninit;
+use core::arch::asm;
 
 /// Wrapper struct to force 16-byte alignment.
 #[repr(align(16))]
diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs
index 01392ffab79..f0b38d29845 100644
--- a/library/std/src/os/raw/mod.rs
+++ b/library/std/src/os/raw/mod.rs
@@ -69,7 +69,8 @@ type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8;
             target_arch = "aarch64",
             target_arch = "arm",
             target_arch = "powerpc",
-            target_arch = "powerpc64"
+            target_arch = "powerpc64",
+            target_arch = "riscv64"
         )
     ),
     all(
@@ -112,7 +113,8 @@ type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8;
             target_arch = "aarch64",
             target_arch = "arm",
             target_arch = "powerpc",
-            target_arch = "powerpc64"
+            target_arch = "powerpc64",
+            target_arch = "riscv64"
         )
     ),
     all(
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 6120d557227..583f861a925 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -11,7 +11,7 @@
 use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
 use super::{sockaddr_un, SocketAddr};
 use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::Shutdown;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 #[cfg(any(
@@ -624,11 +624,6 @@ impl io::Read for UnixStream {
     fn is_read_vectored(&self) -> bool {
         io::Read::is_read_vectored(&&*self)
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 #[stable(feature = "unix_socket", since = "1.10.0")]
@@ -645,11 +640,6 @@ impl<'a> io::Read for &'a UnixStream {
     fn is_read_vectored(&self) -> bool {
         self.0.is_read_vectored()
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 #[stable(feature = "unix_socket", since = "1.10.0")]
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
index be35ab0ca1e..31d1e3c1e42 100644
--- a/library/std/src/os/windows/fs.rs
+++ b/library/std/src/os/windows/fs.rs
@@ -543,6 +543,16 @@ impl FileTypeExt for fs::FileType {
 ///     Ok(())
 /// }
 /// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
 #[stable(feature = "symlink", since = "1.1.0")]
 pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
     sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
@@ -572,6 +582,16 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io:
 ///     Ok(())
 /// }
 /// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
 #[stable(feature = "symlink", since = "1.1.0")]
 pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
     sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 6fc6b8daec0..87854fe4f29 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -365,7 +365,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     // The call to `intrinsics::r#try` is made safe by:
     // - `do_call`, the first argument, can be called with the initial `data_ptr`.
     // - `do_catch`, the second argument, can be called with the `data_ptr` as well.
-    // See their safety preconditions for more informations
+    // See their safety preconditions for more information
     unsafe {
         return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
             Ok(ManuallyDrop::into_inner(data.r))
@@ -398,7 +398,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     // expects normal function pointers.
     #[inline]
     fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
-        // SAFETY: this is the responsibilty of the caller, see above.
+        // SAFETY: this is the responsibility of the caller, see above.
         unsafe {
             let data = data as *mut Data<F, R>;
             let data = &mut (*data);
@@ -420,7 +420,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     // expects normal function pointers.
     #[inline]
     fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
-        // SAFETY: this is the responsibilty of the caller, see above.
+        // SAFETY: this is the responsibility of the caller, see above.
         //
         // When `__rustc_panic_cleaner` is correctly implemented we can rely
         // on `obj` being the correct thing to pass to `data.p` (after wrapping
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index cf2cd5adc48..7d401cff591 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -12,6 +12,13 @@
 //! [`PathBuf`]; note that the paths may differ syntactically by the
 //! normalization described in the documentation for the [`components`] method.
 //!
+//! ## Case sensitivity
+//!
+//! Unless otherwise indicated path methods that do not access the filesystem,
+//! such as [`Path::starts_with`] and [`Path::ends_with`], are case sensitive no
+//! matter the platform or filesystem. An exception to this is made for Windows
+//! drive letters.
+//!
 //! ## Simple usage
 //!
 //! Path manipulation includes both parsing components from slices and building
@@ -2810,7 +2817,7 @@ impl Path {
     /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
     /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
     #[must_use]
-    #[stable(feature = "is_symlink", since = "1.57.0")]
+    #[stable(feature = "is_symlink", since = "1.58.0")]
     pub fn is_symlink(&self) -> bool {
         fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
     }
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 772044f0149..743dd51333d 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -46,20 +46,13 @@ pub use core::prelude::v1::{
 };
 
 #[unstable(
-    feature = "asm",
-    issue = "72016",
-    reason = "inline assembly is not stable enough for use and is subject to change"
+    feature = "concat_bytes",
+    issue = "87555",
+    reason = "`concat_bytes` is not stable enough for use and is subject to change"
 )]
+#[cfg(not(bootstrap))]
 #[doc(no_inline)]
-pub use core::prelude::v1::asm;
-
-#[unstable(
-    feature = "global_asm",
-    issue = "35119",
-    reason = "`global_asm!` is not stable enough for use and is subject to change"
-)]
-#[doc(no_inline)]
-pub use core::prelude::v1::global_asm;
+pub use core::prelude::v1::concat_bytes;
 
 // FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates
 // dead links which fail link checker testing.
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index f47a30c9b5d..8fcd8cdeb10 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -606,8 +606,7 @@ mod prim_pointer {}
 ///     println!("array[{}] = {}", i, x);
 /// }
 ///
-/// // You can explicitly iterate an array by value using
-/// // `IntoIterator::into_iter` or `std::array::IntoIter::new`:
+/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
 ///     println!("array[{}] = {}", i, x);
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 4e9fd51f282..e012594dd46 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -110,7 +110,7 @@ use crate::convert::Infallible;
 use crate::ffi::OsStr;
 use crate::fmt;
 use crate::fs;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
 use crate::num::NonZeroI32;
 use crate::path::Path;
 use crate::str;
@@ -362,12 +362,6 @@ impl Read for ChildStdout {
     fn is_read_vectored(&self) -> bool {
         self.inner.is_read_vectored()
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        unsafe { Initializer::nop() }
-    }
 }
 
 impl AsInner<AnonPipe> for ChildStdout {
@@ -429,12 +423,6 @@ impl Read for ChildStderr {
     fn is_read_vectored(&self) -> bool {
         self.inner.is_read_vectored()
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        // SAFETY: Read is guaranteed to work on uninitialized memory
-        unsafe { Initializer::nop() }
-    }
 }
 
 impl AsInner<AnonPipe> for ChildStderr {
@@ -1612,7 +1600,6 @@ impl ExitStatusError {
     /// ```
     /// #![feature(exit_status_error)]
     /// # if cfg!(unix) {
-    /// use std::convert::TryFrom;
     /// use std::num::NonZeroI32;
     /// use std::process::Command;
     ///
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 094d2efbdd5..67b747e4107 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -4,15 +4,23 @@ use super::{Command, Output, Stdio};
 use crate::io::ErrorKind;
 use crate::str;
 
-// FIXME(#10380) these tests should not all be ignored on android.
+#[cfg(target_os = "android")]
+fn shell_cmd() -> Command {
+    Command::new("/system/bin/sh")
+}
+
+#[cfg(not(target_os = "android"))]
+fn shell_cmd() -> Command {
+    Command::new("/bin/sh")
+}
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn smoke() {
     let p = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "exit 0"]).spawn()
     } else {
-        Command::new("true").spawn()
+        shell_cmd().arg("-c").arg("true").spawn()
     };
     assert!(p.is_ok());
     let mut p = p.unwrap();
@@ -29,12 +37,12 @@ fn smoke_failure() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn exit_reported_right() {
     let p = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "exit 1"]).spawn()
     } else {
-        Command::new("false").spawn()
+        shell_cmd().arg("-c").arg("false").spawn()
     };
     assert!(p.is_ok());
     let mut p = p.unwrap();
@@ -44,12 +52,11 @@ fn exit_reported_right() {
 
 #[test]
 #[cfg(unix)]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn signal_reported_right() {
     use crate::os::unix::process::ExitStatusExt;
 
-    let mut p =
-        Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap();
+    let mut p = shell_cmd().arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap();
     p.kill().unwrap();
     match p.wait().unwrap().signal() {
         Some(9) => {}
@@ -69,31 +76,31 @@ pub fn run_output(mut cmd: Command) -> String {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn stdout_works() {
     if cfg!(target_os = "windows") {
         let mut cmd = Command::new("cmd");
         cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped());
         assert_eq!(run_output(cmd), "foobar\r\n");
     } else {
-        let mut cmd = Command::new("echo");
-        cmd.arg("foobar").stdout(Stdio::piped());
+        let mut cmd = shell_cmd();
+        cmd.arg("-c").arg("echo foobar").stdout(Stdio::piped());
         assert_eq!(run_output(cmd), "foobar\n");
     }
 }
 
 #[test]
-#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
+#[cfg_attr(any(windows, target_os = "vxworks"), ignore)]
 fn set_current_dir_works() {
-    let mut cmd = Command::new("/bin/sh");
+    let mut cmd = shell_cmd();
     cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
     assert_eq!(run_output(cmd), "/\n");
 }
 
 #[test]
-#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
+#[cfg_attr(any(windows, target_os = "vxworks"), ignore)]
 fn stdin_works() {
-    let mut p = Command::new("/bin/sh")
+    let mut p = shell_cmd()
         .arg("-c")
         .arg("read line; echo $line")
         .stdin(Stdio::piped())
@@ -109,19 +116,19 @@ fn stdin_works() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn test_process_status() {
     let mut status = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
     } else {
-        Command::new("false").status().unwrap()
+        shell_cmd().arg("-c").arg("false").status().unwrap()
     };
     assert!(status.code() == Some(1));
 
     status = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap()
     } else {
-        Command::new("true").status().unwrap()
+        shell_cmd().arg("-c").arg("true").status().unwrap()
     };
     assert!(status.success());
 }
@@ -135,12 +142,12 @@ fn test_process_output_fail_to_start() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn test_process_output_output() {
     let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap()
     } else {
-        Command::new("echo").arg("hello").output().unwrap()
+        shell_cmd().arg("-c").arg("echo hello").output().unwrap()
     };
     let output_str = str::from_utf8(&stdout).unwrap();
 
@@ -150,7 +157,7 @@ fn test_process_output_output() {
 }
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn test_process_output_error() {
     let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap()
@@ -158,41 +165,42 @@ fn test_process_output_error() {
         Command::new("mkdir").arg("./").output().unwrap()
     };
 
-    assert!(status.code() == Some(1));
+    assert!(status.code().is_some());
+    assert!(status.code() != Some(0));
     assert_eq!(stdout, Vec::new());
     assert!(!stderr.is_empty());
 }
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn test_finish_once() {
     let mut prog = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
     } else {
-        Command::new("false").spawn().unwrap()
+        shell_cmd().arg("-c").arg("false").spawn().unwrap()
     };
     assert!(prog.wait().unwrap().code() == Some(1));
 }
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn test_finish_twice() {
     let mut prog = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
     } else {
-        Command::new("false").spawn().unwrap()
+        shell_cmd().arg("-c").arg("false").spawn().unwrap()
     };
     assert!(prog.wait().unwrap().code() == Some(1));
     assert!(prog.wait().unwrap().code() == Some(1));
 }
 
 #[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
 fn test_wait_with_output_once() {
     let prog = if cfg!(target_os = "windows") {
         Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap()
     } else {
-        Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap()
+        shell_cmd().arg("-c").arg("echo hello").stdout(Stdio::piped()).spawn().unwrap()
     };
 
     let Output { status, stdout, stderr } = prog.wait_with_output().unwrap();
diff --git a/library/std/src/sys/hermit/fd.rs b/library/std/src/sys/hermit/fd.rs
index c400f5f2c2e..1179a49c22f 100644
--- a/library/std/src/sys/hermit/fd.rs
+++ b/library/std/src/sys/hermit/fd.rs
@@ -1,6 +1,6 @@
 #![unstable(reason = "not public", issue = "none", feature = "fd")]
 
-use crate::io::{self, Read};
+use crate::io::{self, Read, ReadBuf};
 use crate::mem;
 use crate::sys::cvt;
 use crate::sys::hermit::abi;
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index be019d4435d..974c44eb8dd 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -2,7 +2,7 @@ use crate::ffi::{CStr, CString, OsString};
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::io::{self, Error, ErrorKind};
-use crate::io::{IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 use crate::os::unix::ffi::OsStrExt;
 use crate::path::{Path, PathBuf};
 use crate::sys::cvt;
@@ -312,6 +312,10 @@ impl File {
         false
     }
 
+    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|buf| self.read(buf), buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
index 691e7e07902..415cbba101c 100644
--- a/library/std/src/sys/hermit/mutex.rs
+++ b/library/std/src/sys/hermit/mutex.rs
@@ -46,8 +46,17 @@ impl<T> Spinlock<T> {
     #[inline]
     fn obtain_lock(&self) {
         let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
+        let mut counter: u16 = 0;
         while self.dequeue.load(Ordering::SeqCst) != ticket {
-            hint::spin_loop();
+            counter += 1;
+            if counter < 100 {
+                hint::spin_loop();
+            } else {
+                counter = 0;
+                unsafe {
+                    abi::yield_now();
+                }
+            }
         }
     }
 
diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs
index bb9fa54d02e..ebcc9ab26e0 100644
--- a/library/std/src/sys/itron/thread.rs
+++ b/library/std/src/sys/itron/thread.rs
@@ -126,7 +126,7 @@ impl Thread {
                     // In this case, `inner`'s ownership has been moved to us,
                     // And we are responsible for dropping it. The acquire
                     // ordering is not necessary because the parent thread made
-                    // no memory acccess needing synchronization since the call
+                    // no memory access needing synchronization since the call
                     // to `acre_tsk`.
                     // Safety: See above.
                     let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) };
@@ -264,7 +264,7 @@ impl Drop for Thread {
                 // one will ever join it.
                 // The ownership of `self.inner` is moved to the child thread.
                 // However, the release ordering is not necessary because we
-                // made no memory acccess needing synchronization since the call
+                // made no memory access needing synchronization since the call
                 // to `acre_tsk`.
             }
             LIFECYCLE_FINISHED => {
diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs
index 52e8bec937c..18e6d5b3fa2 100644
--- a/library/std/src/sys/sgx/abi/mem.rs
+++ b/library/std/src/sys/sgx/abi/mem.rs
@@ -1,3 +1,5 @@
+use core::arch::asm;
+
 // Do not remove inline: will result in relocation failure
 #[inline(always)]
 pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T {
diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs
index 231cc15b849..5df08a4ff59 100644
--- a/library/std/src/sys/sgx/abi/mod.rs
+++ b/library/std/src/sys/sgx/abi/mod.rs
@@ -1,6 +1,7 @@
 #![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test
 
 use crate::io::Write;
+use core::arch::global_asm;
 use core::sync::atomic::{AtomicUsize, Ordering};
 
 // runtime features
diff --git a/library/std/src/sys/solid/abi/mod.rs b/library/std/src/sys/solid/abi/mod.rs
index 3205f0db85f..1afc83f766d 100644
--- a/library/std/src/sys/solid/abi/mod.rs
+++ b/library/std/src/sys/solid/abi/mod.rs
@@ -10,9 +10,9 @@ pub fn breakpoint_program_exited(tid: usize) {
         match () {
             // SOLID_BP_PROGRAM_EXITED = 15
             #[cfg(target_arch = "arm")]
-            () => asm!("bkpt #15", in("r0") tid),
+            () => core::arch::asm!("bkpt #15", in("r0") tid),
             #[cfg(target_arch = "aarch64")]
-            () => asm!("hlt #15", in("x0") tid),
+            () => core::arch::asm!("hlt #15", in("x0") tid),
         }
     }
 }
@@ -23,9 +23,9 @@ pub fn breakpoint_abort() {
         match () {
             // SOLID_BP_CSABORT = 16
             #[cfg(target_arch = "arm")]
-            () => asm!("bkpt #16"),
+            () => core::arch::asm!("bkpt #16"),
             #[cfg(target_arch = "aarch64")]
-            () => asm!("hlt #16"),
+            () => core::arch::asm!("hlt #16"),
         }
     }
 }
diff --git a/library/std/src/sys/unix/android.rs b/library/std/src/sys/unix/android.rs
index 6a46525f682..73ff10ab8a2 100644
--- a/library/std/src/sys/unix/android.rs
+++ b/library/std/src/sys/unix/android.rs
@@ -18,11 +18,9 @@
 
 #![cfg(target_os = "android")]
 
-use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
-use libc::{ftruncate, pread, pwrite};
+use libc::{c_int, sighandler_t};
 
-use super::{cvt, cvt_r, weak::weak};
-use crate::io;
+use super::weak::weak;
 
 // The `log2` and `log2f` functions apparently appeared in android-18, or at
 // least you can see they're not present in the android-17 header [1] and they
@@ -81,87 +79,3 @@ pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
     let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
     f(signum, handler)
 }
-
-// The `ftruncate64` symbol apparently appeared in android-12, so we do some
-// dynamic detection to see if we can figure out whether `ftruncate64` exists.
-//
-// If it doesn't we just fall back to `ftruncate`, generating an error for
-// too-large values.
-#[cfg(target_pointer_width = "32")]
-pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
-    weak!(fn ftruncate64(c_int, i64) -> c_int);
-
-    unsafe {
-        match ftruncate64.get() {
-            Some(f) => cvt_r(|| f(fd, size as i64)).map(drop),
-            None => {
-                if size > i32::MAX as u64 {
-                    Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot truncate >2GB"))
-                } else {
-                    cvt_r(|| ftruncate(fd, size as i32)).map(drop)
-                }
-            }
-        }
-    }
-}
-
-#[cfg(target_pointer_width = "64")]
-pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
-    unsafe { cvt_r(|| ftruncate(fd, size as i64)).map(drop) }
-}
-
-#[cfg(target_pointer_width = "32")]
-pub unsafe fn cvt_pread64(
-    fd: c_int,
-    buf: *mut c_void,
-    count: size_t,
-    offset: i64,
-) -> io::Result<ssize_t> {
-    use crate::convert::TryInto;
-    weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
-    pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
-        if let Ok(o) = offset.try_into() {
-            cvt(pread(fd, buf, count, o))
-        } else {
-            Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pread >2GB"))
-        }
-    })
-}
-
-#[cfg(target_pointer_width = "32")]
-pub unsafe fn cvt_pwrite64(
-    fd: c_int,
-    buf: *const c_void,
-    count: size_t,
-    offset: i64,
-) -> io::Result<ssize_t> {
-    use crate::convert::TryInto;
-    weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
-    pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
-        if let Ok(o) = offset.try_into() {
-            cvt(pwrite(fd, buf, count, o))
-        } else {
-            Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pwrite >2GB"))
-        }
-    })
-}
-
-#[cfg(target_pointer_width = "64")]
-pub unsafe fn cvt_pread64(
-    fd: c_int,
-    buf: *mut c_void,
-    count: size_t,
-    offset: i64,
-) -> io::Result<ssize_t> {
-    cvt(pread(fd, buf, count, offset))
-}
-
-#[cfg(target_pointer_width = "64")]
-pub unsafe fn cvt_pwrite64(
-    fd: c_int,
-    buf: *const c_void,
-    count: size_t,
-    offset: i64,
-) -> io::Result<ssize_t> {
-    cvt(pwrite(fd, buf, count, offset))
-}
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 0956726084e..2362bff913f 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -4,7 +4,7 @@
 mod tests;
 
 use crate::cmp;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
+use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -99,34 +99,39 @@ impl FileDesc {
     }
 
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        #[cfg(target_os = "android")]
-        use super::android::cvt_pread64;
-
-        #[cfg(not(target_os = "android"))]
-        unsafe fn cvt_pread64(
-            fd: c_int,
-            buf: *mut c_void,
-            count: usize,
-            offset: i64,
-        ) -> io::Result<isize> {
-            #[cfg(not(target_os = "linux"))]
-            use libc::pread as pread64;
-            #[cfg(target_os = "linux")]
-            use libc::pread64;
-            cvt(pread64(fd, buf, count, offset))
-        }
+        #[cfg(not(any(target_os = "linux", target_os = "android")))]
+        use libc::pread as pread64;
+        #[cfg(any(target_os = "linux", target_os = "android"))]
+        use libc::pread64;
 
         unsafe {
-            cvt_pread64(
+            cvt(pread64(
                 self.as_raw_fd(),
                 buf.as_mut_ptr() as *mut c_void,
                 cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
-            )
+            ))
             .map(|n| n as usize)
         }
     }
 
+    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        let ret = cvt(unsafe {
+            libc::read(
+                self.as_raw_fd(),
+                buf.unfilled_mut().as_mut_ptr() as *mut c_void,
+                cmp::min(buf.remaining(), READ_LIMIT),
+            )
+        })?;
+
+        // Safety: `ret` bytes were written to the initialized portion of the buffer
+        unsafe {
+            buf.assume_init(ret as usize);
+        }
+        buf.add_filled(ret as usize);
+        Ok(())
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             libc::write(
@@ -161,30 +166,18 @@ impl FileDesc {
     }
 
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        #[cfg(target_os = "android")]
-        use super::android::cvt_pwrite64;
-
-        #[cfg(not(target_os = "android"))]
-        unsafe fn cvt_pwrite64(
-            fd: c_int,
-            buf: *const c_void,
-            count: usize,
-            offset: i64,
-        ) -> io::Result<isize> {
-            #[cfg(not(target_os = "linux"))]
-            use libc::pwrite as pwrite64;
-            #[cfg(target_os = "linux")]
-            use libc::pwrite64;
-            cvt(pwrite64(fd, buf, count, offset))
-        }
+        #[cfg(not(any(target_os = "linux", target_os = "android")))]
+        use libc::pwrite as pwrite64;
+        #[cfg(any(target_os = "linux", target_os = "android"))]
+        use libc::pwrite64;
 
         unsafe {
-            cvt_pwrite64(
+            cvt(pwrite64(
                 self.as_raw_fd(),
                 buf.as_ptr() as *const c_void,
                 cmp::min(buf.len(), READ_LIMIT),
                 offset as i64,
-            )
+            ))
             .map(|n| n as usize)
         }
     }
@@ -289,11 +282,6 @@ impl<'a> Read for &'a FileDesc {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         (**self).read(buf)
     }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
 }
 
 impl AsInner<OwnedFd> for FileDesc {
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index a4fff9b2e64..bcf2be0e95f 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -2,7 +2,7 @@ use crate::os::unix::prelude::*;
 
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
-use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 use crate::mem;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
 use crate::path::{Path, PathBuf};
@@ -46,8 +46,8 @@ use libc::fstatat64;
 use libc::readdir_r as readdir64_r;
 #[cfg(target_os = "android")]
 use libc::{
-    dirent as dirent64, fstat as fstat64, fstatat as fstatat64, lseek64, lstat as lstat64,
-    open as open64, stat as stat64,
+    dirent as dirent64, fstat as fstat64, fstatat as fstatat64, ftruncate64, lseek64,
+    lstat as lstat64, off64_t, open as open64, stat as stat64,
 };
 #[cfg(not(any(
     target_os = "linux",
@@ -835,16 +835,10 @@ impl File {
     }
 
     pub fn truncate(&self, size: u64) -> io::Result<()> {
-        #[cfg(target_os = "android")]
-        return crate::sys::android::ftruncate64(self.as_raw_fd(), size);
-
-        #[cfg(not(target_os = "android"))]
-        {
-            use crate::convert::TryInto;
-            let size: off64_t =
-                size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
-            cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
-        }
+        use crate::convert::TryInto;
+        let size: off64_t =
+            size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
+        cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
@@ -864,6 +858,10 @@ impl File {
         self.0.read_at(buf, offset)
     }
 
+    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        self.0.read_buf(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
@@ -1154,7 +1152,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
         } else if #[cfg(target_os = "macos")] {
             // On MacOS, older versions (<=10.9) lack support for linkat while newer
             // versions have it. We want to use linkat if it is available, so we use weak!
-            // to check. `linkat` is preferable to `link` ecause it gives us a flag to
+            // to check. `linkat` is preferable to `link` because it gives us a flag to
             // specify how symlinks should be handled. We pass 0 as the flags argument,
             // meaning it shouldn't follow symlinks.
             weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int);
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index a6b43229ba6..e85e4c5d618 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -104,7 +104,7 @@ impl FdMeta {
 
     fn potential_sendfile_source(&self) -> bool {
         match self {
-            // procfs erronously shows 0 length on non-empty readable files.
+            // procfs erroneously shows 0 length on non-empty readable files.
             // and if a file is truly empty then a `read` syscall will determine that and skip the write syscall
             // thus there would be benefit from attempting sendfile
             FdMeta::Metadata(meta)
@@ -576,7 +576,7 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
                 return match err.raw_os_error() {
                     // when file offset + max_length > u64::MAX
                     Some(EOVERFLOW) => CopyResult::Fallback(written),
-                    Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) => {
+                    Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) if written == 0 => {
                         // Try fallback io::copy if either:
                         // - Kernel version is < 4.5 (ENOSYS¹)
                         // - Files are mounted on different fs (EXDEV)
@@ -584,12 +584,14 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
                         // - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM)
                         // - copy_file_range cannot be used with pipes or device nodes (EINVAL)
                         // - the writer fd was opened with O_APPEND (EBADF²)
+                        // and no bytes were written successfully yet.  (All these errnos should
+                        // not be returned if something was already written, but they happen in
+                        // the wild, see #91152.)
                         //
                         // ¹ these cases should be detected by the initial probe but we handle them here
                         //   anyway in case syscall interception changes during runtime
                         // ² actually invalid file descriptors would cause this too, but in that case
                         //   the fallback code path is expected to encounter the same error again
-                        assert_eq!(written, 0);
                         CopyResult::Fallback(0)
                     }
                     _ => CopyResult::Error(err, written),
@@ -612,6 +614,9 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
     static HAS_SENDFILE: AtomicBool = AtomicBool::new(true);
     static HAS_SPLICE: AtomicBool = AtomicBool::new(true);
 
+    // Android builds use feature level 14, but the libc wrapper for splice is
+    // gated on feature level 21+, so we have to invoke the syscall directly.
+    #[cfg(target_os = "android")]
     syscall! {
         fn splice(
             srcfd: libc::c_int,
@@ -623,6 +628,9 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
         ) -> libc::ssize_t
     }
 
+    #[cfg(target_os = "linux")]
+    use libc::splice;
+
     match mode {
         SpliceMode::Sendfile if !HAS_SENDFILE.load(Ordering::Relaxed) => {
             return CopyResult::Fallback(0);
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 9ae6d12dcb9..a82a0172126 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -501,7 +501,7 @@ impl FromRawFd for Socket {
 // res_init unconditionally, we call it only when we detect we're linking
 // against glibc version < 2.26. (That is, when we both know its needed and
 // believe it's thread-safe).
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
 fn on_resolver_failure() {
     use crate::sys;
 
@@ -513,5 +513,5 @@ fn on_resolver_failure() {
     }
 }
 
-#[cfg(any(not(target_env = "gnu"), target_os = "vxworks"))]
+#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
 fn on_resolver_failure() {}
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 87893d26912..8a028d99306 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -2,7 +2,7 @@
 
 #![allow(unused_imports)] // lots of cfg code here
 
-#[cfg(all(test, target_env = "gnu"))]
+#[cfg(test)]
 mod tests;
 
 use crate::os::unix::prelude::*;
@@ -97,6 +97,7 @@ pub fn errno() -> i32 {
 }
 
 #[cfg(target_os = "dragonfly")]
+#[allow(dead_code)]
 pub fn set_errno(e: i32) {
     extern "C" {
         #[thread_local]
@@ -472,10 +473,7 @@ impl Iterator for Env {
 
 #[cfg(target_os = "macos")]
 pub unsafe fn environ() -> *mut *const *const c_char {
-    extern "C" {
-        fn _NSGetEnviron() -> *mut *const *const c_char;
-    }
-    _NSGetEnviron()
+    libc::_NSGetEnviron() as *mut *const *const c_char
 }
 
 #[cfg(not(target_os = "macos"))]
@@ -636,22 +634,14 @@ pub fn getppid() -> u32 {
     unsafe { libc::getppid() as u32 }
 }
 
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
 pub fn glibc_version() -> Option<(usize, usize)> {
-    if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
-        parse_glibc_version(version_str)
-    } else {
-        None
-    }
-}
-
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
-fn glibc_version_cstr() -> Option<&'static CStr> {
-    weak! {
-        fn gnu_get_libc_version() -> *const libc::c_char
+    extern "C" {
+        fn gnu_get_libc_version() -> *const libc::c_char;
     }
-    if let Some(f) = gnu_get_libc_version.get() {
-        unsafe { Some(CStr::from_ptr(f())) }
+    let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) };
+    if let Ok(version_str) = version_cstr.to_str() {
+        parse_glibc_version(version_str)
     } else {
         None
     }
@@ -659,7 +649,7 @@ fn glibc_version_cstr() -> Option<&'static CStr> {
 
 // Returns Some((major, minor)) if the string is a valid "x.y" version,
 // ignoring any extra dot-separated parts. Otherwise return None.
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
 fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
     let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
     match (parsed_ints.next(), parsed_ints.next()) {
diff --git a/library/std/src/sys/unix/os/tests.rs b/library/std/src/sys/unix/os/tests.rs
index c445acf2722..efc29955b05 100644
--- a/library/std/src/sys/unix/os/tests.rs
+++ b/library/std/src/sys/unix/os/tests.rs
@@ -1,14 +1,12 @@
-use super::*;
-
 #[test]
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
 fn test_glibc_version() {
     // This mostly just tests that the weak linkage doesn't panic wildly...
-    glibc_version();
+    super::glibc_version();
 }
 
 #[test]
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
 fn test_parse_glibc_version() {
     let cases = [
         ("0.0", Some((0, 0))),
@@ -20,6 +18,6 @@ fn test_parse_glibc_version() {
         ("foo.1", None),
     ];
     for &(version_str, parsed) in cases.iter() {
-        assert_eq!(parsed, parse_glibc_version(version_str));
+        assert_eq!(parsed, super::parse_glibc_version(version_str));
     }
 }
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index 507abb27871..ce77c210a62 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -284,7 +284,7 @@ impl ExitStatus {
         //
         // The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
         // will give a raw Fuchsia status (whatever that is - I don't know, personally).  That is
-        // not possible here becaause we must return a c_int because that's what Unix (including
+        // not possible here because we must return a c_int because that's what Unix (including
         // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
         // necessarily fit.
         //
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 3bf1493f3b8..bce35b380e6 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -13,7 +13,7 @@ use crate::sys::process::process_common::*;
 use crate::os::linux::process::PidFd;
 
 #[cfg(target_os = "linux")]
-use crate::sys::weak::syscall;
+use crate::sys::weak::raw_syscall;
 
 #[cfg(any(
     target_os = "macos",
@@ -162,7 +162,7 @@ impl Command {
             cgroup: u64,
         }
 
-        syscall! {
+        raw_syscall! {
             fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
         }
 
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index b99eb2e553f..9e02966b57c 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -7,7 +7,9 @@ use crate::ptr;
 use crate::sys::{os, stack_overflow};
 use crate::time::Duration;
 
-#[cfg(any(target_os = "linux", target_os = "solaris", target_os = "illumos"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
+use crate::sys::weak::dlsym;
+#[cfg(any(target_os = "solaris", target_os = "illumos"))]
 use crate::sys::weak::weak;
 #[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -627,10 +629,12 @@ pub mod guard {
 // We need that information to avoid blowing up when a small stack
 // is created in an application with big thread-local storage requirements.
 // See #6233 for rationale and details.
-#[cfg(target_os = "linux")]
-#[allow(deprecated)]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
 fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
-    weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
+    // We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628)
+    // We shouldn't really be using such an internal symbol, but there's currently
+    // no other way to account for the TLS size.
+    dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
 
     match __pthread_get_minstack.get() {
         None => libc::PTHREAD_STACK_MIN,
@@ -638,9 +642,8 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
     }
 }
 
-// No point in looking up __pthread_get_minstack() on non-glibc
-// platforms.
-#[cfg(all(not(target_os = "linux"), not(target_os = "netbsd")))]
+// No point in looking up __pthread_get_minstack() on non-glibc platforms.
+#[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))]
 fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
     libc::PTHREAD_STACK_MIN
 }
diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs
index ba432ec5494..55719b87c7e 100644
--- a/library/std/src/sys/unix/weak.rs
+++ b/library/std/src/sys/unix/weak.rs
@@ -6,7 +6,7 @@
 //! detection.
 //!
 //! One option to use here is weak linkage, but that is unfortunately only
-//! really workable on Linux. Hence, use dlsym to get the symbol value at
+//! really workable with ELF. Otherwise, use dlsym to get the symbol value at
 //! runtime. This is also done for compatibility with older versions of glibc,
 //! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
 //! we've been dynamically linked to the library the symbol comes from, but that
@@ -14,7 +14,8 @@
 //!
 //! A long time ago this used weak linkage for the __pthread_get_minstack
 //! symbol, but that caused Debian to detect an unnecessarily strict versioned
-//! dependency on libc6 (#23628).
+//! dependency on libc6 (#23628) because it is GLIBC_PRIVATE. We now use `dlsym`
+//! for a runtime lookup of that symbol to avoid the ELF versioned dependency.
 
 // There are a variety of `#[cfg]`s controlling which targets are involved in
 // each instance of `weak!` and `syscall!`. Rather than trying to unify all of
@@ -22,31 +23,75 @@
 #![allow(dead_code, unused_macros)]
 
 use crate::ffi::CStr;
-use crate::marker;
+use crate::marker::PhantomData;
 use crate::mem;
 use crate::sync::atomic::{self, AtomicUsize, Ordering};
 
+// We can use true weak linkage on ELF targets.
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
 pub(crate) macro weak {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
-        #[allow(non_upper_case_globals)]
-        static $name: crate::sys::weak::Weak<unsafe extern "C" fn($($t),*) -> $ret> =
-            crate::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
+        let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
+            extern "C" {
+                #[linkage = "extern_weak"]
+                static $name: *const libc::c_void;
+            }
+            #[allow(unused_unsafe)]
+            ExternWeak::new(unsafe { $name })
+        };
     )
 }
 
-pub struct Weak<F> {
+// On non-ELF targets, use the dlsym approximation of weak linkage.
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub(crate) use self::dlsym as weak;
+
+pub(crate) struct ExternWeak<F> {
+    weak_ptr: *const libc::c_void,
+    _marker: PhantomData<F>,
+}
+
+impl<F> ExternWeak<F> {
+    #[inline]
+    pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
+        ExternWeak { weak_ptr, _marker: PhantomData }
+    }
+}
+
+impl<F> ExternWeak<F> {
+    #[inline]
+    pub(crate) fn get(&self) -> Option<F> {
+        unsafe {
+            if self.weak_ptr.is_null() {
+                None
+            } else {
+                Some(mem::transmute_copy::<*const libc::c_void, F>(&self.weak_ptr))
+            }
+        }
+    }
+}
+
+pub(crate) macro dlsym {
+    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+        static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
+            DlsymWeak::new(concat!(stringify!($name), '\0'));
+        let $name = &DLSYM;
+    )
+}
+
+pub(crate) struct DlsymWeak<F> {
     name: &'static str,
     addr: AtomicUsize,
-    _marker: marker::PhantomData<F>,
+    _marker: PhantomData<F>,
 }
 
-impl<F> Weak<F> {
-    pub const fn new(name: &'static str) -> Weak<F> {
-        Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
+impl<F> DlsymWeak<F> {
+    pub(crate) const fn new(name: &'static str) -> Self {
+        DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
     }
 
-    pub fn get(&self) -> Option<F> {
-        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+    #[inline]
+    pub(crate) fn get(&self) -> Option<F> {
         unsafe {
             // Relaxed is fine here because we fence before reading through the
             // pointer (see the comment below).
@@ -79,9 +124,11 @@ impl<F> Weak<F> {
         }
     }
 
-    // Cold because it should only happen during first-time initalization.
+    // Cold because it should only happen during first-time initialization.
     #[cold]
     unsafe fn initialize(&self) -> Option<F> {
+        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+
         let val = fetch(self.name);
         // This synchronizes with the acquire fence in `get`.
         self.addr.store(val, Ordering::Release);
@@ -105,14 +152,12 @@ unsafe fn fetch(name: &str) -> usize {
 pub(crate) macro syscall {
     (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
         unsafe fn $name($($arg_name: $t),*) -> $ret {
-            use super::os;
-
             weak! { fn $name($($t),*) -> $ret }
 
             if let Some(fun) = $name.get() {
                 fun($($arg_name),*)
             } else {
-                os::set_errno(libc::ENOSYS);
+                super::os::set_errno(libc::ENOSYS);
                 -1
             }
         }
@@ -123,11 +168,6 @@ pub(crate) macro syscall {
 pub(crate) macro syscall {
     (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
         unsafe fn $name($($arg_name:$t),*) -> $ret {
-            use weak;
-            // This looks like a hack, but concat_idents only accepts idents
-            // (not paths).
-            use libc::*;
-
             weak! { fn $name($($t),*) -> $ret }
 
             // Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
@@ -135,6 +175,10 @@ pub(crate) macro syscall {
             if let Some(fun) = $name.get() {
                 fun($($arg_name),*)
             } else {
+                // This looks like a hack, but concat_idents only accepts idents
+                // (not paths).
+                use libc::*;
+
                 syscall(
                     concat_idents!(SYS_, $name),
                     $($arg_name),*
@@ -143,3 +187,19 @@ pub(crate) macro syscall {
         }
     )
 }
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub(crate) macro raw_syscall {
+    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
+        unsafe fn $name($($arg_name:$t),*) -> $ret {
+            // This looks like a hack, but concat_idents only accepts idents
+            // (not paths).
+            use libc::*;
+
+            syscall(
+                concat_idents!(SYS_, $name),
+                $($arg_name),*
+            ) as $ret
+        }
+    )
+}
diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs
index 6b45e29c145..d1d2847cd33 100644
--- a/library/std/src/sys/unsupported/fs.rs
+++ b/library/std/src/sys/unsupported/fs.rs
@@ -1,7 +1,7 @@
 use crate::ffi::OsString;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 use crate::path::{Path, PathBuf};
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
@@ -206,6 +206,10 @@ impl File {
         self.0
     }
 
+    pub fn read_buf(&self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        self.0
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         self.0
     }
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 984dda8dc0b..1a3da3746ac 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -3,7 +3,7 @@
 use super::fd::WasiFd;
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 use crate::iter;
 use crate::mem::{self, ManuallyDrop};
 use crate::os::raw::c_int;
@@ -411,6 +411,10 @@ impl File {
         true
     }
 
+    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|buf| self.read(buf), buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.write_vectored(&[IoSlice::new(buf)])
     }
diff --git a/library/std/src/sys/wasm/alloc.rs b/library/std/src/sys/wasm/alloc.rs
index 3223e894102..6dceb1689a8 100644
--- a/library/std/src/sys/wasm/alloc.rs
+++ b/library/std/src/sys/wasm/alloc.rs
@@ -24,7 +24,7 @@ static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new();
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+        // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
         // Calling malloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
         unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
@@ -32,7 +32,7 @@ unsafe impl GlobalAlloc for System {
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+        // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
         // Calling calloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
         unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
@@ -40,7 +40,7 @@ unsafe impl GlobalAlloc for System {
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+        // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
         // Calling free() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
         unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
@@ -48,7 +48,7 @@ unsafe impl GlobalAlloc for System {
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+        // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
         // Calling realloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
         unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
diff --git a/library/std/src/sys/wasm/atomics/mutex.rs b/library/std/src/sys/wasm/atomics/mutex.rs
index 5ff0ec052b6..3a09f0bf9bb 100644
--- a/library/std/src/sys/wasm/atomics/mutex.rs
+++ b/library/std/src/sys/wasm/atomics/mutex.rs
@@ -73,7 +73,7 @@ pub struct ReentrantMutex {
 unsafe impl Send for ReentrantMutex {}
 unsafe impl Sync for ReentrantMutex {}
 
-// Reentrant mutexes are similarly implemented to mutexs above except that
+// Reentrant mutexes are similarly implemented to mutexes above except that
 // instead of "1" meaning unlocked we use the id of a thread to represent
 // whether it has locked a mutex. That way we have an atomic counter which
 // always holds the id of the thread that currently holds the lock (or 0 if the
@@ -96,7 +96,7 @@ impl ReentrantMutex {
     pub unsafe fn lock(&self) {
         let me = thread::my_id();
         while let Err(owner) = self._try_lock(me) {
-            // SAFETY: the caller must gurantee that `self.ptr()` and `owner` are valid i32.
+            // SAFETY: the caller must guarantee that `self.ptr()` and `owner` are valid i32.
             let val = unsafe { wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1) };
             debug_assert!(val == 0 || val == 1);
         }
@@ -136,7 +136,7 @@ impl ReentrantMutex {
         match *self.recursions.get() {
             0 => {
                 self.owner.swap(0, SeqCst);
-                // SAFETY: the caller must gurantee that `self.ptr()` is valid i32.
+                // SAFETY: the caller must guarantee that `self.ptr()` is valid i32.
                 unsafe {
                     wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1);
                 } // wake up one waiter, if any
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 50c4547de85..b87b6b5d88e 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -1110,6 +1110,12 @@ compat_fn! {
                                           -> () {
         GetSystemTimeAsFileTime(lpSystemTimeAsFileTime)
     }
+
+    // >= Win11 / Server 2022
+    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
+    pub fn GetTempPath2W(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD {
+        GetTempPathW(nBufferLength, lpBuffer)
+    }
 }
 
 compat_fn! {
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 9859000c8d4..b258fc0478b 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -2,7 +2,7 @@ use crate::os::windows::prelude::*;
 
 use crate::ffi::OsString;
 use crate::fmt;
-use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 use crate::mem;
 use crate::os::windows::io::{AsHandle, BorrowedHandle};
 use crate::path::{Path, PathBuf};
@@ -420,6 +420,10 @@ impl File {
         self.handle.read_at(buf, offset)
     }
 
+    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        self.handle.read_buf(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.handle.write(buf)
     }
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index 21d86b00226..c3a3482f910 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -1,7 +1,7 @@
 #![unstable(issue = "none", feature = "windows_handle")]
 
 use crate::cmp;
-use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf};
 use crate::mem;
 use crate::os::windows::io::{
     AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
@@ -130,6 +130,39 @@ impl Handle {
         }
     }
 
+    pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+        let mut read = 0;
+        let len = cmp::min(buf.remaining(), <c::DWORD>::MAX as usize) as c::DWORD;
+        let res = cvt(unsafe {
+            c::ReadFile(
+                self.as_raw_handle(),
+                buf.unfilled_mut().as_mut_ptr() as c::LPVOID,
+                len,
+                &mut read,
+                ptr::null_mut(),
+            )
+        });
+
+        match res {
+            Ok(_) => {
+                // Safety: `read` bytes were written to the initialized portion of the buffer
+                unsafe {
+                    buf.assume_init(read as usize);
+                }
+                buf.add_filled(read as usize);
+                Ok(())
+            }
+
+            // The special treatment of BrokenPipe is to deal with Windows
+            // pipe semantics, which yields this error when *reading* from
+            // a pipe after the other end has closed; we interpret that as
+            // EOF on the pipe.
+            Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(()),
+
+            Err(e) => Err(e),
+        }
+    }
+
     pub unsafe fn read_overlapped(
         &self,
         buf: &mut [u8],
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 28fec817f86..084af4325e7 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -288,13 +288,13 @@ pub fn abort_internal() -> ! {
     unsafe {
         cfg_if::cfg_if! {
             if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
-                asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
+                core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
                 crate::intrinsics::unreachable();
             } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
-                asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
+                core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
                 crate::intrinsics::unreachable();
             } else if #[cfg(target_arch = "aarch64")] {
-                asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
+                core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
                 crate::intrinsics::unreachable();
             }
         }
diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs
index b5209aa690b..5f8556c3bc3 100644
--- a/library/std/src/sys/windows/os.rs
+++ b/library/std/src/sys/windows/os.rs
@@ -275,7 +275,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
 }
 
 pub fn temp_dir() -> PathBuf {
-    super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap()
+    super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap()
 }
 
 #[cfg(not(target_vendor = "uwp"))]
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index a4fe5f67f69..eb0925b3fda 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -124,7 +124,7 @@ fn write(
     //
     // If the data is not valid UTF-8 we write out as many bytes as are valid.
     // If the first byte is invalid it is either first byte of a multi-byte sequence but the
-    // provided byte slice is too short or it is the first byte of an invalide multi-byte sequence.
+    // provided byte slice is too short or it is the first byte of an invalid multi-byte sequence.
     let len = cmp::min(data.len(), MAX_BUFFER_SIZE / 2);
     let utf8 = match str::from_utf8(&data[..len]) {
         Ok(s) => s,
diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs
index 4f59d4dd452..5a8011a9588 100644
--- a/library/std/src/sys/windows/thread_parker.rs
+++ b/library/std/src/sys/windows/thread_parker.rs
@@ -22,7 +22,7 @@
 //
 // Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a
 // HANDLE (created with NtCreateKeyedEvent). This means that we can be sure
-// a succesfully awoken park() was awoken by unpark() and not a
+// a successfully awoken park() was awoken by unpark() and not a
 // NtReleaseKeyedEvent call from some other code, as these events are not only
 // matched by the key (address of the parker (state)), but also by this HANDLE.
 // We lazily allocate this handle the first time it is needed.
diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs
index 14cfa958e5e..d99e901bb5f 100644
--- a/library/std/src/sys_common/thread_parker/generic.rs
+++ b/library/std/src/sys_common/thread_parker/generic.rs
@@ -1,4 +1,4 @@
-//! Parker implementaiton based on a Mutex and Condvar.
+//! Parker implementation based on a Mutex and Condvar.
 
 use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::SeqCst;
@@ -20,7 +20,7 @@ impl Parker {
         Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() }
     }
 
-    // This implementaiton doesn't require `unsafe`, but other implementations
+    // This implementation doesn't require `unsafe`, but other implementations
     // may assume this is only called by the thread that owns the Parker.
     pub unsafe fn park(&self) {
         // If we were previously notified then we consume this notification and
@@ -55,7 +55,7 @@ impl Parker {
         }
     }
 
-    // This implementaiton doesn't require `unsafe`, but other implementations
+    // This implementation doesn't require `unsafe`, but other implementations
     // may assume this is only called by the thread that owns the Parker.
     pub unsafe fn park_timeout(&self, dur: Duration) {
         // Like `park` above we have a fast path for an already-notified thread, and
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 4da59577d78..1d2f6e97680 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -76,7 +76,21 @@ use crate::fmt;
 ///    destroyed, but not all platforms have this guard. Those platforms that do
 ///    not guard typically have a synthetic limit after which point no more
 ///    destructors are run.
+/// 3. When the process exits on Windows systems, TLS destructors may only be
+///    run on the thread that causes the process to exit. This is because the
+///    other threads may be forcibly terminated.
 ///
+/// ## Synchronization in thread-local destructors
+///
+/// On Windows, synchronization operations (such as [`JoinHandle::join`]) in
+/// thread local destructors are prone to deadlocks and so should be avoided.
+/// This is because the [loader lock] is held while a destructor is run. The
+/// lock is acquired whenever a thread starts or exits or when a DLL is loaded
+/// or unloaded. Therefore these events are blocked for as long as a thread
+/// local destructor is running.
+///
+/// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
+/// [`JoinHandle::join`]: crate::thread::JoinHandle::join
 /// [`with`]: LocalKey::with
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct LocalKey<T: 'static> {
@@ -164,7 +178,6 @@ macro_rules! __thread_local_inner {
     (@key $t:ty, const $init:expr) => {{
         #[cfg_attr(not(windows), inline)] // see comments below
         unsafe fn __getit() -> $crate::option::Option<&'static $t> {
-            const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local();
             const INIT_EXPR: $t = $init;
 
             // wasm without atomics maps directly to `static mut`, and dtors
@@ -569,7 +582,7 @@ pub mod fast {
             Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) }
         }
 
-        // note that this is just a publically-callable function only for the
+        // note that this is just a publicly-callable function only for the
         // const-initialized form of thread locals, basically a way to call the
         // free `register_dtor` function defined elsewhere in libstd.
         pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
@@ -580,7 +593,7 @@ pub mod fast {
 
         pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
             // SAFETY: See the definitions of `LazyKeyInner::get` and
-            // `try_initialize` for more informations.
+            // `try_initialize` for more information.
             //
             // The caller must ensure no mutable references are ever active to
             // the inner cell or the inner T when this is called.
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 39b53b51bfa..64f6c7fa022 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -204,13 +204,6 @@ pub use self::local::os::Key as __OsLocalKeyInner;
 #[doc(hidden)]
 pub use self::local::statik::Key as __StaticLocalKeyInner;
 
-// This is only used to make thread locals with `const { .. }` initialization
-// expressions unstable. If and/or when that syntax is stabilized with thread
-// locals this will simply be removed.
-#[doc(hidden)]
-#[unstable(feature = "thread_local_const_init", issue = "84223")]
-pub const fn require_unstable_const_init_thread_local() {}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Builder
 ////////////////////////////////////////////////////////////////////////////////
@@ -1460,9 +1453,12 @@ fn _assert_sync_and_send() {
 /// The purpose of this API is to provide an easy and portable way to query
 /// the default amount of parallelism the program should use. Among other things it
 /// does not expose information on NUMA regions, does not account for
-/// differences in (co)processor capabilities, and will not modify the program's
-/// global state in order to more accurately query the amount of available
-/// parallelism.
+/// differences in (co)processor capabilities or current system load,
+/// and will not modify the program's global state in order to more accurately
+/// query the amount of available parallelism.
+///
+/// Where both fixed steady-state and burst limits are available the steady-state
+/// capacity will be used to ensure more predictable latencies.
 ///
 /// Resource limits can be changed during the runtime of a program, therefore the value is
 /// not cached and instead recomputed every time this function is called. It should not be
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index ca0d88135a5..4f2c81731a3 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -1,6 +1,7 @@
 use super::Builder;
 use crate::any::Any;
 use crate::mem;
+use crate::panic::panic_any;
 use crate::result;
 use crate::sync::{
     mpsc::{channel, Sender},
@@ -183,7 +184,7 @@ fn test_simple_newsched_spawn() {
 }
 
 #[test]
-fn test_try_panic_message_static_str() {
+fn test_try_panic_message_string_literal() {
     match thread::spawn(move || {
         panic!("static string");
     })
@@ -199,9 +200,9 @@ fn test_try_panic_message_static_str() {
 }
 
 #[test]
-fn test_try_panic_message_owned_str() {
+fn test_try_panic_any_message_owned_str() {
     match thread::spawn(move || {
-        panic!("owned string".to_string());
+        panic_any("owned string".to_string());
     })
     .join()
     {
@@ -215,9 +216,9 @@ fn test_try_panic_message_owned_str() {
 }
 
 #[test]
-fn test_try_panic_message_any() {
+fn test_try_panic_any_message_any() {
     match thread::spawn(move || {
-        panic!(box 413u16 as Box<dyn Any + Send>);
+        panic_any(box 413u16 as Box<dyn Any + Send>);
     })
     .join()
     {
@@ -233,10 +234,10 @@ fn test_try_panic_message_any() {
 }
 
 #[test]
-fn test_try_panic_message_unit_struct() {
+fn test_try_panic_any_message_unit_struct() {
     struct Juju;
 
-    match thread::spawn(move || panic!(Juju)).join() {
+    match thread::spawn(move || panic_any(Juju)).join() {
         Err(ref e) if e.is::<Juju>() => {}
         Err(_) | Ok(()) => panic!(),
     }
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index a5e3bd0c290..86cc93c4453 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -273,7 +273,7 @@ impl Instant {
         // While issues have been seen on arm64 platforms the Arm architecture
         // requires that the counter monotonically increases and that it must
         // provide a uniform view of system time (e.g. it must not be possible
-        // for a core to recieve a message from another core with a time stamp
+        // for a core to receive a message from another core with a time stamp
         // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
         // there have been a few 64bit SoCs that have bugs which cause time to
         // not monoticially increase, these have been fixed in the Linux kernel