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.rs52
-rw-r--r--library/std/src/collections/hash/map/tests.rs26
-rw-r--r--library/std/src/collections/hash/set.rs53
-rw-r--r--library/std/src/collections/hash/set/tests.rs42
-rw-r--r--library/std/src/f32.rs2
-rw-r--r--library/std/src/f64.rs2
-rw-r--r--library/std/src/ffi/os_str.rs20
-rw-r--r--library/std/src/io/buffered/bufreader.rs29
-rw-r--r--library/std/src/io/buffered/bufwriter.rs138
-rw-r--r--library/std/src/io/buffered/linewriter.rs50
-rw-r--r--library/std/src/io/buffered/linewritershim.rs6
-rw-r--r--library/std/src/io/copy.rs110
-rw-r--r--library/std/src/io/copy/tests.rs108
-rw-r--r--library/std/src/io/mod.rs13
-rw-r--r--library/std/src/io/util/tests.rs61
-rw-r--r--library/std/src/lib.rs13
-rw-r--r--library/std/src/os/unix/net/ancillary.rs9
-rw-r--r--library/std/src/personality.rs2
-rw-r--r--library/std/src/primitive_docs.rs2
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs4
-rw-r--r--library/std/src/sys/unix/l4re.rs6
-rw-r--r--library/std/src/sys/unix/os_str.rs4
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs18
-rw-r--r--library/std/src/sys/unix/thread.rs23
-rw-r--r--library/std/src/sys/windows/c.rs55
-rw-r--r--library/std/src/sys/windows/c/windows_sys.lst1
-rw-r--r--library/std/src/sys/windows/c/windows_sys.rs21
-rw-r--r--library/std/src/sys/windows/os_str.rs2
-rw-r--r--library/std/src/sys/windows/rand.rs5
-rw-r--r--library/std/src/sys_common/wtf8.rs9
-rw-r--r--library/std/src/sys_common/wtf8/tests.rs6
-rw-r--r--library/std/src/thread/mod.rs2
32 files changed, 601 insertions, 293 deletions
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index c722bad2e4f..f3316d97c5f 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -623,28 +623,27 @@ impl<K, V, S> HashMap<K, V, S> {
     /// If the closure returns false, or panics, the element remains in the map and will not be
     /// yielded.
     ///
-    /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of
+    /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of
     /// whether you choose to keep or remove it.
     ///
-    /// If the iterator is only partially consumed or not consumed at all, each of the remaining
-    /// elements will still be subjected to the closure and removed and dropped if it returns true.
+    /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
+    /// or the iteration short-circuits, then the remaining elements will be retained.
+    /// Use [`retain`] with a negated predicate if you do not need the returned iterator.
     ///
-    /// It is unspecified how many more elements will be subjected to the closure
-    /// if a panic occurs in the closure, or a panic occurs while dropping an element,
-    /// or if the `DrainFilter` value is leaked.
+    /// [`retain`]: HashMap::retain
     ///
     /// # Examples
     ///
     /// Splitting a map into even and odd keys, reusing the original map:
     ///
     /// ```
-    /// #![feature(hash_drain_filter)]
+    /// #![feature(hash_extract_if)]
     /// use std::collections::HashMap;
     ///
     /// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
-    /// let drained: HashMap<i32, i32> = map.drain_filter(|k, _v| k % 2 == 0).collect();
+    /// let extracted: HashMap<i32, i32> = map.extract_if(|k, _v| k % 2 == 0).collect();
     ///
-    /// let mut evens = drained.keys().copied().collect::<Vec<_>>();
+    /// let mut evens = extracted.keys().copied().collect::<Vec<_>>();
     /// let mut odds = map.keys().copied().collect::<Vec<_>>();
     /// evens.sort();
     /// odds.sort();
@@ -654,12 +653,12 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ```
     #[inline]
     #[rustc_lint_query_instability]
-    #[unstable(feature = "hash_drain_filter", issue = "59618")]
-    pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
+    #[unstable(feature = "hash_extract_if", issue = "59618")]
+    pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F>
     where
         F: FnMut(&K, &mut V) -> bool,
     {
-        DrainFilter { base: self.base.drain_filter(pred) }
+        ExtractIf { base: self.base.extract_if(pred) }
     }
 
     /// Retains only the elements specified by the predicate.
@@ -1578,28 +1577,29 @@ impl<'a, K, V> Drain<'a, K, V> {
 
 /// A draining, filtering iterator over the entries of a `HashMap`.
 ///
-/// This `struct` is created by the [`drain_filter`] method on [`HashMap`].
+/// This `struct` is created by the [`extract_if`] method on [`HashMap`].
 ///
-/// [`drain_filter`]: HashMap::drain_filter
+/// [`extract_if`]: HashMap::extract_if
 ///
 /// # Example
 ///
 /// ```
-/// #![feature(hash_drain_filter)]
+/// #![feature(hash_extract_if)]
 ///
 /// use std::collections::HashMap;
 ///
 /// let mut map = HashMap::from([
 ///     ("a", 1),
 /// ]);
-/// let iter = map.drain_filter(|_k, v| *v % 2 == 0);
+/// let iter = map.extract_if(|_k, v| *v % 2 == 0);
 /// ```
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-pub struct DrainFilter<'a, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+pub struct ExtractIf<'a, K, V, F>
 where
     F: FnMut(&K, &mut V) -> bool,
 {
-    base: base::DrainFilter<'a, K, V, F>,
+    base: base::ExtractIf<'a, K, V, F>,
 }
 
 /// A mutable iterator over the values of a `HashMap`.
@@ -2479,8 +2479,8 @@ where
     }
 }
 
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, V, F> Iterator for DrainFilter<'_, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, V, F> Iterator for ExtractIf<'_, K, V, F>
 where
     F: FnMut(&K, &mut V) -> bool,
 {
@@ -2496,16 +2496,16 @@ where
     }
 }
 
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, V, F> FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
 
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F>
 where
     F: FnMut(&K, &mut V) -> bool,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("DrainFilter").finish_non_exhaustive()
+        f.debug_struct("ExtractIf").finish_non_exhaustive()
     }
 }
 
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 6b89518e2e2..91a3776e7be 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -944,7 +944,7 @@ fn test_raw_entry() {
     }
 }
 
-mod test_drain_filter {
+mod test_extract_if {
     use super::*;
 
     use crate::panic::{catch_unwind, AssertUnwindSafe};
@@ -968,7 +968,7 @@ mod test_drain_filter {
     #[test]
     fn empty() {
         let mut map: HashMap<i32, i32> = HashMap::new();
-        map.drain_filter(|_, _| unreachable!("there's nothing to decide on"));
+        map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop);
         assert!(map.is_empty());
     }
 
@@ -976,7 +976,7 @@ mod test_drain_filter {
     fn consuming_nothing() {
         let pairs = (0..3).map(|i| (i, i));
         let mut map: HashMap<_, _> = pairs.collect();
-        assert!(map.drain_filter(|_, _| false).eq_sorted(crate::iter::empty()));
+        assert!(map.extract_if(|_, _| false).eq_sorted(crate::iter::empty()));
         assert_eq!(map.len(), 3);
     }
 
@@ -984,7 +984,7 @@ mod test_drain_filter {
     fn consuming_all() {
         let pairs = (0..3).map(|i| (i, i));
         let mut map: HashMap<_, _> = pairs.clone().collect();
-        assert!(map.drain_filter(|_, _| true).eq_sorted(pairs));
+        assert!(map.extract_if(|_, _| true).eq_sorted(pairs));
         assert!(map.is_empty());
     }
 
@@ -993,7 +993,7 @@ mod test_drain_filter {
         let pairs = (0..3).map(|i| (i, i));
         let mut map: HashMap<_, _> = pairs.collect();
         assert!(
-            map.drain_filter(|_, v| {
+            map.extract_if(|_, v| {
                 *v += 6;
                 false
             })
@@ -1008,7 +1008,7 @@ mod test_drain_filter {
         let pairs = (0..3).map(|i| (i, i));
         let mut map: HashMap<_, _> = pairs.collect();
         assert!(
-            map.drain_filter(|_, v| {
+            map.extract_if(|_, v| {
                 *v += 6;
                 true
             })
@@ -1034,14 +1034,15 @@ mod test_drain_filter {
         let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
 
         catch_unwind(move || {
-            drop(map.drain_filter(|_, _| {
+            map.extract_if(|_, _| {
                 PREDS.fetch_add(1, Ordering::SeqCst);
                 true
-            }))
+            })
+            .for_each(drop)
         })
         .unwrap_err();
 
-        assert_eq!(PREDS.load(Ordering::SeqCst), 3);
+        assert_eq!(PREDS.load(Ordering::SeqCst), 2);
         assert_eq!(DROPS.load(Ordering::SeqCst), 3);
     }
 
@@ -1060,10 +1061,11 @@ mod test_drain_filter {
         let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
 
         catch_unwind(AssertUnwindSafe(|| {
-            drop(map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
+            map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
                 0 => true,
                 _ => panic!(),
-            }))
+            })
+            .for_each(drop)
         }))
         .unwrap_err();
 
@@ -1088,7 +1090,7 @@ mod test_drain_filter {
         let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
 
         {
-            let mut it = map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
+            let mut it = map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
                 0 => true,
                 _ => panic!(),
             });
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index ac906e682d5..ec59634df36 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -262,25 +262,24 @@ impl<T, S> HashSet<T, S> {
     /// If the closure returns false, the value will remain in the list and will not be yielded
     /// by the iterator.
     ///
-    /// If the iterator is only partially consumed or not consumed at all, each of the remaining
-    /// values will still be subjected to the closure and removed and dropped if it returns true.
+    /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
+    /// or the iteration short-circuits, then the remaining elements will be retained.
+    /// Use [`retain`] with a negated predicate if you do not need the returned iterator.
     ///
-    /// It is unspecified how many more values will be subjected to the closure
-    /// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the
-    /// `DrainFilter` itself is leaked.
+    /// [`retain`]: HashSet::retain
     ///
     /// # Examples
     ///
     /// Splitting a set into even and odd values, reusing the original set:
     ///
     /// ```
-    /// #![feature(hash_drain_filter)]
+    /// #![feature(hash_extract_if)]
     /// use std::collections::HashSet;
     ///
     /// let mut set: HashSet<i32> = (0..8).collect();
-    /// let drained: HashSet<i32> = set.drain_filter(|v| v % 2 == 0).collect();
+    /// let extracted: HashSet<i32> = set.extract_if(|v| v % 2 == 0).collect();
     ///
-    /// let mut evens = drained.into_iter().collect::<Vec<_>>();
+    /// let mut evens = extracted.into_iter().collect::<Vec<_>>();
     /// let mut odds = set.into_iter().collect::<Vec<_>>();
     /// evens.sort();
     /// odds.sort();
@@ -290,12 +289,12 @@ impl<T, S> HashSet<T, S> {
     /// ```
     #[inline]
     #[rustc_lint_query_instability]
-    #[unstable(feature = "hash_drain_filter", issue = "59618")]
-    pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
+    #[unstable(feature = "hash_extract_if", issue = "59618")]
+    pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, T, F>
     where
         F: FnMut(&T) -> bool,
     {
-        DrainFilter { base: self.base.drain_filter(pred) }
+        ExtractIf { base: self.base.extract_if(pred) }
     }
 
     /// Retains only the elements specified by the predicate.
@@ -868,7 +867,9 @@ where
     /// Returns whether the value was newly inserted. That is:
     ///
     /// - If the set did not previously contain this value, `true` is returned.
-    /// - If the set already contained this value, `false` is returned.
+    /// - If the set already contained this value, `false` is returned,
+    ///   and the set is not modified: original value is not replaced,
+    ///   and the value passed as argument is dropped.
     ///
     /// # Examples
     ///
@@ -1310,27 +1311,27 @@ pub struct Drain<'a, K: 'a> {
 
 /// A draining, filtering iterator over the items of a `HashSet`.
 ///
-/// This `struct` is created by the [`drain_filter`] method on [`HashSet`].
+/// This `struct` is created by the [`extract_if`] method on [`HashSet`].
 ///
-/// [`drain_filter`]: HashSet::drain_filter
+/// [`extract_if`]: HashSet::extract_if
 ///
 /// # Examples
 ///
 /// ```
-/// #![feature(hash_drain_filter)]
+/// #![feature(hash_extract_if)]
 ///
 /// use std::collections::HashSet;
 ///
 /// let mut a = HashSet::from([1, 2, 3]);
 ///
-/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0);
+/// let mut extract_ifed = a.extract_if(|v| v % 2 == 0);
 /// ```
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-pub struct DrainFilter<'a, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+pub struct ExtractIf<'a, K, F>
 where
     F: FnMut(&K) -> bool,
 {
-    base: base::DrainFilter<'a, K, F>,
+    base: base::ExtractIf<'a, K, F>,
 }
 
 /// A lazy iterator producing elements in the intersection of `HashSet`s.
@@ -1576,8 +1577,8 @@ impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
     }
 }
 
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, F> Iterator for DrainFilter<'_, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, F> Iterator for ExtractIf<'_, K, F>
 where
     F: FnMut(&K) -> bool,
 {
@@ -1593,16 +1594,16 @@ where
     }
 }
 
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, F> FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {}
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, F> FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {}
 
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F>
 where
     F: FnMut(&K) -> bool,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("DrainFilter").finish_non_exhaustive()
+        f.debug_struct("ExtractIf").finish_non_exhaustive()
     }
 }
 
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
index 941a0450cc7..e0cd80b44f8 100644
--- a/library/std/src/collections/hash/set/tests.rs
+++ b/library/std/src/collections/hash/set/tests.rs
@@ -3,6 +3,7 @@ use super::HashSet;
 
 use crate::panic::{catch_unwind, AssertUnwindSafe};
 use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::sync::Arc;
 
 #[test]
 fn test_zero_capacities() {
@@ -418,18 +419,18 @@ fn test_retain() {
 }
 
 #[test]
-fn test_drain_filter() {
+fn test_extract_if() {
     let mut x: HashSet<_> = [1].iter().copied().collect();
     let mut y: HashSet<_> = [1].iter().copied().collect();
 
-    x.drain_filter(|_| true);
-    y.drain_filter(|_| false);
+    x.extract_if(|_| true).for_each(drop);
+    y.extract_if(|_| false).for_each(drop);
     assert_eq!(x.len(), 0);
     assert_eq!(y.len(), 1);
 }
 
 #[test]
-fn test_drain_filter_drop_panic_leak() {
+fn test_extract_if_drop_panic_leak() {
     static PREDS: AtomicU32 = AtomicU32::new(0);
     static DROPS: AtomicU32 = AtomicU32::new(0);
 
@@ -446,19 +447,20 @@ fn test_drain_filter_drop_panic_leak() {
     let mut set = (0..3).map(|i| D(i)).collect::<HashSet<_>>();
 
     catch_unwind(move || {
-        drop(set.drain_filter(|_| {
+        set.extract_if(|_| {
             PREDS.fetch_add(1, Ordering::SeqCst);
             true
-        }))
+        })
+        .for_each(drop)
     })
     .ok();
 
-    assert_eq!(PREDS.load(Ordering::SeqCst), 3);
+    assert_eq!(PREDS.load(Ordering::SeqCst), 2);
     assert_eq!(DROPS.load(Ordering::SeqCst), 3);
 }
 
 #[test]
-fn test_drain_filter_pred_panic_leak() {
+fn test_extract_if_pred_panic_leak() {
     static PREDS: AtomicU32 = AtomicU32::new(0);
     static DROPS: AtomicU32 = AtomicU32::new(0);
 
@@ -473,10 +475,11 @@ fn test_drain_filter_pred_panic_leak() {
     let mut set: HashSet<_> = (0..3).map(|_| D).collect();
 
     catch_unwind(AssertUnwindSafe(|| {
-        drop(set.drain_filter(|_| match PREDS.fetch_add(1, Ordering::SeqCst) {
+        set.extract_if(|_| match PREDS.fetch_add(1, Ordering::SeqCst) {
             0 => true,
             _ => panic!(),
-        }))
+        })
+        .for_each(drop)
     }))
     .ok();
 
@@ -502,3 +505,22 @@ fn const_with_hasher() {
     const X: HashSet<(), ()> = HashSet::with_hasher(());
     assert_eq!(X.len(), 0);
 }
+
+#[test]
+fn test_insert_does_not_overwrite_the_value() {
+    let first_value = Arc::new(17);
+    let second_value = Arc::new(17);
+
+    let mut set = HashSet::new();
+    let inserted = set.insert(first_value.clone());
+    assert!(inserted);
+
+    let inserted = set.insert(second_value);
+    assert!(!inserted);
+
+    assert!(
+        Arc::ptr_eq(set.iter().next().unwrap(), &first_value),
+        "Insert must not overwrite the value, so the contained value pointer \
+            must be the same as first value pointer we inserted"
+    );
+}
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 408244b2ce9..bed90418be1 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -528,7 +528,7 @@ impl f32 {
 
     /// The positive difference of two numbers.
     ///
-    /// * If `self <= other`: `0:0`
+    /// * If `self <= other`: `0.0`
     /// * Else: `self - other`
     ///
     /// # Examples
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 6782b861f11..e72de05ca41 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -530,7 +530,7 @@ impl f64 {
 
     /// The positive difference of two numbers.
     ///
-    /// * If `self <= other`: `0:0`
+    /// * If `self <= other`: `0.0`
     /// * Else: `self - other`
     ///
     /// # Examples
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index bb577acf769..fbdf7f5ecac 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -745,7 +745,7 @@ impl OsStr {
                   without modifying the original"]
     #[inline]
     pub fn to_str(&self) -> Option<&str> {
-        self.inner.to_str()
+        self.inner.to_str().ok()
     }
 
     /// Converts an `OsStr` to a <code>[Cow]<[str]></code>.
@@ -1165,6 +1165,24 @@ impl<'a> From<Cow<'a, OsStr>> for OsString {
     }
 }
 
+#[stable(feature = "str_tryfrom_osstr_impl", since = "CURRENT_RUSTC_VERSION")]
+impl<'a> TryFrom<&'a OsStr> for &'a str {
+    type Error = crate::str::Utf8Error;
+
+    /// Tries to convert an `&OsStr` to a `&str`.
+    ///
+    /// ```
+    /// use std::ffi::OsStr;
+    ///
+    /// let os_str = OsStr::new("foo");
+    /// let as_str = <&str>::try_from(os_str).unwrap();
+    /// assert_eq!(as_str, "foo");
+    /// ```
+    fn try_from(value: &'a OsStr) -> Result<Self, Self::Error> {
+        value.inner.to_str()
+    }
+}
+
 #[stable(feature = "box_default_extra", since = "1.17.0")]
 impl Default for Box<OsStr> {
     #[inline]
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 4f339a18a48..a66e6ccf673 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -47,9 +47,9 @@ use buffer::Buffer;
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct BufReader<R> {
-    inner: R,
+pub struct BufReader<R: ?Sized> {
     buf: Buffer,
+    inner: R,
 }
 
 impl<R: Read> BufReader<R> {
@@ -95,7 +95,7 @@ impl<R: Read> BufReader<R> {
     }
 }
 
-impl<R> BufReader<R> {
+impl<R: ?Sized> BufReader<R> {
     /// Gets a reference to the underlying reader.
     ///
     /// It is inadvisable to directly read from the underlying reader.
@@ -213,26 +213,29 @@ impl<R> BufReader<R> {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(self) -> R {
+    pub fn into_inner(self) -> R
+    where
+        R: Sized,
+    {
         self.inner
     }
 
     /// Invalidates all data in the internal buffer.
     #[inline]
-    fn discard_buffer(&mut self) {
+    pub(in crate::io) fn discard_buffer(&mut self) {
         self.buf.discard_buffer()
     }
 }
 
 // This is only used by a test which asserts that the initialization-tracking is correct.
 #[cfg(test)]
-impl<R> BufReader<R> {
+impl<R: ?Sized> BufReader<R> {
     pub fn initialized(&self) -> usize {
         self.buf.initialized()
     }
 }
 
-impl<R: Seek> BufReader<R> {
+impl<R: ?Sized + Seek> BufReader<R> {
     /// Seeks relative to the current position. If the new position lies within the buffer,
     /// the buffer will not be flushed, allowing for more efficient seeks.
     /// This method does not return the location of the underlying reader, so the caller
@@ -257,7 +260,7 @@ impl<R: Seek> BufReader<R> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Read> Read for BufReader<R> {
+impl<R: ?Sized + Read> Read for BufReader<R> {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         // If we don't have any buffered data and we're doing a massive read
         // (larger than our internal buffer), bypass our internal buffer
@@ -371,7 +374,7 @@ impl<R: Read> Read for BufReader<R> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Read> BufRead for BufReader<R> {
+impl<R: ?Sized + Read> BufRead for BufReader<R> {
     fn fill_buf(&mut self) -> io::Result<&[u8]> {
         self.buf.fill_buf(&mut self.inner)
     }
@@ -384,11 +387,11 @@ impl<R: Read> BufRead for BufReader<R> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<R> fmt::Debug for BufReader<R>
 where
-    R: fmt::Debug,
+    R: ?Sized + fmt::Debug,
 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct("BufReader")
-            .field("reader", &self.inner)
+            .field("reader", &&self.inner)
             .field(
                 "buffer",
                 &format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()),
@@ -398,7 +401,7 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Seek> Seek for BufReader<R> {
+impl<R: ?Sized + Seek> Seek for BufReader<R> {
     /// Seek to an offset, in bytes, in the underlying reader.
     ///
     /// The position used for seeking with <code>[SeekFrom::Current]\(_)</code> is the
@@ -491,7 +494,7 @@ impl<R: Seek> Seek for BufReader<R> {
     }
 }
 
-impl<T> SizeHint for BufReader<T> {
+impl<T: ?Sized> SizeHint for BufReader<T> {
     #[inline]
     fn lower_bound(&self) -> usize {
         SizeHint::lower_bound(self.get_ref()) + self.buffer().len()
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
index 14c455d4fa3..0e2450655e5 100644
--- a/library/std/src/io/buffered/bufwriter.rs
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -67,8 +67,7 @@ use crate::ptr;
 /// [`TcpStream`]: crate::net::TcpStream
 /// [`flush`]: BufWriter::flush
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct BufWriter<W: Write> {
-    inner: W,
+pub struct BufWriter<W: ?Sized + Write> {
     // The buffer. Avoid using this like a normal `Vec` in common code paths.
     // That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
     // methods that require bounds checking or the like. This makes an enormous
@@ -78,6 +77,7 @@ pub struct BufWriter<W: Write> {
     // write the buffered data a second time in BufWriter's destructor. This
     // flag tells the Drop impl if it should skip the flush.
     panicked: bool,
+    inner: W,
 }
 
 impl<W: Write> BufWriter<W> {
@@ -115,6 +115,69 @@ impl<W: Write> BufWriter<W> {
         BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false }
     }
 
+    /// Unwraps this `BufWriter<W>`, returning the underlying writer.
+    ///
+    /// The buffer is written out before returning the writer.
+    ///
+    /// # Errors
+    ///
+    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // unwrap the TcpStream and flush the buffer
+    /// let stream = buffer.into_inner().unwrap();
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
+        match self.flush_buf() {
+            Err(e) => Err(IntoInnerError::new(self, e)),
+            Ok(()) => Ok(self.into_parts().0),
+        }
+    }
+
+    /// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
+    /// unwritten data.
+    ///
+    /// If the underlying writer panicked, it is not known what portion of the data was written.
+    /// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
+    /// contents can still be recovered).
+    ///
+    /// `into_parts` makes no attempt to flush data and cannot fail.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::{BufWriter, Write};
+    ///
+    /// let mut buffer = [0u8; 10];
+    /// let mut stream = BufWriter::new(buffer.as_mut());
+    /// write!(stream, "too much data").unwrap();
+    /// stream.flush().expect_err("it doesn't fit");
+    /// let (recovered_writer, buffered_data) = stream.into_parts();
+    /// assert_eq!(recovered_writer.len(), 0);
+    /// assert_eq!(&buffered_data.unwrap(), b"ata");
+    /// ```
+    #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
+    pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
+        let buf = mem::take(&mut self.buf);
+        let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
+
+        // SAFETY: forget(self) prevents double dropping inner
+        let inner = unsafe { ptr::read(&self.inner) };
+        mem::forget(self);
+
+        (inner, buf)
+    }
+}
+
+impl<W: ?Sized + Write> BufWriter<W> {
     /// Send data in our local buffer into the inner writer, looping as
     /// necessary until either it's all been sent or an error occurs.
     ///
@@ -284,67 +347,6 @@ impl<W: Write> BufWriter<W> {
         self.buf.capacity()
     }
 
-    /// Unwraps this `BufWriter<W>`, returning the underlying writer.
-    ///
-    /// The buffer is written out before returning the writer.
-    ///
-    /// # Errors
-    ///
-    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // unwrap the TcpStream and flush the buffer
-    /// let stream = buffer.into_inner().unwrap();
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
-        match self.flush_buf() {
-            Err(e) => Err(IntoInnerError::new(self, e)),
-            Ok(()) => Ok(self.into_parts().0),
-        }
-    }
-
-    /// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
-    /// unwritten data.
-    ///
-    /// If the underlying writer panicked, it is not known what portion of the data was written.
-    /// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
-    /// contents can still be recovered).
-    ///
-    /// `into_parts` makes no attempt to flush data and cannot fail.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::io::{BufWriter, Write};
-    ///
-    /// let mut buffer = [0u8; 10];
-    /// let mut stream = BufWriter::new(buffer.as_mut());
-    /// write!(stream, "too much data").unwrap();
-    /// stream.flush().expect_err("it doesn't fit");
-    /// let (recovered_writer, buffered_data) = stream.into_parts();
-    /// assert_eq!(recovered_writer.len(), 0);
-    /// assert_eq!(&buffered_data.unwrap(), b"ata");
-    /// ```
-    #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
-    pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
-        let buf = mem::take(&mut self.buf);
-        let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
-
-        // SAFETY: forget(self) prevents double dropping inner
-        let inner = unsafe { ptr::read(&self.inner) };
-        mem::forget(self);
-
-        (inner, buf)
-    }
-
     // Ensure this function does not get inlined into `write`, so that it
     // remains inlineable and its common path remains as short as possible.
     // If this function ends up being called frequently relative to `write`,
@@ -511,7 +513,7 @@ impl fmt::Debug for WriterPanicked {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Write for BufWriter<W> {
+impl<W: ?Sized + Write> Write for BufWriter<W> {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         // Use < instead of <= to avoid a needless trip through the buffer in some cases.
@@ -640,20 +642,20 @@ impl<W: Write> Write for BufWriter<W> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> fmt::Debug for BufWriter<W>
+impl<W: ?Sized + Write> fmt::Debug for BufWriter<W>
 where
     W: fmt::Debug,
 {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct("BufWriter")
-            .field("writer", &self.inner)
+            .field("writer", &&self.inner)
             .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
             .finish()
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write + Seek> Seek for BufWriter<W> {
+impl<W: ?Sized + Write + Seek> Seek for BufWriter<W> {
     /// Seek to the offset, in bytes, in the underlying writer.
     ///
     /// Seeking always writes out the internal buffer before seeking.
@@ -664,7 +666,7 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Drop for BufWriter<W> {
+impl<W: ?Sized + Write> Drop for BufWriter<W> {
     fn drop(&mut self) {
         if !self.panicked {
             // dtors should not panic, so we ignore a failed flush
diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs
index a26a4ab330e..3d4ae704193 100644
--- a/library/std/src/io/buffered/linewriter.rs
+++ b/library/std/src/io/buffered/linewriter.rs
@@ -64,7 +64,7 @@ use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSli
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct LineWriter<W: Write> {
+pub struct LineWriter<W: ?Sized + Write> {
     inner: BufWriter<W>,
 }
 
@@ -109,27 +109,6 @@ impl<W: Write> LineWriter<W> {
         LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
     }
 
-    /// Gets a reference to the underlying writer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let file = LineWriter::new(file);
-    ///
-    ///     let reference = file.get_ref();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_ref(&self) -> &W {
-        self.inner.get_ref()
-    }
-
     /// Gets a mutable reference to the underlying writer.
     ///
     /// Caution must be taken when calling methods on the mutable reference
@@ -184,8 +163,31 @@ impl<W: Write> LineWriter<W> {
     }
 }
 
+impl<W: ?Sized + Write> LineWriter<W> {
+    /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::new(file);
+    ///
+    ///     let reference = file.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_ref(&self) -> &W {
+        self.inner.get_ref()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Write for LineWriter<W> {
+impl<W: ?Sized + Write> Write for LineWriter<W> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         LineWriterShim::new(&mut self.inner).write(buf)
     }
@@ -216,7 +218,7 @@ impl<W: Write> Write for LineWriter<W> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> fmt::Debug for LineWriter<W>
+impl<W: ?Sized + Write> fmt::Debug for LineWriter<W>
 where
     W: fmt::Debug,
 {
diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs
index 0175d2693e8..f2a55da05b2 100644
--- a/library/std/src/io/buffered/linewritershim.rs
+++ b/library/std/src/io/buffered/linewritershim.rs
@@ -11,11 +11,11 @@ use crate::sys_common::memchr;
 /// `BufWriters` to be temporarily given line-buffering logic; this is what
 /// enables Stdout to be alternately in line-buffered or block-buffered mode.
 #[derive(Debug)]
-pub struct LineWriterShim<'a, W: Write> {
+pub struct LineWriterShim<'a, W: ?Sized + Write> {
     buffer: &'a mut BufWriter<W>,
 }
 
-impl<'a, W: Write> LineWriterShim<'a, W> {
+impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
     pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
         Self { buffer }
     }
@@ -49,7 +49,7 @@ impl<'a, W: Write> LineWriterShim<'a, W> {
     }
 }
 
-impl<'a, W: Write> Write for LineWriterShim<'a, W> {
+impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
     /// Write some data into this BufReader with line buffering. This means
     /// that, if any newlines are present in the data, the data up to the last
     /// newline is sent directly to the underlying writer, and data after it
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 1d9d93f5b64..ef1f4031ef2 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,6 +1,9 @@
-use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
 use crate::mem::MaybeUninit;
 
+#[cfg(test)]
+mod tests;
+
 /// Copies the entire contents of a reader into a writer.
 ///
 /// This function will continuously read data from `reader` and then
@@ -71,32 +74,113 @@ where
     R: Read,
     W: Write,
 {
-    BufferedCopySpec::copy_to(reader, writer)
+    let read_buf = BufferedReaderSpec::buffer_size(reader);
+    let write_buf = BufferedWriterSpec::buffer_size(writer);
+
+    if read_buf >= DEFAULT_BUF_SIZE && read_buf >= write_buf {
+        return BufferedReaderSpec::copy_to(reader, writer);
+    }
+
+    BufferedWriterSpec::copy_from(writer, reader)
+}
+
+/// Specialization of the read-write loop that reuses the internal
+/// buffer of a BufReader. If there's no buffer then the writer side
+/// should be used intead.
+trait BufferedReaderSpec {
+    fn buffer_size(&self) -> usize;
+
+    fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64>;
+}
+
+impl<T> BufferedReaderSpec for T
+where
+    Self: Read,
+    T: ?Sized,
+{
+    #[inline]
+    default fn buffer_size(&self) -> usize {
+        0
+    }
+
+    default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result<u64> {
+        unimplemented!("only called from specializations");
+    }
+}
+
+impl<I> BufferedReaderSpec for BufReader<I>
+where
+    Self: Read,
+    I: ?Sized,
+{
+    fn buffer_size(&self) -> usize {
+        self.capacity()
+    }
+
+    fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result<u64> {
+        let mut len = 0;
+
+        loop {
+            // Hack: this relies on `impl Read for BufReader` always calling fill_buf
+            // if the buffer is empty, even for empty slices.
+            // It can't be called directly here since specialization prevents us
+            // from adding I: Read
+            match self.read(&mut []) {
+                Ok(_) => {}
+                Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+                Err(e) => return Err(e),
+            }
+            let buf = self.buffer();
+            if self.buffer().len() == 0 {
+                return Ok(len);
+            }
+
+            // In case the writer side is a BufWriter then its write_all
+            // implements an optimization that passes through large
+            // buffers to the underlying writer. That code path is #[cold]
+            // but we're still avoiding redundant memcopies when doing
+            // a copy between buffered inputs and outputs.
+            to.write_all(buf)?;
+            len += buf.len() as u64;
+            self.discard_buffer();
+        }
+    }
 }
 
 /// Specialization of the read-write loop that either uses a stack buffer
 /// or reuses the internal buffer of a BufWriter
-trait BufferedCopySpec: Write {
-    fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64>;
+trait BufferedWriterSpec: Write {
+    fn buffer_size(&self) -> usize;
+
+    fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64>;
 }
 
-impl<W: Write + ?Sized> BufferedCopySpec for W {
-    default fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
-        stack_buffer_copy(reader, writer)
+impl<W: Write + ?Sized> BufferedWriterSpec for W {
+    #[inline]
+    default fn buffer_size(&self) -> usize {
+        0
+    }
+
+    default fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
+        stack_buffer_copy(reader, self)
     }
 }
 
-impl<I: Write> BufferedCopySpec for BufWriter<I> {
-    fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
-        if writer.capacity() < DEFAULT_BUF_SIZE {
-            return stack_buffer_copy(reader, writer);
+impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
+    fn buffer_size(&self) -> usize {
+        self.capacity()
+    }
+
+    fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
+        if self.capacity() < DEFAULT_BUF_SIZE {
+            return stack_buffer_copy(reader, self);
         }
 
         let mut len = 0;
         let mut init = 0;
 
         loop {
-            let buf = writer.buffer_mut();
+            let buf = self.buffer_mut();
             let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
 
             unsafe {
@@ -127,7 +211,7 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
                     Err(e) => return Err(e),
                 }
             } else {
-                writer.flush_buf()?;
+                self.flush_buf()?;
                 init = 0;
             }
         }
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
new file mode 100644
index 00000000000..8c816af15b8
--- /dev/null
+++ b/library/std/src/io/copy/tests.rs
@@ -0,0 +1,108 @@
+use crate::cmp::{max, min};
+use crate::io::*;
+
+#[test]
+fn copy_copies() {
+    let mut r = repeat(0).take(4);
+    let mut w = sink();
+    assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
+
+    let mut r = repeat(0).take(1 << 17);
+    assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
+}
+
+struct ShortReader {
+    cap: usize,
+    read_size: usize,
+    observed_buffer: usize,
+}
+
+impl Read for ShortReader {
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        let bytes = min(self.cap, self.read_size);
+        self.cap -= bytes;
+        self.observed_buffer = max(self.observed_buffer, buf.len());
+        Ok(bytes)
+    }
+}
+
+struct WriteObserver {
+    observed_buffer: usize,
+}
+
+impl Write for WriteObserver {
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        self.observed_buffer = max(self.observed_buffer, buf.len());
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> Result<()> {
+        Ok(())
+    }
+}
+
+#[test]
+fn copy_specializes_bufwriter() {
+    let cap = 117 * 1024;
+    let buf_sz = 16 * 1024;
+    let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
+    let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 });
+    assert_eq!(
+        copy(&mut r, &mut w).unwrap(),
+        cap as u64,
+        "expected the whole capacity to be copied"
+    );
+    assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader");
+    assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes");
+}
+
+#[test]
+fn copy_specializes_bufreader() {
+    let mut source = vec![0; 768 * 1024];
+    source[1] = 42;
+    let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source));
+
+    let mut sink = Vec::new();
+    assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
+    assert_eq!(source.as_slice(), sink.as_slice());
+
+    let buf_sz = 71 * 1024;
+    assert!(buf_sz > DEFAULT_BUF_SIZE, "test precondition");
+
+    let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source));
+    let mut sink = WriteObserver { observed_buffer: 0 };
+    assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
+    assert_eq!(
+        sink.observed_buffer, buf_sz,
+        "expected a large buffer to be provided to the writer"
+    );
+}
+
+#[cfg(unix)]
+mod io_benches {
+    use crate::fs::File;
+    use crate::fs::OpenOptions;
+    use crate::io::prelude::*;
+    use crate::io::BufReader;
+
+    use test::Bencher;
+
+    #[bench]
+    fn bench_copy_buf_reader(b: &mut Bencher) {
+        let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed");
+        // use dyn to avoid specializations unrelated to readbuf
+        let dyn_in = &mut file_in as &mut dyn Read;
+        let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0));
+        let mut writer =
+            OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed");
+
+        const BYTES: u64 = 1024 * 1024;
+
+        b.bytes = BYTES;
+
+        b.iter(|| {
+            reader.get_mut().set_limit(BYTES);
+            crate::io::copy(&mut reader, &mut writer).unwrap()
+        });
+    }
+}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 8a007d095d5..5c1d2d8f46c 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1416,17 +1416,18 @@ pub trait Write {
     ///
     /// This function will attempt to write the entire contents of `buf`, but
     /// the entire write might not succeed, or the write may also generate an
-    /// error. A call to `write` represents *at most one* attempt to write to
+    /// error. Typically, a call to `write` represents one attempt to write to
     /// any wrapped object.
     ///
     /// Calls to `write` are not guaranteed to block waiting for data to be
     /// written, and a write which would otherwise block can be indicated through
     /// an [`Err`] variant.
     ///
-    /// If the return value is [`Ok(n)`] then it must be guaranteed that
-    /// `n <= buf.len()`. A return value of `0` typically means that the
-    /// underlying object is no longer able to accept bytes and will likely not
-    /// be able to in the future as well, or that the buffer provided is empty.
+    /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`].
+    /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`.
+    /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the
+    /// caller may interpret that as an error.  To indicate lack of space,
+    /// implementors should return [`ErrorKind::StorageFull`] error instead.
     ///
     /// # Errors
     ///
@@ -2754,7 +2755,7 @@ trait SizeHint {
     }
 }
 
-impl<T> SizeHint for T {
+impl<T: ?Sized> SizeHint for T {
     #[inline]
     default fn lower_bound(&self) -> usize {
         0
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index ce5e2c9da1d..1baa94e64c9 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,68 +1,9 @@
-use crate::cmp::{max, min};
 use crate::io::prelude::*;
-use crate::io::{
-    copy, empty, repeat, sink, BorrowedBuf, BufWriter, Empty, Repeat, Result, SeekFrom, Sink,
-    DEFAULT_BUF_SIZE,
-};
+use crate::io::{empty, repeat, sink, BorrowedBuf, Empty, Repeat, SeekFrom, Sink};
 
 use crate::mem::MaybeUninit;
 
 #[test]
-fn copy_copies() {
-    let mut r = repeat(0).take(4);
-    let mut w = sink();
-    assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
-
-    let mut r = repeat(0).take(1 << 17);
-    assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
-}
-
-struct ShortReader {
-    cap: usize,
-    read_size: usize,
-    observed_buffer: usize,
-}
-
-impl Read for ShortReader {
-    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
-        let bytes = min(self.cap, self.read_size);
-        self.cap -= bytes;
-        self.observed_buffer = max(self.observed_buffer, buf.len());
-        Ok(bytes)
-    }
-}
-
-struct WriteObserver {
-    observed_buffer: usize,
-}
-
-impl Write for WriteObserver {
-    fn write(&mut self, buf: &[u8]) -> Result<usize> {
-        self.observed_buffer = max(self.observed_buffer, buf.len());
-        Ok(buf.len())
-    }
-
-    fn flush(&mut self) -> Result<()> {
-        Ok(())
-    }
-}
-
-#[test]
-fn copy_specializes_bufwriter() {
-    let cap = 117 * 1024;
-    let buf_sz = 16 * 1024;
-    let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
-    let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 });
-    assert_eq!(
-        copy(&mut r, &mut w).unwrap(),
-        cap as u64,
-        "expected the whole capacity to be copied"
-    );
-    assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader");
-    assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes");
-}
-
-#[test]
 fn sink_sinks() {
     let mut s = sink();
     assert_eq!(s.write(&[]).unwrap(), 0);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index d53f1a2b2ff..da08c018d0e 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -188,6 +188,13 @@
 //! [array]: prim@array
 //! [slice]: prim@slice
 
+// To run std tests without x.py without ending up with two copies of std, Miri needs to be
+// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
+// rustc itself never sets the feature, so this line has no affect there.
+#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
+// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
+#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
+//
 #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
 #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
 #![doc(
@@ -202,12 +209,6 @@
     no_global_oom_handling,
     not(no_global_oom_handling)
 ))]
-// To run std tests without x.py without ending up with two copies of std, Miri needs to be
-// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
-// rustc itself never sets the feature, so this line has no affect there.
-#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
-// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
-#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
 // Don't link to std. We are std.
 #![no_std]
 // Tell the compiler to link to either panic_abort or panic_unwind
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 7565fbc0d09..218536689fd 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -11,12 +11,19 @@ use crate::slice::from_raw_parts;
 use crate::sys::net::Socket;
 
 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
-#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))]
+#[cfg(all(
+    doc,
+    not(target_os = "linux"),
+    not(target_os = "android"),
+    not(target_os = "netbsd"),
+    not(target_os = "freebsd")
+))]
 #[allow(non_camel_case_types)]
 mod libc {
     pub use libc::c_int;
     pub struct ucred;
     pub struct cmsghdr;
+    pub struct sockcred2;
     pub type pid_t = i32;
     pub type gid_t = u32;
     pub type uid_t = u32;
diff --git a/library/std/src/personality.rs b/library/std/src/personality.rs
index 63f0ad4f16e..386a399f532 100644
--- a/library/std/src/personality.rs
+++ b/library/std/src/personality.rs
@@ -29,7 +29,7 @@ cfg_if::cfg_if! {
         all(target_family = "windows", target_env = "gnu"),
         target_os = "psp",
         target_os = "solid_asp3",
-        all(target_family = "unix", not(target_os = "espidf")),
+        all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")),
         all(target_vendor = "fortanix", target_env = "sgx"),
     ))] {
         mod gcc;
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 8266e899011..80289ca08c3 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -308,7 +308,7 @@ mod prim_never {}
 ///
 /// ```no_run
 /// // Undefined behaviour
-/// unsafe { char::from_u32_unchecked(0x110000) };
+/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
 /// ```
 ///
 /// USVs are also the exact set of values that may be encoded in UTF-8. Because
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 16c8e0c0ebf..7d49bbdcbe0 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -466,7 +466,7 @@ impl<T: CopyRead> CopyRead for Take<T> {
     }
 }
 
-impl<T: CopyRead> CopyRead for BufReader<T> {
+impl<T: ?Sized + CopyRead> CopyRead for BufReader<T> {
     fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
         let buf = self.buffer();
         let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))];
@@ -495,7 +495,7 @@ impl<T: CopyRead> CopyRead for BufReader<T> {
     }
 }
 
-impl<T: CopyWrite> CopyWrite for BufWriter<T> {
+impl<T: ?Sized + CopyWrite> CopyWrite for BufWriter<T> {
     fn properties(&self) -> CopyParams {
         self.get_ref().properties()
     }
diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs
index ee016887e70..fe9559f2a56 100644
--- a/library/std/src/sys/unix/l4re.rs
+++ b/library/std/src/sys/unix/l4re.rs
@@ -10,7 +10,7 @@ macro_rules! unimpl {
 pub mod net {
     #![allow(warnings)]
     use crate::fmt;
-    use crate::io::{self, IoSlice, IoSliceMut};
+    use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
     use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
     use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
     use crate::sys::fd::FileDesc;
@@ -218,6 +218,10 @@ pub mod net {
             unimpl!();
         }
 
+        pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> {
+            unimpl!();
+        }
+
         pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
             unimpl!();
         }
diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs
index 142fcb9ed0b..f7333fd5a1f 100644
--- a/library/std/src/sys/unix/os_str.rs
+++ b/library/std/src/sys/unix/os_str.rs
@@ -207,8 +207,8 @@ impl Slice {
         unsafe { Slice::from_os_str_bytes_unchecked(s.as_bytes()) }
     }
 
-    pub fn to_str(&self) -> Option<&str> {
-        str::from_utf8(&self.inner).ok()
+    pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> {
+        str::from_utf8(&self.inner)
     }
 
     pub fn to_string_lossy(&self) -> Cow<'_, str> {
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 3721988b405..22d9d6141f4 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -836,31 +836,47 @@ fn signal_string(signal: i32) -> &'static str {
         libc::SIGILL => " (SIGILL)",
         libc::SIGTRAP => " (SIGTRAP)",
         libc::SIGABRT => " (SIGABRT)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGBUS => " (SIGBUS)",
         libc::SIGFPE => " (SIGFPE)",
         libc::SIGKILL => " (SIGKILL)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGUSR1 => " (SIGUSR1)",
         libc::SIGSEGV => " (SIGSEGV)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGUSR2 => " (SIGUSR2)",
         libc::SIGPIPE => " (SIGPIPE)",
         libc::SIGALRM => " (SIGALRM)",
         libc::SIGTERM => " (SIGTERM)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGCHLD => " (SIGCHLD)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGCONT => " (SIGCONT)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGSTOP => " (SIGSTOP)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGTSTP => " (SIGTSTP)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGTTIN => " (SIGTTIN)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGTTOU => " (SIGTTOU)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGURG => " (SIGURG)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGXCPU => " (SIGXCPU)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGXFSZ => " (SIGXFSZ)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGVTALRM => " (SIGVTALRM)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGPROF => " (SIGPROF)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGWINCH => " (SIGWINCH)",
-        #[cfg(not(target_os = "haiku"))]
+        #[cfg(not(any(target_os = "haiku", target_os = "l4re")))]
         libc::SIGIO => " (SIGIO)",
         #[cfg(target_os = "haiku")]
         libc::SIGPOLL => " (SIGPOLL)",
+        #[cfg(not(target_os = "l4re"))]
         libc::SIGSYS => " (SIGSYS)",
         // For information on Linux signals, run `man 7 signal`
         #[cfg(all(
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 878af5088d9..010015667f7 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -344,6 +344,29 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                 }
             }
 
+            #[cfg(target_os = "netbsd")]
+            {
+                unsafe {
+                    let set = libc::_cpuset_create();
+                    if !set.is_null() {
+                        let mut count: usize = 0;
+                        if libc::pthread_getaffinity_np(libc::pthread_self(), libc::_cpuset_size(set), set) == 0 {
+                            for i in 0..u64::MAX {
+                                match libc::_cpuset_isset(i, set) {
+                                    -1 => break,
+                                    0 => continue,
+                                    _ => count = count + 1,
+                                }
+                            }
+                        }
+                        libc::_cpuset_destroy(set);
+                        if let Some(count) = NonZeroUsize::new(count) {
+                            return Ok(count);
+                        }
+                    }
+                }
+            }
+
             let mut cpus: libc::c_uint = 0;
             let mut cpus_size = crate::mem::size_of_val(&cpus);
 
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 07b0610d463..5fc6136ba1f 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -19,6 +19,7 @@ pub use windows_sys::*;
 pub type DWORD = c_ulong;
 pub type NonZeroDWORD = NonZero_c_ulong;
 pub type LARGE_INTEGER = c_longlong;
+#[cfg_attr(target_vendor = "uwp", allow(unused))]
 pub type LONG = c_long;
 pub type UINT = c_uint;
 pub type WCHAR = u16;
@@ -267,6 +268,8 @@ pub unsafe fn getaddrinfo(
     windows_sys::getaddrinfo(node.cast::<u8>(), service.cast::<u8>(), hints, res)
 }
 
+cfg_if::cfg_if! {
+if #[cfg(not(target_vendor = "uwp"))] {
 pub unsafe fn NtReadFile(
     filehandle: BorrowedHandle<'_>,
     event: HANDLE,
@@ -313,6 +316,8 @@ pub unsafe fn NtWriteFile(
         key.map(|k| k as *const u32).unwrap_or(ptr::null()),
     )
 }
+}
+}
 
 // Functions that aren't available on every version of Windows that we support,
 // but we still use them and just provide some form of a fallback implementation.
@@ -376,4 +381,54 @@ compat_fn_with_fallback! {
     ) -> NTSTATUS {
         panic!("keyed events not available")
     }
+
+    // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically.
+    #[cfg(target_vendor = "uwp")]
+    pub fn NtCreateFile(
+        filehandle: *mut HANDLE,
+        desiredaccess: FILE_ACCESS_RIGHTS,
+        objectattributes: *const OBJECT_ATTRIBUTES,
+        iostatusblock: *mut IO_STATUS_BLOCK,
+        allocationsize: *const i64,
+        fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
+        shareaccess: FILE_SHARE_MODE,
+        createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
+        createoptions: NTCREATEFILE_CREATE_OPTIONS,
+        eabuffer: *const ::core::ffi::c_void,
+        ealength: u32
+    ) -> NTSTATUS {
+        STATUS_NOT_IMPLEMENTED
+    }
+    #[cfg(target_vendor = "uwp")]
+    pub fn NtReadFile(
+        filehandle: BorrowedHandle<'_>,
+        event: HANDLE,
+        apcroutine: PIO_APC_ROUTINE,
+        apccontext: *mut c_void,
+        iostatusblock: &mut IO_STATUS_BLOCK,
+        buffer: *mut crate::mem::MaybeUninit<u8>,
+        length: ULONG,
+        byteoffset: Option<&LARGE_INTEGER>,
+        key: Option<&ULONG>
+    ) -> NTSTATUS {
+        STATUS_NOT_IMPLEMENTED
+    }
+    #[cfg(target_vendor = "uwp")]
+    pub fn NtWriteFile(
+        filehandle: BorrowedHandle<'_>,
+        event: HANDLE,
+        apcroutine: PIO_APC_ROUTINE,
+        apccontext: *mut c_void,
+        iostatusblock: &mut IO_STATUS_BLOCK,
+        buffer: *const u8,
+        length: ULONG,
+        byteoffset: Option<&LARGE_INTEGER>,
+        key: Option<&ULONG>
+    ) -> NTSTATUS {
+        STATUS_NOT_IMPLEMENTED
+    }
+    #[cfg(target_vendor = "uwp")]
+    pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 {
+        Status as u32
+    }
 }
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst
index 3e454199f13..2cf1ade99ce 100644
--- a/library/std/src/sys/windows/c/windows_sys.lst
+++ b/library/std/src/sys/windows/c/windows_sys.lst
@@ -1930,6 +1930,7 @@ Windows.Win32.Foundation.SetLastError
 Windows.Win32.Foundation.STATUS_DELETE_PENDING
 Windows.Win32.Foundation.STATUS_END_OF_FILE
 Windows.Win32.Foundation.STATUS_INVALID_PARAMETER
+Windows.Win32.Foundation.STATUS_NOT_IMPLEMENTED
 Windows.Win32.Foundation.STATUS_PENDING
 Windows.Win32.Foundation.STATUS_SUCCESS
 Windows.Win32.Foundation.TRUE
diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs
index 36a30f6ba56..a4294f336fe 100644
--- a/library/std/src/sys/windows/c/windows_sys.rs
+++ b/library/std/src/sys/windows/c/windows_sys.rs
@@ -3888,6 +3888,7 @@ pub type STARTUPINFOW_FLAGS = u32;
 pub const STATUS_DELETE_PENDING: NTSTATUS = -1073741738i32;
 pub const STATUS_END_OF_FILE: NTSTATUS = -1073741807i32;
 pub const STATUS_INVALID_PARAMETER: NTSTATUS = -1073741811i32;
+pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = -1073741822i32;
 pub const STATUS_PENDING: NTSTATUS = 259i32;
 pub const STATUS_SUCCESS: NTSTATUS = 0i32;
 pub const STD_ERROR_HANDLE: STD_HANDLE = 4294967284u32;
@@ -4274,3 +4275,23 @@ impl ::core::clone::Clone for XSAVE_FORMAT {
         *self
     }
 }
+// Begin of ARM32 shim
+// The raw content of this file should be processed by `generate-windows-sys`
+// to be merged with the generated binding. It is not supposed to be used as
+// a normal Rust module.
+cfg_if::cfg_if! {
+if #[cfg(target_arch = "arm")] {
+#[repr(C)]
+pub struct WSADATA {
+    pub wVersion: u16,
+    pub wHighVersion: u16,
+    pub szDescription: [u8; 257],
+    pub szSystemStatus: [u8; 129],
+    pub iMaxSockets: u16,
+    pub iMaxUdpDg: u16,
+    pub lpVendorInfo: PSTR,
+}
+pub enum CONTEXT {}
+}
+}
+// End of ARM32 shim
diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs
index 611f0d040f0..16c4f55c687 100644
--- a/library/std/src/sys/windows/os_str.rs
+++ b/library/std/src/sys/windows/os_str.rs
@@ -166,7 +166,7 @@ impl Slice {
         unsafe { mem::transmute(Wtf8::from_str(s)) }
     }
 
-    pub fn to_str(&self) -> Option<&str> {
+    pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> {
         self.inner.as_str()
     }
 
diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs
index bca4e38d9f6..5d8fd13785a 100644
--- a/library/std/src/sys/windows/rand.rs
+++ b/library/std/src/sys/windows/rand.rs
@@ -1,5 +1,3 @@
-use crate::ffi::c_void;
-use crate::io;
 use crate::mem;
 use crate::ptr;
 use crate::sys::c;
@@ -25,6 +23,9 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 #[cfg(not(target_vendor = "uwp"))]
 #[inline(never)]
 fn fallback_rng() -> (u64, u64) {
+    use crate::ffi::c_void;
+    use crate::io;
+
     let mut v = (0, 0);
     let ret = unsafe {
         c::RtlGenRandom(&mut v as *mut _ as *mut c_void, mem::size_of_val(&v) as c::ULONG)
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 31bb0ad25a6..c9d3e13cf0c 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -626,13 +626,8 @@ impl Wtf8 {
     ///
     /// This does not copy the data.
     #[inline]
-    pub fn as_str(&self) -> Option<&str> {
-        // Well-formed WTF-8 is also well-formed UTF-8
-        // if and only if it contains no surrogate.
-        match self.next_surrogate(0) {
-            None => Some(unsafe { str::from_utf8_unchecked(&self.bytes) }),
-            Some(_) => None,
-        }
+    pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
+        str::from_utf8(&self.bytes)
     }
 
     /// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`.
diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs
index 1a302d64694..a07bbe6d7e4 100644
--- a/library/std/src/sys_common/wtf8/tests.rs
+++ b/library/std/src/sys_common/wtf8/tests.rs
@@ -521,11 +521,11 @@ fn wtf8_code_points() {
 
 #[test]
 fn wtf8_as_str() {
-    assert_eq!(Wtf8::from_str("").as_str(), Some(""));
-    assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩"));
+    assert_eq!(Wtf8::from_str("").as_str(), Ok(""));
+    assert_eq!(Wtf8::from_str("aé 💩").as_str(), Ok("aé 💩"));
     let mut string = Wtf8Buf::new();
     string.push(CodePoint::from_u32(0xD800).unwrap());
-    assert_eq!(string.as_str(), None);
+    assert!(string.as_str().is_err());
 }
 
 #[test]
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index d9973185bc4..1230bb5deed 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -195,7 +195,7 @@ mod local;
 
 cfg_if::cfg_if! {
     if #[cfg(test)] {
-        // Avoid duplicating the global state assoicated with thread-locals between this crate and
+        // Avoid duplicating the global state associated with thread-locals between this crate and
         // realstd. Miri relies on this.
         pub use realstd::thread::{local_impl, AccessError, LocalKey};
     } else {