about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorSoveu <marx.tomasz@gmail.com>2021-03-15 21:51:38 +0100
committerGitHub <noreply@github.com>2021-03-15 21:51:38 +0100
commit96d6f22a8e7f04f2ae0712f7359470a78c77a9e0 (patch)
tree1660abccf0df54100751181250e049e830327b3c /library/std/src
parent2285f11724e2fa3251c94c9ab7672544099600e2 (diff)
parent2ccf06302c08d7d4911aad40e66a9a3ee731c6f9 (diff)
Merge branch 'master' into dedup
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/collections/hash/map.rs68
-rw-r--r--library/std/src/collections/hash/map/tests.rs8
-rw-r--r--library/std/src/error.rs40
-rw-r--r--library/std/src/f32.rs2
-rw-r--r--library/std/src/f64.rs2
-rw-r--r--library/std/src/ffi/c_str.rs6
-rw-r--r--library/std/src/ffi/os_str.rs88
-rw-r--r--library/std/src/io/buffered/bufreader.rs17
-rw-r--r--library/std/src/io/copy.rs2
-rw-r--r--library/std/src/io/impls.rs3
-rw-r--r--library/std/src/io/mod.rs40
-rw-r--r--library/std/src/io/stdio.rs16
-rw-r--r--library/std/src/io/tests.rs49
-rw-r--r--library/std/src/io/util.rs10
-rw-r--r--library/std/src/keyword_docs.rs8
-rw-r--r--library/std/src/lazy.rs15
-rw-r--r--library/std/src/lib.rs35
-rw-r--r--library/std/src/macros.rs17
-rw-r--r--library/std/src/os/mod.rs60
-rw-r--r--library/std/src/os/raw/mod.rs110
-rw-r--r--library/std/src/path.rs10
-rw-r--r--library/std/src/prelude/mod.rs34
-rw-r--r--library/std/src/prelude/v1.rs11
-rw-r--r--library/std/src/primitive_docs.rs6
-rw-r--r--library/std/src/process.rs50
-rw-r--r--library/std/src/sync/mpsc/mod.rs1
-rw-r--r--library/std/src/sync/mutex.rs20
-rw-r--r--library/std/src/sync/rwlock.rs4
-rw-r--r--library/std/src/sys/mod.rs31
-rw-r--r--library/std/src/sys/sgx/abi/mem.rs42
-rw-r--r--library/std/src/sys/unix/ext/net/ancillary.rs10
-rw-r--r--library/std/src/sys/unix/ext/net/datagram.rs44
-rw-r--r--library/std/src/sys/unix/ext/net/stream.rs21
-rw-r--r--library/std/src/sys/unix/ext/net/tests.rs18
-rw-r--r--library/std/src/sys/unix/ext/process.rs27
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs18
-rw-r--r--library/std/src/sys/unix/kernel_copy/tests.rs18
-rw-r--r--library/std/src/sys/unix/net.rs8
-rw-r--r--library/std/src/sys/unix/os.rs19
-rw-r--r--library/std/src/sys/unix/process/process_common.rs22
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs36
-rw-r--r--library/std/src/sys/unix/process/process_unix/tests.rs30
-rw-r--r--library/std/src/sys/unix/stack_overflow.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs4
-rw-r--r--library/std/src/sys/wasi/ext/fs.rs30
-rw-r--r--library/std/src/sys/wasi/ext/io.rs12
-rw-r--r--library/std/src/sys/wasi/ext/mod.rs36
-rw-r--r--library/std/src/sys/wasi/fs.rs16
-rw-r--r--library/std/src/sys/wasi/net.rs2
-rw-r--r--library/std/src/sys/wasi/stdio.rs2
-rw-r--r--library/std/src/sys/windows/ext/process.rs21
-rw-r--r--library/std/src/sys/windows/path.rs6
-rw-r--r--library/std/src/sys/windows/process.rs12
-rw-r--r--library/std/src/sys/windows/process/tests.rs26
-rw-r--r--library/std/src/sys_common/rwlock.rs59
-rw-r--r--library/std/src/sys_common/thread_local_dtor.rs2
56 files changed, 919 insertions, 389 deletions
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 27f7191831d..233afa92389 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-filelength
+
 #[cfg(test)]
 mod tests;
 
@@ -842,6 +844,37 @@ where
         self.base.insert(k, v)
     }
 
+    /// Tries to insert a key-value pair into the map, and returns
+    /// a mutable reference to the value in the entry.
+    ///
+    /// If the map already had this key present, nothing is updated, and
+    /// an error containing the occupied entry and the value is returned.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(map_try_insert)]
+    ///
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// assert_eq!(map.try_insert(37, "a").unwrap(), &"a");
+    ///
+    /// let err = map.try_insert(37, "b").unwrap_err();
+    /// assert_eq!(err.entry.key(), &37);
+    /// assert_eq!(err.entry.get(), &"a");
+    /// assert_eq!(err.value, "b");
+    /// ```
+    #[unstable(feature = "map_try_insert", issue = "82766")]
+    pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V>> {
+        match self.entry(key) {
+            Occupied(entry) => Err(OccupiedError { entry, value }),
+            Vacant(entry) => Ok(entry.insert(value)),
+        }
+    }
+
     /// Removes a key from the map, returning the value at the key if the key
     /// was previously in the map.
     ///
@@ -1851,6 +1884,41 @@ impl<K: Debug, V> Debug for VacantEntry<'_, K, V> {
     }
 }
 
+/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists.
+///
+/// Contains the occupied entry, and the value that was not inserted.
+#[unstable(feature = "map_try_insert", issue = "82766")]
+pub struct OccupiedError<'a, K: 'a, V: 'a> {
+    /// The entry in the map that was already occupied.
+    pub entry: OccupiedEntry<'a, K, V>,
+    /// The value which was not inserted, because the entry was already occupied.
+    pub value: V,
+}
+
+#[unstable(feature = "map_try_insert", issue = "82766")]
+impl<K: Debug, V: Debug> Debug for OccupiedError<'_, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OccupiedError")
+            .field("key", self.entry.key())
+            .field("old_value", self.entry.get())
+            .field("new_value", &self.value)
+            .finish()
+    }
+}
+
+#[unstable(feature = "map_try_insert", issue = "82766")]
+impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "failed to insert {:?}, key {:?} already exists with value {:?}",
+            self.value,
+            self.entry.key(),
+            self.entry.get(),
+        )
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> {
     type Item = (&'a K, &'a V);
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 467968354e2..819be142227 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -774,11 +774,11 @@ fn test_occupied_entry_key() {
     let key = "hello there";
     let value = "value goes here";
     assert!(a.is_empty());
-    a.insert(key.clone(), value.clone());
+    a.insert(key, value);
     assert_eq!(a.len(), 1);
     assert_eq!(a[key], value);
 
-    match a.entry(key.clone()) {
+    match a.entry(key) {
         Vacant(_) => panic!(),
         Occupied(e) => assert_eq!(key, *e.key()),
     }
@@ -793,11 +793,11 @@ fn test_vacant_entry_key() {
     let value = "value goes here";
 
     assert!(a.is_empty());
-    match a.entry(key.clone()) {
+    match a.entry(key) {
         Occupied(_) => panic!(),
         Vacant(e) => {
             assert_eq!(key, *e.key());
-            e.insert(value.clone());
+            e.insert(value);
         }
     }
     assert_eq!(a.len(), 1);
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 605d953f5da..80c35307d52 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -30,6 +30,7 @@ use crate::mem::transmute;
 use crate::num;
 use crate::str;
 use crate::string;
+use crate::sync::Arc;
 
 /// `Error` is a trait representing the basic expectations for error values,
 /// i.e., values of type `E` in [`Result<T, E>`]. Errors must describe
@@ -469,6 +470,24 @@ impl Error for char::DecodeUtf16Error {
     }
 }
 
+#[unstable(feature = "map_try_insert", issue = "82766")]
+impl<'a, K: Debug + Ord, V: Debug> Error
+    for crate::collections::btree_map::OccupiedError<'a, K, V>
+{
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        "key already exists"
+    }
+}
+
+#[unstable(feature = "map_try_insert", issue = "82766")]
+impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> {
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        "key already exists"
+    }
+}
+
 #[stable(feature = "box_error", since = "1.8.0")]
 impl<T: Error> Error for Box<T> {
     #[allow(deprecated, deprecated_in_future)]
@@ -507,6 +526,27 @@ impl<'a, T: Error + ?Sized> Error for &'a T {
     }
 }
 
+#[stable(feature = "arc_error", since = "1.52.0")]
+impl<T: Error + ?Sized> Error for Arc<T> {
+    #[allow(deprecated, deprecated_in_future)]
+    fn description(&self) -> &str {
+        Error::description(&**self)
+    }
+
+    #[allow(deprecated)]
+    fn cause(&self) -> Option<&dyn Error> {
+        Error::cause(&**self)
+    }
+
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        Error::source(&**self)
+    }
+
+    fn backtrace(&self) -> Option<&Backtrace> {
+        Error::backtrace(&**self)
+    }
+}
+
 #[stable(feature = "fmt_error", since = "1.11.0")]
 impl Error for fmt::Error {
     #[allow(deprecated)]
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index f51b2c24621..c16d27fa1f5 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -503,7 +503,7 @@ impl f32 {
         unsafe { cmath::fdimf(self, other) }
     }
 
-    /// Returns the cubic root of a number.
+    /// Returns the cube root of a number.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 8c41e448686..4c95df5ffe0 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -505,7 +505,7 @@ impl f64 {
         unsafe { cmath::fdim(self, other) }
     }
 
-    /// Returns the cubic root of a number.
+    /// Returns the cube root of a number.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 230ef0b23db..945bfda1b78 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -62,20 +62,18 @@ use crate::sys;
 /// u8` argument which is not necessarily nul-terminated, plus another
 /// argument with the length of the string — like C's `strndup()`.
 /// You can of course get the slice's length with its
-/// [`len`][slice.len] method.
+/// [`len`][slice::len] method.
 ///
 /// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
 /// can use [`CString::as_bytes_with_nul`] instead.
 ///
 /// Once you have the kind of slice you need (with or without a nul
 /// terminator), you can call the slice's own
-/// [`as_ptr`][slice.as_ptr] method to get a read-only raw pointer to pass to
+/// [`as_ptr`][slice::as_ptr] method to get a read-only raw pointer to pass to
 /// extern functions. See the documentation for that function for a
 /// discussion on ensuring the lifetime of the raw pointer.
 ///
 /// [`&str`]: prim@str
-/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr
-/// [slice.len]: ../primitive.slice.html#method.len
 /// [`Deref`]: ops::Deref
 /// [`&CStr`]: CStr
 ///
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 5bb3f6bdcfd..ce52ffc0241 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -5,6 +5,7 @@ use crate::borrow::{Borrow, Cow};
 use crate::cmp;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
+use crate::iter::{Extend, FromIterator};
 use crate::ops;
 use crate::rc::Rc;
 use crate::str::FromStr;
@@ -71,6 +72,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
 /// [`CStr`]: crate::ffi::CStr
 /// [conversions]: super#conversions
 #[derive(Clone)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "OsString")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsString {
     inner: Buf,
@@ -93,6 +95,7 @@ impl crate::sealed::Sealed for OsString {}
 ///
 /// [`&str`]: str
 /// [conversions]: super#conversions
+#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")]
 #[stable(feature = "rust1", since = "1.0.0")]
 // FIXME:
 // `OsStr::from_inner` current implementation relies
@@ -1190,3 +1193,88 @@ impl FromStr for OsString {
         Ok(OsString::from(s))
     }
 }
+
+#[stable(feature = "osstring_extend", since = "1.52.0")]
+impl Extend<OsString> for OsString {
+    #[inline]
+    fn extend<T: IntoIterator<Item = OsString>>(&mut self, iter: T) {
+        for s in iter {
+            self.push(&s);
+        }
+    }
+}
+
+#[stable(feature = "osstring_extend", since = "1.52.0")]
+impl<'a> Extend<&'a OsStr> for OsString {
+    #[inline]
+    fn extend<T: IntoIterator<Item = &'a OsStr>>(&mut self, iter: T) {
+        for s in iter {
+            self.push(s);
+        }
+    }
+}
+
+#[stable(feature = "osstring_extend", since = "1.52.0")]
+impl<'a> Extend<Cow<'a, OsStr>> for OsString {
+    #[inline]
+    fn extend<T: IntoIterator<Item = Cow<'a, OsStr>>>(&mut self, iter: T) {
+        for s in iter {
+            self.push(&s);
+        }
+    }
+}
+
+#[stable(feature = "osstring_extend", since = "1.52.0")]
+impl FromIterator<OsString> for OsString {
+    #[inline]
+    fn from_iter<I: IntoIterator<Item = OsString>>(iter: I) -> Self {
+        let mut iterator = iter.into_iter();
+
+        // Because we're iterating over `OsString`s, we can avoid at least
+        // one allocation by getting the first string from the iterator
+        // and appending to it all the subsequent strings.
+        match iterator.next() {
+            None => OsString::new(),
+            Some(mut buf) => {
+                buf.extend(iterator);
+                buf
+            }
+        }
+    }
+}
+
+#[stable(feature = "osstring_extend", since = "1.52.0")]
+impl<'a> FromIterator<&'a OsStr> for OsString {
+    #[inline]
+    fn from_iter<I: IntoIterator<Item = &'a OsStr>>(iter: I) -> Self {
+        let mut buf = Self::new();
+        for s in iter {
+            buf.push(s);
+        }
+        buf
+    }
+}
+
+#[stable(feature = "osstring_extend", since = "1.52.0")]
+impl<'a> FromIterator<Cow<'a, OsStr>> for OsString {
+    #[inline]
+    fn from_iter<I: IntoIterator<Item = Cow<'a, OsStr>>>(iter: I) -> Self {
+        let mut iterator = iter.into_iter();
+
+        // Because we're iterating over `OsString`s, we can avoid at least
+        // one allocation by getting the first owned string from the iterator
+        // and appending to it all the subsequent strings.
+        match iterator.next() {
+            None => OsString::new(),
+            Some(Cow::Owned(mut buf)) => {
+                buf.extend(iterator);
+                buf
+            }
+            Some(Cow::Borrowed(buf)) => {
+                let mut buf = OsString::from(buf);
+                buf.extend(iterator);
+                buf
+            }
+        }
+    }
+}
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 987371f50ec..02b0fc0c57d 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -1,6 +1,8 @@
 use crate::cmp;
 use crate::fmt;
-use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE};
+use crate::io::{
+    self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
+};
 
 /// The `BufReader<R>` struct adds buffering to any reader.
 ///
@@ -90,10 +92,9 @@ 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 buffer = Vec::with_capacity(capacity);
-            buffer.set_len(capacity);
-            inner.initializer().initialize(&mut buffer);
-            BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 }
+            let mut buf = Box::new_uninit_slice(capacity).assume_init();
+            inner.initializer().initialize(&mut buf);
+            BufReader { inner, buf, pos: 0, cap: 0 }
         }
     }
 }
@@ -435,3 +436,9 @@ impl<R: Seek> Seek for BufReader<R> {
         })
     }
 }
+
+impl<T> SizeHint for BufReader<T> {
+    fn lower_bound(&self) -> usize {
+        self.buffer().len()
+    }
+}
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 3780f2044cb..eb60df214c4 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -106,7 +106,7 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
                     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`
+                        // 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.
                         unsafe { buf.set_len(buf.len() + bytes_read) };
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 00bf8b9af73..9870cfc4c95 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -1,6 +1,7 @@
 #[cfg(test)]
 mod tests;
 
+use crate::alloc::Allocator;
 use crate::cmp;
 use crate::fmt;
 use crate::io::{
@@ -357,7 +358,7 @@ impl Write for &mut [u8] {
 /// Write is implemented for `Vec<u8>` by appending to the vector.
 /// The vector will grow as needed.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl Write for Vec<u8> {
+impl<A: Allocator> Write for Vec<u8, A> {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.extend_from_slice(buf);
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index db3b0e2628f..17002e3b860 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -482,7 +482,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
 /// }
 /// ```
 ///
-/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`:
+/// Read from [`&str`] because [`&[u8]`][prim@slice] implements `Read`:
 ///
 /// ```no_run
 /// # use std::io;
@@ -504,7 +504,6 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
 /// [`&str`]: prim@str
 /// [`std::io`]: self
 /// [`File`]: crate::fs::File
-/// [slice]: ../../std/primitive.slice.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(spotlight)]
 pub trait Read {
@@ -2239,6 +2238,19 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
     }
 }
 
+impl<T, U> SizeHint for Chain<T, U> {
+    fn lower_bound(&self) -> usize {
+        SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second)
+    }
+
+    fn upper_bound(&self) -> Option<usize> {
+        match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) {
+            (Some(first), Some(second)) => Some(first + second),
+            _ => None,
+        }
+    }
+}
+
 /// Reader adaptor which limits the bytes read from an underlying reader.
 ///
 /// This struct is generally created by calling [`take`] on a reader.
@@ -2465,6 +2477,30 @@ impl<R: Read> Iterator for Bytes<R> {
             };
         }
     }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        SizeHint::size_hint(&self.inner)
+    }
+}
+
+trait SizeHint {
+    fn lower_bound(&self) -> usize;
+
+    fn upper_bound(&self) -> Option<usize>;
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.lower_bound(), self.upper_bound())
+    }
+}
+
+impl<T> SizeHint for T {
+    default fn lower_bound(&self) -> usize {
+        0
+    }
+
+    default fn upper_bound(&self) -> Option<usize> {
+        None
+    }
 }
 
 /// An iterator over the contents of an instance of `BufRead` split on a
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 1160011f352..1e72c9e0611 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -231,7 +231,7 @@ pub struct Stdin {
     inner: &'static Mutex<BufReader<StdinRaw>>,
 }
 
-/// A locked reference to the `Stdin` handle.
+/// A locked reference to the [`Stdin`] handle.
 ///
 /// This handle implements both the [`Read`] and [`BufRead`] traits, and
 /// is constructed via the [`Stdin::lock`] method.
@@ -251,8 +251,8 @@ pub struct Stdin {
 ///     let mut buffer = String::new();
 ///     let stdin = io::stdin(); // We get `Stdin` here.
 ///     {
-///         let mut stdin_lock = stdin.lock(); // We get `StdinLock` here.
-///         stdin_lock.read_to_string(&mut buffer)?;
+///         let mut handle = stdin.lock(); // We get `StdinLock` here.
+///         handle.read_to_string(&mut buffer)?;
 ///     } // `StdinLock` is dropped here.
 ///     Ok(())
 /// }
@@ -494,10 +494,10 @@ pub struct Stdout {
     inner: Pin<&'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
 }
 
-/// A locked reference to the `Stdout` handle.
+/// A locked reference to the [`Stdout`] handle.
 ///
 /// This handle implements the [`Write`] trait, and is constructed via
-/// the [`Stdout::lock`] method.
+/// the [`Stdout::lock`] method. See its documentation for more.
 ///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
@@ -708,10 +708,10 @@ pub struct Stderr {
     inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>,
 }
 
-/// A locked reference to the `Stderr` handle.
+/// A locked reference to the [`Stderr`] handle.
 ///
-/// This handle implements the `Write` trait and is constructed via
-/// the [`Stderr::lock`] method.
+/// This handle implements the [`Write`] trait and is constructed via
+/// the [`Stderr::lock`] method. See its documentation for more.
 ///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index f176c2f088c..a85dd0d9827 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -1,7 +1,7 @@
 use super::{repeat, Cursor, SeekFrom};
 use crate::cmp::{self, min};
 use crate::io::{self, IoSlice, IoSliceMut};
-use crate::io::{BufRead, Read, Seek, Write};
+use crate::io::{BufRead, BufReader, Read, Seek, Write};
 use crate::ops::Deref;
 
 #[test]
@@ -199,6 +199,53 @@ fn chain_bufread() {
 }
 
 #[test]
+fn bufreader_size_hint() {
+    let testdata = b"ABCDEFGHIJKL";
+    let mut buf_reader = BufReader::new(&testdata[..]);
+    assert_eq!(buf_reader.buffer().len(), 0);
+
+    let buffer_length = testdata.len();
+    buf_reader.fill_buf().unwrap();
+
+    // Check that size hint matches buffer contents
+    let mut buffered_bytes = buf_reader.bytes();
+    let (lower_bound, _upper_bound) = buffered_bytes.size_hint();
+    assert_eq!(lower_bound, buffer_length);
+
+    // Check that size hint matches buffer contents after advancing
+    buffered_bytes.next().unwrap().unwrap();
+    let (lower_bound, _upper_bound) = buffered_bytes.size_hint();
+    assert_eq!(lower_bound, buffer_length - 1);
+}
+
+#[test]
+fn empty_size_hint() {
+    let size_hint = io::empty().bytes().size_hint();
+    assert_eq!(size_hint, (0, Some(0)));
+}
+
+#[test]
+fn chain_empty_size_hint() {
+    let chain = io::empty().chain(io::empty());
+    let size_hint = chain.bytes().size_hint();
+    assert_eq!(size_hint, (0, Some(0)));
+}
+
+#[test]
+fn chain_size_hint() {
+    let testdata = b"ABCDEFGHIJKL";
+    let mut buf_reader_1 = BufReader::new(&testdata[..6]);
+    let mut buf_reader_2 = BufReader::new(&testdata[6..]);
+
+    buf_reader_1.fill_buf().unwrap();
+    buf_reader_2.fill_buf().unwrap();
+
+    let chain = buf_reader_1.chain(buf_reader_2);
+    let size_hint = chain.bytes().size_hint();
+    assert_eq!(size_hint, (testdata.len(), None));
+}
+
+#[test]
 fn chain_zero_length_read_is_not_eof() {
     let a = b"A";
     let b = b"B";
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index e43ce4cdb4b..f472361f916 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -4,7 +4,9 @@
 mod tests;
 
 use crate::fmt;
-use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
+use crate::io::{
+    self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
+};
 
 /// A reader which is always at EOF.
 ///
@@ -80,6 +82,12 @@ impl fmt::Debug for Empty {
     }
 }
 
+impl SizeHint for Empty {
+    fn upper_bound(&self) -> Option<usize> {
+        Some(0)
+    }
+}
+
 /// A reader which yields one byte over and over and over and over and over and...
 ///
 /// This struct is generally created by calling [`repeat()`]. Please
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 6b06539a094..383eaf2e3a2 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -42,7 +42,7 @@
 /// [Reference]: ../reference/expressions/operator-expr.html#type-cast-expressions
 /// [`crate`]: keyword.crate.html
 /// [`use`]: keyword.use.html
-/// [const-cast]: primitive.pointer.html#method.cast
+/// [const-cast]: pointer::cast
 /// [mut-cast]: primitive.pointer.html#method.cast-1
 mod as_keyword {}
 
@@ -181,9 +181,8 @@ mod break_keyword {}
 /// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const
 /// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive].
 ///
-/// [pointer primitive]: primitive.pointer.html
-/// [Rust Book]:
-/// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
+/// [pointer primitive]: pointer
+/// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
 /// [Reference]: ../reference/items/constant-items.html
 /// [const-eval]: ../reference/const_eval.html
 mod const_keyword {}
@@ -371,7 +370,6 @@ mod else_keyword {}
 /// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type
 /// [Rust Book]: ../book/ch06-01-defining-an-enum.html
 /// [Reference]: ../reference/items/enumerations.html
-/// [`!`]: primitive.never.html
 mod enum_keyword {}
 
 #[doc(keyword = "extern")]
diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs
index 68f57958bb2..974851a8bd6 100644
--- a/library/std/src/lazy.rs
+++ b/library/std/src/lazy.rs
@@ -177,7 +177,10 @@ impl<T> SyncOnceCell<T> {
 
     /// Sets the contents of this cell to `value`.
     ///
-    /// Returns `Ok(())` if the cell's value was updated.
+    /// May block if another thread is currently attempting to initialize the cell. The cell is
+    /// guaranteed to contain a value when set returns, though not necessarily the one provided.
+    ///
+    /// Returns `Ok(())` if the cell's value was set by this call.
     ///
     /// # Examples
     ///
@@ -440,13 +443,17 @@ impl<T> SyncOnceCell<T> {
         res
     }
 
-    /// Safety: The value must be initialized
+    /// # Safety
+    ///
+    /// The value must be initialized
     unsafe fn get_unchecked(&self) -> &T {
         debug_assert!(self.is_initialized());
         (&*self.value.get()).assume_init_ref()
     }
 
-    /// Safety: The value must be initialized
+    /// # Safety
+    ///
+    /// The value must be initialized
     unsafe fn get_unchecked_mut(&mut self) -> &mut T {
         debug_assert!(self.is_initialized());
         (&mut *self.value.get()).assume_init_mut()
@@ -456,7 +463,7 @@ impl<T> SyncOnceCell<T> {
 unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
     fn drop(&mut self) {
         if self.is_initialized() {
-            // Safety: The cell is initialized and being dropped, so it can't
+            // SAFETY: The cell is initialized and being dropped, so it can't
             // be accessed again. We also don't touch the `T` other than
             // dropping it, which validates our usage of #[may_dangle].
             unsafe { (&mut *self.value.get()).assume_init_drop() };
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index bc9b4702941..8149858e103 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -61,14 +61,14 @@
 //!    type, but not the all-important methods.
 //!
 //! So for example there is a [page for the primitive type
-//! `i32`](primitive.i32.html) that lists all the methods that can be called on
+//! `i32`](primitive::i32) that lists all the methods that can be called on
 //! 32-bit integers (very useful), and there is a [page for the module
 //! `std::i32`] that documents the constant values [`MIN`] and [`MAX`] (rarely
 //! useful).
 //!
-//! Note the documentation for the primitives [`str`] and [`[T]`][slice] (also
+//! Note the documentation for the primitives [`str`] and [`[T]`][prim@slice] (also
 //! called 'slice'). Many method calls on [`String`] and [`Vec<T>`] are actually
-//! calls to methods on [`str`] and [`[T]`][slice] respectively, via [deref
+//! calls to methods on [`str`] and [`[T]`][prim@slice] respectively, via [deref
 //! coercions][deref-coercions].
 //!
 //! Third, the standard library defines [The Rust Prelude], a small collection
@@ -111,8 +111,8 @@
 //! regions of memory:
 //!
 //! * [`Vec<T>`] - A heap-allocated *vector* that is resizable at runtime.
-//! * [`[T; n]`][array] - An inline *array* with a fixed size at compile time.
-//! * [`[T]`][slice] - A dynamically sized *slice* into any other kind of contiguous
+//! * [`[T; N]`][prim@array] - An inline *array* with a fixed size at compile time.
+//! * [`[T]`][prim@slice] - A dynamically sized *slice* into any other kind of contiguous
 //!   storage, whether heap-allocated or not.
 //!
 //! Slices can only be handled through some kind of *pointer*, and as such come
@@ -185,8 +185,8 @@
 //! [other]: #what-is-in-the-standard-library-documentation
 //! [primitive types]: ../book/ch03-02-data-types.html
 //! [rust-discord]: https://discord.gg/rust-lang
-#![cfg_attr(not(bootstrap), doc = "[array]: prim@array")]
-#![cfg_attr(not(bootstrap), doc = "[slice]: prim@slice")]
+//! [array]: prim@array
+//! [slice]: prim@slice
 #![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(
@@ -228,11 +228,13 @@
 #![feature(arbitrary_self_types)]
 #![feature(array_error_internals)]
 #![feature(asm)]
+#![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(atomic_mut_ptr)]
 #![feature(box_syntax)]
 #![feature(c_variadic)]
 #![feature(cfg_accessible)]
+#![cfg_attr(not(bootstrap), feature(cfg_eval))]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
@@ -263,7 +265,7 @@
 #![feature(exact_size_is_empty)]
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
-#![feature(external_doc)]
+#![feature(extended_key_value_attributes)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]
@@ -275,11 +277,13 @@
 #![feature(int_error_matching)]
 #![feature(integer_atomics)]
 #![feature(into_future)]
+#![feature(intra_doc_pointers)]
 #![feature(lang_items)]
 #![feature(link_args)]
 #![feature(linkage)]
 #![feature(llvm_asm)]
 #![feature(log_syntax)]
+#![feature(map_try_insert)]
 #![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
@@ -288,6 +292,7 @@
 #![feature(needs_panic_runtime)]
 #![feature(negative_impls)]
 #![feature(never_type)]
+#![feature(new_uninit)]
 #![feature(nll)]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(once_cell)]
@@ -297,6 +302,7 @@
 #![feature(panic_internals)]
 #![feature(panic_unwind)]
 #![feature(pin_static_ref)]
+#![feature(prelude_2021)]
 #![feature(prelude_import)]
 #![feature(ptr_internals)]
 #![feature(raw)]
@@ -313,7 +319,6 @@
 #![feature(stdsimd)]
 #![feature(stmt_expr_attributes)]
 #![feature(str_internals)]
-#![feature(str_split_once)]
 #![feature(test)]
 #![feature(thread_local)]
 #![feature(thread_local_internals)]
@@ -323,7 +328,7 @@
 #![feature(try_blocks)]
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
-#![feature(unsafe_block_in_unsafe_fn)]
+#![cfg_attr(bootstrap, feature(unsafe_block_in_unsafe_fn))]
 #![feature(unsafe_cell_raw_get)]
 #![feature(unwind_attributes)]
 #![feature(vec_into_raw_parts)]
@@ -391,7 +396,11 @@ pub use alloc_crate::vec;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::any;
 #[stable(feature = "simd_arch", since = "1.27.0")]
-#[doc(no_inline)]
+// The `no_inline`-attribute is required to make the documentation of all
+// targets available.
+// See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for
+// more information.
+#[doc(no_inline)] // Note (#82861): required for correct documentation
 pub use core::arch;
 #[stable(feature = "core_array", since = "1.36.0")]
 pub use core::array;
@@ -550,8 +559,8 @@ pub use std_detect::detect;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::{
-    assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, r#try, todo,
-    unimplemented, unreachable, write, writeln,
+    assert_eq, assert_matches, assert_ne, debug_assert, debug_assert_eq, debug_assert_matches,
+    debug_assert_ne, matches, r#try, todo, unimplemented, unreachable, write, writeln,
 };
 
 // Re-export built-in macros defined through libcore.
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 0ce6542cb72..b729349cf53 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -4,22 +4,7 @@
 //! library. Each macro is available for use when linking against the standard
 //! library.
 
-#[cfg(bootstrap)]
-#[doc(include = "../../core/src/macros/panic.md")]
-#[macro_export]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable(libstd_sys_internals)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")]
-macro_rules! panic {
-    () => ({ $crate::panic!("explicit panic") });
-    ($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) });
-    ($fmt:expr, $($arg:tt)+) => ({
-        $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))
-    });
-}
-
-#[cfg(not(bootstrap))]
-#[doc(include = "../../core/src/macros/panic.md")]
+#[doc = include_str!("../../core/src/macros/panic.md")]
 #[macro_export]
 #[rustc_builtin_macro = "std_panic"]
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index fd6ee088e96..b95511e43d8 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -3,40 +3,48 @@
 #![stable(feature = "os", since = "1.0.0")]
 #![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
 
-cfg_if::cfg_if! {
-    if #[cfg(doc)] {
+// When documenting libstd we want to show unix/windows/linux/wasi modules as these are the "main
+// modules" that are used across platforms, so all modules are enabled when `cfg(doc)` is set.
+// This should help show platform-specific functionality in a hopefully cross-platform way in the
+// documentation.
+// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make
+// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038
 
-        // When documenting libstd we want to show unix/windows/linux modules as
-        // these are the "main modules" that are used across platforms. This
-        // should help show platform-specific functionality in a hopefully
-        // cross-platform way in the documentation
+#[cfg(doc)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys::unix_ext as unix;
 
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use crate::sys::unix_ext as unix;
+#[cfg(doc)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys::windows_ext as windows;
 
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use crate::sys::windows_ext as windows;
+#[cfg(doc)]
+#[doc(cfg(target_os = "linux"))]
+pub mod linux;
 
-        #[doc(cfg(target_os = "linux"))]
-        pub mod linux;
-    } else {
+#[cfg(doc)]
+#[stable(feature = "wasi_ext_doc", since = "1.35.0")]
+pub use crate::sys::wasi_ext as wasi;
 
-        // If we're not documenting libstd then we just expose the main modules
-        // as we otherwise would.
+// If we're not documenting libstd then we just expose the main modules as we otherwise would.
 
-        #[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))]
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use crate::sys::ext as unix;
+#[cfg(not(doc))]
+#[cfg(any(unix, target_os = "hermit"))]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys::ext as unix;
 
-        #[cfg(windows)]
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use crate::sys::ext as windows;
+#[cfg(not(doc))]
+#[cfg(windows)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys::ext as windows;
 
-        #[cfg(any(target_os = "linux", target_os = "l4re"))]
-        pub mod linux;
+#[cfg(not(doc))]
+#[cfg(any(target_os = "linux", target_os = "l4re"))]
+pub mod linux;
 
-    }
-}
+#[cfg(not(doc))]
+#[cfg(target_os = "wasi")]
+pub mod wasi;
 
 #[cfg(target_os = "android")]
 pub mod android;
@@ -68,7 +76,5 @@ pub mod redox;
 pub mod solaris;
 #[cfg(target_os = "vxworks")]
 pub mod vxworks;
-#[cfg(target_os = "wasi")]
-pub mod wasi;
 
 pub mod raw;
diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs
index 16272aa0571..50464a050c7 100644
--- a/library/std/src/os/raw/mod.rs
+++ b/library/std/src/os/raw/mod.rs
@@ -11,7 +11,41 @@
 #[cfg(test)]
 mod tests;
 
-#[doc(include = "char.md")]
+use core::num::*;
+
+macro_rules! type_alias_no_nz {
+    {
+      $Docfile:tt, $Alias:ident = $Real:ty;
+      $( $Cfg:tt )*
+    } => {
+        #[doc = include_str!($Docfile)]
+        $( $Cfg )*
+        #[stable(feature = "raw_os", since = "1.1.0")]
+        pub type $Alias = $Real;
+    }
+}
+
+// To verify that the NonZero types in this file's macro invocations correspond
+//
+//  perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2'
+//
+// NB this does not check that the main c_* types are right.
+
+macro_rules! type_alias {
+    {
+      $Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty;
+      $( $Cfg:tt )*
+    } => {
+        type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* }
+
+        #[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")]
+        #[unstable(feature = "raw_os_nonzero", issue = "82363")]
+        $( $Cfg )*
+        pub type $NZAlias = $NZReal;
+    }
+}
+
+type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8;
 #[cfg(any(
     all(
         target_os = "linux",
@@ -52,10 +86,8 @@ mod tests;
         )
     ),
     all(target_os = "fuchsia", target_arch = "aarch64")
-))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_char = u8;
-#[doc(include = "char.md")]
+))]}
+type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8;
 #[cfg(not(any(
     all(
         target_os = "linux",
@@ -96,55 +128,25 @@ pub type c_char = u8;
         )
     ),
     all(target_os = "fuchsia", target_arch = "aarch64")
-)))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_char = i8;
-#[doc(include = "schar.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_schar = i8;
-#[doc(include = "uchar.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_uchar = u8;
-#[doc(include = "short.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_short = i16;
-#[doc(include = "ushort.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_ushort = u16;
-#[doc(include = "int.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_int = i32;
-#[doc(include = "uint.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_uint = u32;
-#[doc(include = "long.md")]
-#[cfg(any(target_pointer_width = "32", windows))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_long = i32;
-#[doc(include = "ulong.md")]
-#[cfg(any(target_pointer_width = "32", windows))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_ulong = u32;
-#[doc(include = "long.md")]
-#[cfg(all(target_pointer_width = "64", not(windows)))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_long = i64;
-#[doc(include = "ulong.md")]
-#[cfg(all(target_pointer_width = "64", not(windows)))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_ulong = u64;
-#[doc(include = "longlong.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_longlong = i64;
-#[doc(include = "ulonglong.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_ulonglong = u64;
-#[doc(include = "float.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_float = f32;
-#[doc(include = "double.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_double = f64;
+)))]}
+type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
+type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
+type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
+type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; }
+type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; }
+type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; }
+type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32;
+#[cfg(any(target_pointer_width = "32", windows))] }
+type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32;
+#[cfg(any(target_pointer_width = "32", windows))] }
+type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64;
+#[cfg(all(target_pointer_width = "64", not(windows)))] }
+type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64;
+#[cfg(all(target_pointer_width = "64", not(windows)))] }
+type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; }
+type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; }
+type_alias_no_nz! { "float.md", c_float = f32; }
+type_alias_no_nz! { "double.md", c_double = f64; }
 
 #[stable(feature = "raw_os", since = "1.1.0")]
 #[doc(no_inline)]
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 1889e549338..de3b57df44e 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1066,6 +1066,7 @@ impl FusedIterator for Ancestors<'_> {}
 ///
 /// Which method works best depends on what kind of situation you're in.
 #[derive(Clone)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")]
 #[stable(feature = "rust1", since = "1.0.0")]
 // FIXME:
 // `PathBuf::as_mut_vec` current implementation relies
@@ -1719,6 +1720,7 @@ impl AsRef<OsStr> for PathBuf {
 /// let extension = path.extension();
 /// assert_eq!(extension, Some(OsStr::new("txt")));
 /// ```
+#[cfg_attr(not(test), rustc_diagnostic_item = "Path")]
 #[stable(feature = "rust1", since = "1.0.0")]
 // FIXME:
 // `Path::new` current implementation relies
@@ -2321,7 +2323,9 @@ impl Path {
     }
 
     /// Returns an object that implements [`Display`] for safely printing paths
-    /// that may contain non-Unicode data.
+    /// that may contain non-Unicode data. This may perform lossy conversion,
+    /// depending on the platform.  If you would like an implementation which
+    /// escapes the path please use [`Debug`] instead.
     ///
     /// [`Display`]: fmt::Display
     ///
@@ -2555,7 +2559,9 @@ impl fmt::Debug for Path {
 ///
 /// A [`Path`] might contain non-Unicode data. This `struct` implements the
 /// [`Display`] trait in a way that mitigates that. It is created by the
-/// [`display`](Path::display) method on [`Path`].
+/// [`display`](Path::display) method on [`Path`]. This may perform lossy
+/// conversion, depending on the platform. If you would like an implementation
+/// which escapes the path please use [`Debug`] instead.
 ///
 /// # Examples
 ///
diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs
index eb2095b8196..505b5f3013b 100644
--- a/library/std/src/prelude/mod.rs
+++ b/library/std/src/prelude/mod.rs
@@ -84,3 +84,37 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 pub mod v1;
+
+/// The 2015 version of the prelude of The Rust Standard Library.
+///
+/// See the [module-level documentation](self) for more.
+#[unstable(feature = "prelude_2015", issue = "none")]
+pub mod rust_2015 {
+    #[unstable(feature = "prelude_2015", issue = "none")]
+    #[doc(no_inline)]
+    pub use super::v1::*;
+}
+
+/// The 2018 version of the prelude of The Rust Standard Library.
+///
+/// See the [module-level documentation](self) for more.
+#[unstable(feature = "prelude_2018", issue = "none")]
+pub mod rust_2018 {
+    #[unstable(feature = "prelude_2018", issue = "none")]
+    #[doc(no_inline)]
+    pub use super::v1::*;
+}
+
+/// The 2021 version of the prelude of The Rust Standard Library.
+///
+/// See the [module-level documentation](self) for more.
+#[unstable(feature = "prelude_2021", issue = "none")]
+pub mod rust_2021 {
+    #[unstable(feature = "prelude_2021", issue = "none")]
+    #[doc(no_inline)]
+    pub use super::v1::*;
+
+    #[unstable(feature = "prelude_2021", issue = "none")]
+    #[doc(no_inline)]
+    pub use core::prelude::rust_2021::*;
+}
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index ef9aec54a4c..ec89bb6d2a4 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -1,6 +1,6 @@
 //! The first version of the prelude of The Rust Standard Library.
 //!
-//! See the [module-level documentation](../index.html) for more.
+//! See the [module-level documentation](super) for more.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -67,6 +67,15 @@ pub use core::prelude::v1::derive;
 #[doc(hidden)]
 pub use core::prelude::v1::cfg_accessible;
 
+#[cfg(not(bootstrap))]
+#[unstable(
+    feature = "cfg_eval",
+    issue = "82679",
+    reason = "`cfg_eval` is a recently implemented feature"
+)]
+#[doc(hidden)]
+pub use core::prelude::v1::cfg_eval;
+
 // The file so far is equivalent to src/libcore/prelude/v1.rs,
 // and below to src/liballoc/prelude.rs.
 // Those files are duplicated rather than using glob imports
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 876b2b8a3f6..d4bb2083d00 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -468,8 +468,8 @@ mod prim_unit {}
 ///
 /// [`null`]: ptr::null
 /// [`null_mut`]: ptr::null_mut
-/// [`is_null`]: ../std/primitive.pointer.html#method.is_null
-/// [`offset`]: ../std/primitive.pointer.html#method.offset
+/// [`is_null`]: pointer::is_null
+/// [`offset`]: pointer::offset
 /// [`into_raw`]: Box::into_raw
 /// [`drop`]: mem::drop
 /// [`write`]: ptr::write
@@ -564,7 +564,7 @@ mod prim_pointer {}
 /// move_away(roa);
 /// ```
 ///
-/// [slice]: primitive.slice.html
+/// [slice]: prim@slice
 /// [`Debug`]: fmt::Debug
 /// [`Hash`]: hash::Hash
 /// [`Borrow`]: borrow::Borrow
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 6480e654c55..f9cfd11e906 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -71,11 +71,15 @@
 //!     .spawn()
 //!     .expect("failed to execute child");
 //!
-//! {
-//!     // limited borrow of stdin
-//!     let stdin = child.stdin.as_mut().expect("failed to get stdin");
+//! // If the child process fills its stdout buffer, it may end up
+//! // waiting until the parent reads the stdout, and not be able to
+//! // read stdin in the meantime, causing a deadlock.
+//! // Writing from another thread ensures that stdout is being read
+//! // at the same time, avoiding the problem.
+//! let mut stdin = child.stdin.take().expect("failed to get stdin");
+//! std::thread::spawn(move || {
 //!     stdin.write_all(b"test").expect("failed to write to stdin");
-//! }
+//! });
 //!
 //! let output = child
 //!     .wait_with_output()
@@ -885,7 +889,7 @@ impl Command {
     }
 
     /// Executes a command as a child process, waiting for it to finish and
-    /// collecting its exit status.
+    /// collecting its status.
     ///
     /// By default, stdin, stdout and stderr are inherited from the parent.
     ///
@@ -899,7 +903,7 @@ impl Command {
     ///                      .status()
     ///                      .expect("failed to execute process");
     ///
-    /// println!("process exited with: {}", status);
+    /// println!("process finished with: {}", status);
     ///
     /// assert!(status.success());
     /// ```
@@ -1145,14 +1149,21 @@ impl Stdio {
     ///     .spawn()
     ///     .expect("Failed to spawn child process");
     ///
-    /// {
-    ///     let stdin = child.stdin.as_mut().expect("Failed to open stdin");
+    /// let mut stdin = child.stdin.take().expect("Failed to open stdin");
+    /// std::thread::spawn(move || {
     ///     stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin");
-    /// }
+    /// });
     ///
     /// let output = child.wait_with_output().expect("Failed to read stdout");
     /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH");
     /// ```
+    ///
+    /// Writing more than a pipe buffer's worth of input to stdin without also reading
+    /// stdout and stderr at the same time may cause a deadlock.
+    /// This is an issue when running any program that doesn't guarantee that it reads
+    /// its entire stdin before writing more than a pipe buffer's worth of output.
+    /// The size of a pipe buffer varies on different targets.
+    ///
     #[stable(feature = "process", since = "1.0.0")]
     pub fn piped() -> Stdio {
         Stdio(imp::Stdio::MakePipe)
@@ -1368,11 +1379,17 @@ impl From<fs::File> for Stdio {
 
 /// Describes the result of a process after it has terminated.
 ///
-/// This `struct` is used to represent the exit status of a child process.
+/// This `struct` is used to represent the exit status or other termination of a child process.
 /// Child processes are created via the [`Command`] struct and their exit
 /// status is exposed through the [`status`] method, or the [`wait`] method
 /// of a [`Child`] process.
 ///
+/// An `ExitStatus` represents every possible disposition of a process.  On Unix this
+/// is the **wait status**.  It is *not* simply an *exit status* (a value passed to `exit`).
+///
+/// For proper error reporting of failed processes, print the value of `ExitStatus` using its
+/// implementation of [`Display`](crate::fmt::Display).
+///
 /// [`status`]: Command::status
 /// [`wait`]: Child::wait
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -1400,7 +1417,7 @@ impl ExitStatus {
     /// if status.success() {
     ///     println!("'projects/' directory created");
     /// } else {
-    ///     println!("failed to create 'projects/' directory");
+    ///     println!("failed to create 'projects/' directory: {}", status);
     /// }
     /// ```
     #[stable(feature = "process", since = "1.0.0")]
@@ -1410,9 +1427,14 @@ impl ExitStatus {
 
     /// Returns the exit code of the process, if any.
     ///
-    /// On Unix, this will return `None` if the process was terminated
-    /// by a signal; `std::os::unix` provides an extension trait for
-    /// extracting the signal and other details from the `ExitStatus`.
+    /// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the
+    /// process finished by calling `exit`.  Note that on Unix the exit status is truncated to 8
+    /// bits, and that values that didn't come from a program's call to `exit` may be invented the
+    /// runtime system (often, for example, 255, 254, 127 or 126).
+    ///
+    /// On Unix, this will return `None` if the process was terminated by a signal.
+    /// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt) is an
+    /// extension trait for extracting any such signal, and other details, from the `ExitStatus`.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index db0777ee9f0..b12e7eeb138 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -310,6 +310,7 @@ mod cache_aligned;
 /// println!("{}", recv.recv().unwrap()); // Received after 2 seconds
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Receiver")]
 pub struct Receiver<T> {
     inner: UnsafeCell<Flavor<T>>,
 }
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index a01ebb316e8..ab61618dc7d 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -219,6 +219,26 @@ impl<T> Mutex<T> {
             data: UnsafeCell::new(t),
         }
     }
+
+    /// Immediately drops the guard, and consequently unlocks the mutex.
+    ///
+    /// This function is equivalent to calling [`drop`] on the guard but is more self-documenting.
+    /// Alternately, the guard will be automatically dropped when it goes out of scope.
+    ///
+    /// ```
+    /// #![feature(mutex_unlock)]
+    ///
+    /// use std::sync::Mutex;
+    /// let mutex = Mutex::new(0);
+    ///
+    /// let mut guard = mutex.lock().unwrap();
+    /// *guard += 20;
+    /// Mutex::unlock(guard);
+    /// ```
+    #[unstable(feature = "mutex_unlock", issue = "81872")]
+    pub fn unlock(guard: MutexGuard<'_, T>) {
+        drop(guard);
+    }
 }
 
 impl<T: ?Sized> Mutex<T> {
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index d967779ce36..0298f59228c 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -23,7 +23,9 @@ use crate::sys_common::rwlock as sys;
 ///
 /// The priority policy of the lock is dependent on the underlying operating
 /// system's implementation, and this type does not guarantee that any
-/// particular policy will be used.
+/// particular policy will be used. In particular, a writer which is waiting to
+/// acquire the lock in `write` might or might not block concurrent calls to
+/// `read`.
 ///
 /// The type parameter `T` represents the data that this lock protects. It is
 /// required that `T` satisfies [`Send`] to be shared across threads and
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index d48d9cb0efc..1e79a5c3f9b 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -61,9 +61,9 @@ cfg_if::cfg_if! {
         #[stable(feature = "rust1", since = "1.0.0")]
         pub use self::ext as unix_ext;
     } else if #[cfg(any(target_os = "hermit",
-                        target_arch = "wasm32",
+                        all(target_arch = "wasm32", not(target_os = "wasi")),
                         all(target_vendor = "fortanix", target_env = "sgx")))] {
-        // On wasm right now the module below doesn't compile
+        // On non-WASI wasm right now the module below doesn't compile
         // (missing things in `libc` which is empty) so just omit everything
         // with an empty module
         #[unstable(issue = "none", feature = "std_internals")]
@@ -85,9 +85,9 @@ cfg_if::cfg_if! {
         #[stable(feature = "rust1", since = "1.0.0")]
         pub use self::ext as windows_ext;
     } else if #[cfg(any(target_os = "hermit",
-                        target_arch = "wasm32",
+                        all(target_arch = "wasm32", not(target_os = "wasi")),
                         all(target_vendor = "fortanix", target_env = "sgx")))] {
-        // On wasm right now the shim below doesn't compile, so
+        // On non-WASI wasm right now the shim below doesn't compile, so
         // just omit it
         #[unstable(issue = "none", feature = "std_internals")]
         #[allow(missing_docs)]
@@ -106,3 +106,26 @@ cfg_if::cfg_if! {
         pub mod windows_ext;
     }
 }
+
+#[cfg(doc)]
+cfg_if::cfg_if! {
+    if #[cfg(target_os = "wasi")] {
+        // On WASI we'll document what's already available
+        #[stable(feature = "wasi_ext_doc", since = "1.35.0")]
+        pub use self::ext as wasi_ext;
+    } else if #[cfg(any(target_os = "hermit",
+                        target_arch = "wasm32",
+                        all(target_vendor = "fortanix", target_env = "sgx")))] {
+        // On non-WASI wasm right now the module below doesn't compile
+        // (missing things in `libc` which is empty) so just omit everything
+        // with an empty module
+        #[unstable(issue = "none", feature = "std_internals")]
+        #[allow(missing_docs)]
+        pub mod wasi_ext {}
+    } else {
+        // On other platforms like Windows document the bare bones of WASI
+        #[path = "wasi/ext/mod.rs"]
+        #[stable(feature = "wasi_ext_doc", since = "1.35.0")]
+        pub mod wasi_ext;
+    }
+}
diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs
index da899773dbb..3753fdd3536 100644
--- a/library/std/src/sys/sgx/abi/mem.rs
+++ b/library/std/src/sys/sgx/abi/mem.rs
@@ -47,20 +47,46 @@ pub fn image_base() -> u64 {
 
 /// Returns `true` if the specified memory range is in the enclave.
 ///
-/// `p + len` must not overflow.
+/// For safety, this function also checks whether the range given overflows,
+/// returning `false` if so.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn is_enclave_range(p: *const u8, len: usize) -> bool {
-    let start = p as u64;
-    let end = start + (len as u64);
-    start >= image_base() && end <= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant
+    let start = p as usize;
+
+    // Subtract one from `len` when calculating `end` in case `p + len` is
+    // exactly at the end of addressable memory (`p + len` would overflow, but
+    // the range is still valid).
+    let end = if len == 0 {
+        start
+    } else if let Some(end) = start.checked_add(len - 1) {
+        end
+    } else {
+        return false;
+    };
+
+    let base = image_base() as usize;
+    start >= base && end <= base + (unsafe { ENCLAVE_SIZE } - 1) // unsafe ok: link-time constant
 }
 
 /// Returns `true` if the specified memory range is in userspace.
 ///
-/// `p + len` must not overflow.
+/// For safety, this function also checks whether the range given overflows,
+/// returning `false` if so.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn is_user_range(p: *const u8, len: usize) -> bool {
-    let start = p as u64;
-    let end = start + (len as u64);
-    end <= image_base() || start >= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant
+    let start = p as usize;
+
+    // Subtract one from `len` when calculating `end` in case `p + len` is
+    // exactly at the end of addressable memory (`p + len` would overflow, but
+    // the range is still valid).
+    let end = if len == 0 {
+        start
+    } else if let Some(end) = start.checked_add(len - 1) {
+        end
+    } else {
+        return false;
+    };
+
+    let base = image_base() as usize;
+    end < base || start > base + (unsafe { ENCLAVE_SIZE } - 1) // unsafe ok: link-time constant
 }
diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs
index 0964b6335aa..33d6a39af07 100644
--- a/library/std/src/sys/unix/ext/net/ancillary.rs
+++ b/library/std/src/sys/unix/ext/net/ancillary.rs
@@ -1,6 +1,6 @@
 use super::{sockaddr_un, SocketAddr};
 use crate::convert::TryFrom;
-use crate::io::{self, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
 use crate::marker::PhantomData;
 use crate::mem::{size_of, zeroed};
 use crate::os::unix::io::RawFd;
@@ -68,7 +68,7 @@ pub(super) fn recv_vectored_with_ancillary_from(
 pub(super) fn send_vectored_with_ancillary_to(
     socket: &Socket,
     path: Option<&Path>,
-    bufs: &mut [IoSliceMut<'_>],
+    bufs: &[IoSlice<'_>],
     ancillary: &mut SocketAncillary<'_>,
 ) -> io::Result<usize> {
     unsafe {
@@ -78,7 +78,7 @@ pub(super) fn send_vectored_with_ancillary_to(
         let mut msg: libc::msghdr = zeroed();
         msg.msg_name = &mut msg_name as *mut _ as *mut _;
         msg.msg_namelen = msg_namelen;
-        msg.msg_iov = bufs.as_mut_ptr().cast();
+        msg.msg_iov = bufs.as_ptr() as *mut _;
         msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
         cfg_if::cfg_if! {
             if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
@@ -567,7 +567,7 @@ impl<'a> SocketAncillary<'a> {
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixStream, SocketAncillary};
     /// use std::os::unix::io::AsRawFd;
-    /// use std::io::IoSliceMut;
+    /// use std::io::IoSlice;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let sock = UnixStream::connect("/tmp/sock")?;
@@ -577,7 +577,7 @@ impl<'a> SocketAncillary<'a> {
     ///     ancillary.add_fds(&[sock.as_raw_fd()][..]);
     ///
     ///     let mut buf = [1; 8];
-    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+    ///     let mut bufs = &mut [IoSlice::new(&mut buf[..])][..];
     ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
     ///     Ok(())
     /// }
diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs
index 0f532c47c8f..a8c13fbb874 100644
--- a/library/std/src/sys/unix/ext/net/datagram.rs
+++ b/library/std/src/sys/unix/ext/net/datagram.rs
@@ -19,7 +19,7 @@ use super::{sockaddr_un, SocketAddr};
     target_os = "netbsd",
     target_os = "openbsd",
 ))]
-use crate::io::IoSliceMut;
+use crate::io::{IoSlice, IoSliceMut};
 use crate::net::Shutdown;
 use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 use crate::path::Path;
@@ -506,23 +506,24 @@ impl UnixDatagram {
     /// ```no_run
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
-    /// use std::io::IoSliceMut;
+    /// use std::io::IoSlice;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let sock = UnixDatagram::unbound()?;
-    ///     let mut buf1 = [1; 8];
-    ///     let mut buf2 = [2; 16];
-    ///     let mut buf3 = [3; 8];
-    ///     let mut bufs = &mut [
-    ///         IoSliceMut::new(&mut buf1),
-    ///         IoSliceMut::new(&mut buf2),
-    ///         IoSliceMut::new(&mut buf3),
+    ///     let buf1 = [1; 8];
+    ///     let buf2 = [2; 16];
+    ///     let buf3 = [3; 8];
+    ///     let bufs = &[
+    ///         IoSlice::new(&buf1),
+    ///         IoSlice::new(&buf2),
+    ///         IoSlice::new(&buf3),
     ///     ][..];
     ///     let fds = [0, 1, 2];
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     ancillary.add_fds(&fds[..]);
-    ///     sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed");
+    ///     sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock")
+    ///         .expect("send_vectored_with_ancillary_to function failed");
     ///     Ok(())
     /// }
     /// ```
@@ -538,7 +539,7 @@ impl UnixDatagram {
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>(
         &self,
-        bufs: &mut [IoSliceMut<'_>],
+        bufs: &[IoSlice<'_>],
         ancillary: &mut SocketAncillary<'_>,
         path: P,
     ) -> io::Result<usize> {
@@ -554,23 +555,24 @@ impl UnixDatagram {
     /// ```no_run
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
-    /// use std::io::IoSliceMut;
+    /// use std::io::IoSlice;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let sock = UnixDatagram::unbound()?;
-    ///     let mut buf1 = [1; 8];
-    ///     let mut buf2 = [2; 16];
-    ///     let mut buf3 = [3; 8];
-    ///     let mut bufs = &mut [
-    ///         IoSliceMut::new(&mut buf1),
-    ///         IoSliceMut::new(&mut buf2),
-    ///         IoSliceMut::new(&mut buf3),
+    ///     let buf1 = [1; 8];
+    ///     let buf2 = [2; 16];
+    ///     let buf3 = [3; 8];
+    ///     let bufs = &[
+    ///         IoSlice::new(&buf1),
+    ///         IoSlice::new(&buf2),
+    ///         IoSlice::new(&buf3),
     ///     ][..];
     ///     let fds = [0, 1, 2];
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     ancillary.add_fds(&fds[..]);
-    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed");
+    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)
+    ///         .expect("send_vectored_with_ancillary function failed");
     ///     Ok(())
     /// }
     /// ```
@@ -586,7 +588,7 @@ impl UnixDatagram {
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn send_vectored_with_ancillary(
         &self,
-        bufs: &mut [IoSliceMut<'_>],
+        bufs: &[IoSlice<'_>],
         ancillary: &mut SocketAncillary<'_>,
     ) -> io::Result<usize> {
         send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs
index 9fe6b85837e..fc08edacb82 100644
--- a/library/std/src/sys/unix/ext/net/stream.rs
+++ b/library/std/src/sys/unix/ext/net/stream.rs
@@ -530,23 +530,24 @@ impl UnixStream {
     /// ```no_run
     /// #![feature(unix_socket_ancillary_data)]
     /// use std::os::unix::net::{UnixStream, SocketAncillary};
-    /// use std::io::IoSliceMut;
+    /// use std::io::IoSlice;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let mut buf1 = [1; 8];
-    ///     let mut buf2 = [2; 16];
-    ///     let mut buf3 = [3; 8];
-    ///     let mut bufs = &mut [
-    ///         IoSliceMut::new(&mut buf1),
-    ///         IoSliceMut::new(&mut buf2),
-    ///         IoSliceMut::new(&mut buf3),
+    ///     let buf1 = [1; 8];
+    ///     let buf2 = [2; 16];
+    ///     let buf3 = [3; 8];
+    ///     let bufs = &[
+    ///         IoSlice::new(&buf1),
+    ///         IoSlice::new(&buf2),
+    ///         IoSlice::new(&buf3),
     ///     ][..];
     ///     let fds = [0, 1, 2];
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     ancillary.add_fds(&fds[..]);
-    ///     socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed");
+    ///     socket.send_vectored_with_ancillary(bufs, &mut ancillary)
+    ///         .expect("send_vectored_with_ancillary function failed");
     ///     Ok(())
     /// }
     /// ```
@@ -562,7 +563,7 @@ impl UnixStream {
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn send_vectored_with_ancillary(
         &self,
-        bufs: &mut [IoSliceMut<'_>],
+        bufs: &[IoSlice<'_>],
         ancillary: &mut SocketAncillary<'_>,
     ) -> io::Result<usize> {
         send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs
index 97a016904b4..bd9b6dd727b 100644
--- a/library/std/src/sys/unix/ext/net/tests.rs
+++ b/library/std/src/sys/unix/ext/net/tests.rs
@@ -485,14 +485,14 @@ fn test_unix_datagram_peek_from() {
 fn test_send_vectored_fds_unix_stream() {
     let (s1, s2) = or_panic!(UnixStream::pair());
 
-    let mut buf1 = [1; 8];
-    let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
+    let buf1 = [1; 8];
+    let bufs_send = &[IoSlice::new(&buf1[..])][..];
 
     let mut ancillary1_buffer = [0; 128];
     let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
     assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..]));
 
-    let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1));
+    let usize = or_panic!(s1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
     assert_eq!(usize, 8);
 
     let mut buf2 = [0; 8];
@@ -542,8 +542,8 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() {
 
     or_panic!(bsock2.set_passcred(true));
 
-    let mut buf1 = [1; 8];
-    let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
+    let buf1 = [1; 8];
+    let bufs_send = &[IoSlice::new(&buf1[..])][..];
 
     let mut ancillary1_buffer = [0; 128];
     let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
@@ -554,7 +554,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() {
     assert!(ancillary1.add_creds(&[cred1.clone()][..]));
 
     let usize =
-        or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2));
+        or_panic!(bsock1.send_vectored_with_ancillary_to(&bufs_send, &mut ancillary1, &path2));
     assert_eq!(usize, 8);
 
     let mut buf2 = [0; 8];
@@ -603,15 +603,15 @@ fn test_send_vectored_with_ancillary_unix_datagram() {
     let bsock1 = or_panic!(UnixDatagram::bind(&path1));
     let bsock2 = or_panic!(UnixDatagram::bind(&path2));
 
-    let mut buf1 = [1; 8];
-    let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
+    let buf1 = [1; 8];
+    let bufs_send = &[IoSlice::new(&buf1[..])][..];
 
     let mut ancillary1_buffer = [0; 128];
     let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
     assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..]));
 
     or_panic!(bsock1.connect(&path2));
-    let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1));
+    let usize = or_panic!(bsock1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
     assert_eq!(usize, 8);
 
     let mut buf2 = [0; 8];
diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs
index 7559c1f1d9e..1276edc6af6 100644
--- a/library/std/src/sys/unix/ext/process.rs
+++ b/library/std/src/sys/unix/ext/process.rs
@@ -62,9 +62,14 @@ pub trait CommandExt: Sealed {
     /// `fork`. This primarily means that any modifications made to memory on
     /// behalf of this closure will **not** be visible to the parent process.
     /// This is often a very constrained environment where normal operations
-    /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
+    /// like `malloc`, accessing environment variables through [`std::env`]
+    /// or acquiring a mutex are not guaranteed to work (due to
     /// other threads perhaps still running when the `fork` was run).
     ///
+    /// For further details refer to the [POSIX fork() specification]
+    /// and the equivalent documentation for any targeted
+    /// platform, especially the requirements around *async-signal-safety*.
+    ///
     /// This also means that all resources such as file descriptors and
     /// memory-mapped regions got duplicated. It is your responsibility to make
     /// sure that the closure does not violate library invariants by making
@@ -73,6 +78,10 @@ pub trait CommandExt: Sealed {
     /// When this closure is run, aspects such as the stdio file descriptors and
     /// working directory have successfully been changed, so output to these
     /// locations may not appear where intended.
+    ///
+    /// [POSIX fork() specification]:
+    ///     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
+    /// [`std::env`]: mod@crate::env
     #[stable(feature = "process_pre_exec", since = "1.34.0")]
     unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
     where
@@ -172,6 +181,8 @@ impl CommandExt for process::Command {
     }
 
     fn exec(&mut self) -> io::Error {
+        // NOTE: This may *not* be safe to call after `libc::fork`, because it
+        // may allocate. That may be worth fixing at some point in the future.
         self.as_inner_mut().exec(sys::process::Stdio::Inherit)
     }
 
@@ -186,12 +197,20 @@ impl CommandExt for process::Command {
 
 /// Unix-specific extensions to [`process::ExitStatus`].
 ///
+/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as passed to the
+/// `exit` system call or returned by [`ExitStatus::code()`](crate::process::ExitStatus::code).
+/// It represents **any wait status**, as returned by one of the `wait` family of system calls.
+///
+/// This is because a Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but
+/// can also represent other kinds of process event.
+///
 /// This trait is sealed: it cannot be implemented outside the standard library.
 /// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ExitStatusExt: Sealed {
-    /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
-    /// a process.
+    /// Creates a new `ExitStatus` from the raw underlying integer status value from `wait`
+    ///
+    /// The value should be a **wait status, not an exit status**.
     #[stable(feature = "exit_status_from", since = "1.12.0")]
     fn from_raw(raw: i32) -> Self;
 
@@ -220,6 +239,8 @@ pub trait ExitStatusExt: Sealed {
     fn continued(&self) -> bool;
 
     /// Returns the underlying raw `wait` status.
+    ///
+    /// The returned integer is a **wait status, not an exit status**.
     #[unstable(feature = "unix_process_wait_more", issue = "80695")]
     fn into_raw(self) -> i32;
 }
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 200dbf06ff8..9687576bb6a 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -61,6 +61,7 @@ use crate::process::{ChildStderr, ChildStdin, ChildStdout};
 use crate::ptr;
 use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
 use crate::sys::cvt;
+use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV};
 
 #[cfg(test)]
 mod tests;
@@ -535,7 +536,7 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
                 cvt(copy_file_range(INVALID_FD, ptr::null_mut(), INVALID_FD, ptr::null_mut(), 1, 0))
             };
 
-            if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(libc::EBADF))) {
+            if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(EBADF))) {
                 HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed);
             } else {
                 HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed);
@@ -573,19 +574,20 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
             Err(err) => {
                 return match err.raw_os_error() {
                     // when file offset + max_length > u64::MAX
-                    Some(libc::EOVERFLOW) => CopyResult::Fallback(written),
-                    Some(
-                        libc::ENOSYS | libc::EXDEV | libc::EINVAL | libc::EPERM | libc::EOPNOTSUPP,
-                    ) => {
+                    Some(EOVERFLOW) => CopyResult::Fallback(written),
+                    Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) => {
                         // Try fallback io::copy if either:
                         // - Kernel version is < 4.5 (ENOSYS¹)
                         // - Files are mounted on different fs (EXDEV)
                         // - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP)
                         // - 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²)
                         //
                         // ¹ 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)
                     }
@@ -649,7 +651,7 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
             Ok(ret) => written += ret as u64,
             Err(err) => {
                 return match err.raw_os_error() {
-                    Some(libc::ENOSYS | libc::EPERM) => {
+                    Some(ENOSYS | EPERM) => {
                         // syscall not supported (ENOSYS)
                         // syscall is disallowed, e.g. by seccomp (EPERM)
                         match mode {
@@ -659,12 +661,12 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
                         assert_eq!(written, 0);
                         CopyResult::Fallback(0)
                     }
-                    Some(libc::EINVAL) => {
+                    Some(EINVAL) => {
                         // splice/sendfile do not support this particular file descriptor (EINVAL)
                         assert_eq!(written, 0);
                         CopyResult::Fallback(0)
                     }
-                    Some(os_err) if mode == SpliceMode::Sendfile && os_err == libc::EOVERFLOW => {
+                    Some(os_err) if mode == SpliceMode::Sendfile && os_err == EOVERFLOW => {
                         CopyResult::Fallback(written)
                     }
                     _ => CopyResult::Error(err, written),
diff --git a/library/std/src/sys/unix/kernel_copy/tests.rs b/library/std/src/sys/unix/kernel_copy/tests.rs
index 77369cdd35f..3fe849e23e2 100644
--- a/library/std/src/sys/unix/kernel_copy/tests.rs
+++ b/library/std/src/sys/unix/kernel_copy/tests.rs
@@ -65,6 +65,24 @@ fn copy_specialization() -> Result<()> {
     result.and(rm1).and(rm2)
 }
 
+#[test]
+fn copies_append_mode_sink() -> Result<()> {
+    let tmp_path = tmpdir();
+    let source_path = tmp_path.join("copies_append_mode.source");
+    let sink_path = tmp_path.join("copies_append_mode.sink");
+    let mut source =
+        OpenOptions::new().create(true).truncate(true).write(true).read(true).open(&source_path)?;
+    write!(source, "not empty")?;
+    source.seek(SeekFrom::Start(0))?;
+    let mut sink = OpenOptions::new().create(true).append(true).open(&sink_path)?;
+
+    let copied = crate::io::copy(&mut source, &mut sink)?;
+
+    assert_eq!(copied, 9);
+
+    Ok(())
+}
+
 #[bench]
 fn bench_file_to_file_copy(b: &mut test::Bencher) {
     const BYTES: usize = 128 * 1024;
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 7198a2f08d6..587ffe15981 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -195,6 +195,7 @@ impl Socket {
         // glibc 2.10 and musl 0.9.5.
         cfg_if::cfg_if! {
             if #[cfg(any(
+                target_os = "android",
                 target_os = "dragonfly",
                 target_os = "freebsd",
                 target_os = "illumos",
@@ -206,13 +207,6 @@ impl Socket {
                     libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
                 })?;
                 Ok(Socket(FileDesc::new(fd)))
-            // While the Android kernel supports the syscall,
-            // it is not included in all versions of Android's libc.
-            } else if #[cfg(target_os = "android")] {
-                let fd = cvt_r(|| unsafe {
-                    libc::syscall(libc::SYS_accept4, self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
-                })?;
-                Ok(Socket(FileDesc::new(fd as c_int)))
             } else {
                 let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
                 let fd = FileDesc::new(fd);
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 1d1118aa694..d5e14bec765 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -22,7 +22,6 @@ use crate::str;
 use crate::sys::cvt;
 use crate::sys::fd;
 use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
-use crate::sys_common::rwlock::{RWLockReadGuard, StaticRWLock};
 use crate::vec;
 
 use libc::{c_char, c_int, c_void};
@@ -491,20 +490,20 @@ pub unsafe fn environ() -> *mut *const *const c_char {
     extern "C" {
         static mut environ: *const *const c_char;
     }
-    ptr::addr_of_mut!(environ)
+    &mut environ
 }
 
-static ENV_LOCK: StaticRWLock = StaticRWLock::new();
-
-pub fn env_read_lock() -> RWLockReadGuard {
-    ENV_LOCK.read_with_guard()
+pub unsafe fn env_lock() -> StaticMutexGuard {
+    // It is UB to attempt to acquire this mutex reentrantly!
+    static ENV_LOCK: StaticMutex = StaticMutex::new();
+    ENV_LOCK.lock()
 }
 
 /// Returns a vector of (variable, value) byte-vector pairs for all the
 /// environment variables of the current process.
 pub fn env() -> Env {
     unsafe {
-        let _guard = env_read_lock();
+        let _guard = env_lock();
         let mut environ = *environ();
         let mut result = Vec::new();
         if !environ.is_null() {
@@ -541,7 +540,7 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
     // always None as well
     let k = CString::new(k.as_bytes())?;
     unsafe {
-        let _guard = env_read_lock();
+        let _guard = env_lock();
         let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
         let ret = if s.is_null() {
             None
@@ -557,7 +556,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
     let v = CString::new(v.as_bytes())?;
 
     unsafe {
-        let _guard = ENV_LOCK.write_with_guard();
+        let _guard = env_lock();
         cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
     }
 }
@@ -566,7 +565,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
     let nbuf = CString::new(n.as_bytes())?;
 
     unsafe {
-        let _guard = ENV_LOCK.write_with_guard();
+        let _guard = env_lock();
         cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
     }
 }
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index a96d4aa6a45..b9dcc4e4b9e 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -60,25 +60,13 @@ cfg_if::cfg_if! {
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct Command {
-    // Currently we try hard to ensure that the call to `.exec()` doesn't
-    // actually allocate any memory. While many platforms try to ensure that
-    // memory allocation works after a fork in a multithreaded process, it's
-    // been observed to be buggy and somewhat unreliable, so we do our best to
-    // just not do it at all!
-    //
-    // Along those lines, the `argv` and `envp` raw pointers here are exactly
-    // what's gonna get passed to `execvp`. The `argv` array starts with the
-    // `program` and ends with a NULL, and the `envp` pointer, if present, is
-    // also null-terminated.
-    //
-    // Right now we don't support removing arguments, so there's no much fancy
-    // support there, but we support adding and removing environment variables,
-    // so a side table is used to track where in the `envp` array each key is
-    // located. Whenever we add a key we update it in place if it's already
-    // present, and whenever we remove a key we update the locations of all
-    // other keys.
     program: CString,
     args: Vec<CString>,
+    /// Exactly what will be passed to `execvp`.
+    ///
+    /// First element is a pointer to `program`, followed by pointers to
+    /// `args`, followed by a `null`. Be careful when modifying `program` or
+    /// `args` to properly update this as well.
     argv: Argv,
     env: CommandEnv,
 
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 9e82df7755e..2eb64a99e59 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -1,6 +1,7 @@
 use crate::convert::TryInto;
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
+use crate::mem;
 use crate::ptr;
 use crate::sys;
 use crate::sys::cvt;
@@ -45,15 +46,14 @@ impl Command {
         //
         // Note that as soon as we're done with the fork there's no need to hold
         // a lock any more because the parent won't do anything and the child is
-        // in its own process.
-        let result = unsafe {
-            let _env_lock = sys::os::env_read_lock();
-            cvt(libc::fork())?
-        };
+        // in its own process. Thus the parent drops the lock guard while the child
+        // forgets it to avoid unlocking it on a new thread, which would be invalid.
+        let (env_lock, result) = unsafe { (sys::os::env_lock(), cvt(libc::fork())?) };
 
         let pid = unsafe {
             match result {
                 0 => {
+                    mem::forget(env_lock);
                     drop(input);
                     let Err(err) = self.do_exec(theirs, envp.as_ref());
                     let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
@@ -74,7 +74,10 @@ impl Command {
                     rtassert!(output.write(&bytes).is_ok());
                     libc::_exit(1)
                 }
-                n => n,
+                n => {
+                    drop(env_lock);
+                    n
+                }
             }
         };
 
@@ -124,7 +127,7 @@ impl Command {
                     // Similar to when forking, we want to ensure that access to
                     // the environment is synchronized, so make sure to grab the
                     // environment lock before we try to exec.
-                    let _lock = sys::os::env_read_lock();
+                    let _lock = sys::os::env_lock();
 
                     let Err(e) = self.do_exec(theirs, envp.as_ref());
                     e
@@ -404,7 +407,7 @@ impl Command {
             cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
 
             // Make sure we synchronize access to the global `environ` resource
-            let _env_lock = sys::os::env_read_lock();
+            let _env_lock = sys::os::env_lock();
             let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
             cvt_nz(libc::posix_spawnp(
                 &mut p.pid,
@@ -527,9 +530,22 @@ impl fmt::Display for ExitStatus {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if let Some(code) = self.code() {
             write!(f, "exit code: {}", code)
+        } else if let Some(signal) = self.signal() {
+            if self.core_dumped() {
+                write!(f, "signal: {} (core dumped)", signal)
+            } else {
+                write!(f, "signal: {}", signal)
+            }
+        } else if let Some(signal) = self.stopped_signal() {
+            write!(f, "stopped (not terminated) by signal: {}", signal)
+        } else if self.continued() {
+            write!(f, "continued (WIFCONTINUED)")
         } else {
-            let signal = self.signal().unwrap();
-            write!(f, "signal: {}", signal)
+            write!(f, "unrecognised wait status: {} {:#x}", self.0, self.0)
         }
     }
 }
+
+#[cfg(test)]
+#[path = "process_unix/tests.rs"]
+mod tests;
diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs
new file mode 100644
index 00000000000..5819d2c2a5a
--- /dev/null
+++ b/library/std/src/sys/unix/process/process_unix/tests.rs
@@ -0,0 +1,30 @@
+#[test]
+fn exitstatus_display_tests() {
+    // In practice this is the same on every Unix.
+    // If some weird platform turns out to be different, and this test fails, use #[cfg].
+    use crate::os::unix::process::ExitStatusExt;
+    use crate::process::ExitStatus;
+
+    let t = |v, s| assert_eq!(s, format!("{}", <ExitStatus as ExitStatusExt>::from_raw(v)));
+
+    t(0x0000f, "signal: 15");
+    t(0x0008b, "signal: 11 (core dumped)");
+    t(0x00000, "exit code: 0");
+    t(0x0ff00, "exit code: 255");
+
+    // On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED.  Probably *BSD is similar.
+    //   https://github.com/rust-lang/rust/pull/82749#issuecomment-790525956
+    // The purpose of this test is to test our string formatting, not our understanding of the wait
+    // status magic numbers.  So restrict these to Linux.
+    if cfg!(target_os = "linux") {
+        t(0x0137f, "stopped (not terminated) by signal: 19");
+        t(0x0ffff, "continued (WIFCONTINUED)");
+    }
+
+    // Testing "unrecognised wait status" is hard because the wait.h macros typically
+    // assume that the value came from wait and isn't mad.  With the glibc I have here
+    // this works:
+    if cfg!(all(target_os = "linux", target_env = "gnu")) {
+        t(0x000ff, "unrecognised wait status: 255 0xff");
+    }
+}
diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs
index d8474205352..d7bba50c76a 100644
--- a/library/std/src/sys/unix/stack_overflow.rs
+++ b/library/std/src/sys/unix/stack_overflow.rs
@@ -34,7 +34,7 @@ impl Drop for Handler {
     target_os = "freebsd",
     target_os = "solaris",
     target_os = "illumos",
-    all(target_os = "netbsd", not(target_vendor = "rumprun")),
+    target_os = "netbsd",
     target_os = "openbsd"
 ))]
 mod imp {
@@ -218,7 +218,7 @@ mod imp {
     target_os = "freebsd",
     target_os = "solaris",
     target_os = "illumos",
-    all(target_os = "netbsd", not(target_vendor = "rumprun")),
+    target_os = "netbsd",
     target_os = "openbsd",
 )))]
 mod imp {
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index cda17eb4bd2..40c96307514 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -202,7 +202,7 @@ impl Drop for Thread {
     not(target_os = "linux"),
     not(target_os = "freebsd"),
     not(target_os = "macos"),
-    not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
+    not(target_os = "netbsd"),
     not(target_os = "openbsd"),
     not(target_os = "solaris")
 ))]
@@ -222,7 +222,7 @@ pub mod guard {
     target_os = "linux",
     target_os = "freebsd",
     target_os = "macos",
-    all(target_os = "netbsd", not(target_vendor = "rumprun")),
+    target_os = "netbsd",
     target_os = "openbsd",
     target_os = "solaris"
 ))]
diff --git a/library/std/src/sys/wasi/ext/fs.rs b/library/std/src/sys/wasi/ext/fs.rs
index a8da003d550..6472642f034 100644
--- a/library/std/src/sys/wasi/ext/fs.rs
+++ b/library/std/src/sys/wasi/ext/fs.rs
@@ -3,11 +3,14 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 #![unstable(feature = "wasi_ext", issue = "none")]
 
+use crate::ffi::OsStr;
 use crate::fs::{self, File, Metadata, OpenOptions};
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::path::{Path, PathBuf};
-use crate::sys::fs::osstr2str;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+// Used for `File::read` on intra-doc links
+#[allow(unused_imports)]
+use io::{Read, Write};
 
 /// WASI-specific extensions to [`File`].
 pub trait FileExt {
@@ -54,11 +57,11 @@ pub trait FileExt {
     /// # Errors
     ///
     /// If this function encounters an error of the kind
-    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
     /// will continue.
     ///
     /// If this function encounters an "end of file" before completely filling
-    /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+    /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
     /// The contents of `buf` are unspecified in this case.
     ///
     /// If any other read error is encountered then this function immediately
@@ -131,16 +134,16 @@ pub trait FileExt {
     /// The current file cursor is not affected by this function.
     ///
     /// This method will continuously call [`write_at`] until there is no more data
-    /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+    /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
     /// returned. This method will not return until the entire buffer has been
     /// successfully written or such an error occurs. The first error that is
-    /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+    /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
     /// returned.
     ///
     /// # Errors
     ///
     /// This function will return the first error of
-    /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
+    /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
     ///
     /// [`write_at`]: FileExt::write_at
     #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
@@ -397,6 +400,8 @@ pub trait MetadataExt {
     fn ino(&self) -> u64;
     /// Returns the `st_nlink` field of the internal `filestat_t`
     fn nlink(&self) -> u64;
+    /// Returns the `st_size` field of the internal `filestat_t`
+    fn size(&self) -> u64;
     /// Returns the `st_atim` field of the internal `filestat_t`
     fn atim(&self) -> u64;
     /// Returns the `st_mtim` field of the internal `filestat_t`
@@ -415,6 +420,9 @@ impl MetadataExt for fs::Metadata {
     fn nlink(&self) -> u64 {
         self.as_inner().as_wasi().nlink
     }
+    fn size(&self) -> u64 {
+        self.as_inner().as_wasi().size
+    }
     fn atim(&self) -> u64 {
         self.as_inner().as_wasi().atim
     }
@@ -426,7 +434,7 @@ impl MetadataExt for fs::Metadata {
     }
 }
 
-/// WASI-specific extensions for [`FileType`].
+/// WASI-specific extensions for [`fs::FileType`].
 ///
 /// Adds support for special WASI file types such as block/character devices,
 /// pipes, and sockets.
@@ -517,8 +525,12 @@ pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
 
 /// Create a symbolic link.
 ///
-/// This is a convenience API similar to [`std::os::unix::fs::symlink`] and
-/// [`std::os::windows::fs::symlink_file`] and [`symlink_dir`](std::os::windows::fs::symlink_dir).
+/// This is a convenience API similar to `std::os::unix::fs::symlink` and
+/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`.
 pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> {
     crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
 }
+
+fn osstr2str(f: &OsStr) -> io::Result<&str> {
+    f.to_str().ok_or_else(|| io::Error::new(io::ErrorKind::Other, "input must be utf-8"))
+}
diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs
index 81413f39dc1..3c480aa8e19 100644
--- a/library/std/src/sys/wasi/ext/io.rs
+++ b/library/std/src/sys/wasi/ext/io.rs
@@ -145,36 +145,36 @@ impl IntoRawFd for fs::File {
 
 impl AsRawFd for io::Stdin {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stdin.as_raw_fd()
+        libc::STDIN_FILENO as RawFd
     }
 }
 
 impl AsRawFd for io::Stdout {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stdout.as_raw_fd()
+        libc::STDOUT_FILENO as RawFd
     }
 }
 
 impl AsRawFd for io::Stderr {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stderr.as_raw_fd()
+        libc::STDERR_FILENO as RawFd
     }
 }
 
 impl<'a> AsRawFd for io::StdinLock<'a> {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stdin.as_raw_fd()
+        libc::STDIN_FILENO as RawFd
     }
 }
 
 impl<'a> AsRawFd for io::StdoutLock<'a> {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stdout.as_raw_fd()
+        libc::STDOUT_FILENO as RawFd
     }
 }
 
 impl<'a> AsRawFd for io::StderrLock<'a> {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stderr.as_raw_fd()
+        libc::STDERR_FILENO as RawFd
     }
 }
diff --git a/library/std/src/sys/wasi/ext/mod.rs b/library/std/src/sys/wasi/ext/mod.rs
index 1cda30edcad..b08402f0776 100644
--- a/library/std/src/sys/wasi/ext/mod.rs
+++ b/library/std/src/sys/wasi/ext/mod.rs
@@ -1,4 +1,32 @@
+//! Platform-specific extensions to `std` for WASI.
+//!
+//! Provides access to platform-level information on WASI, and exposes
+//! WASI-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings (`OsStr`,
+//! `OsString`), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::wasi::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//!     let f = File::create("foo.txt")?;
+//!     let fd = f.as_raw_fd();
+//!
+//!     // use fd with native WASI bindings
+//!
+//!     Ok(())
+//! }
+//! ```
+
 #![deny(unsafe_op_in_unsafe_fn)]
+#![doc(cfg(target_os = "wasi"))]
 
 pub mod ffi;
 pub mod fs;
@@ -11,14 +39,14 @@ pub mod io;
 pub mod prelude {
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::sys::ext::ffi::{OsStrExt, OsStringExt};
+    pub use super::ffi::{OsStrExt, OsStringExt};
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::sys::ext::fs::FileTypeExt;
+    pub use super::fs::FileTypeExt;
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::sys::ext::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
+    pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
     #[doc(no_inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::sys::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 }
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 4134ef67671..63c22136273 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -1,5 +1,6 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
+use super::fd::WasiFd;
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
 use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
@@ -9,7 +10,6 @@ use crate::os::wasi::ffi::{OsStrExt, OsStringExt};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::sync::Arc;
-use crate::sys::fd::WasiFd;
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
 use crate::sys_common::FromInner;
@@ -557,12 +557,8 @@ pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
 pub fn link(original: &Path, link: &Path) -> io::Result<()> {
     let (original, original_file) = open_parent(original)?;
     let (link, link_file) = open_parent(link)?;
-    original.link(
-        wasi::LOOKUPFLAGS_SYMLINK_FOLLOW,
-        osstr2str(original_file.as_ref())?,
-        &link,
-        osstr2str(link_file.as_ref())?,
-    )
+    // Pass 0 as the flags argument, meaning don't follow symlinks.
+    original.link(0, osstr2str(original_file.as_ref())?, &link, osstr2str(link_file.as_ref())?)
 }
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
@@ -654,13 +650,11 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
                 );
                 return Err(io::Error::new(io::ErrorKind::Other, msg));
             }
-            let len = CStr::from_ptr(buf.as_ptr().cast()).to_bytes().len();
-            buf.set_len(len);
-            buf.shrink_to_fit();
+            let relative = CStr::from_ptr(relative_path).to_bytes().to_vec();
 
             return Ok((
                 ManuallyDrop::new(WasiFd::from_raw(fd as u32)),
-                PathBuf::from(OsString::from_vec(buf)),
+                PathBuf::from(OsString::from_vec(relative)),
             ));
         }
     }
diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs
index 8fd4bb76d85..3f294e7df41 100644
--- a/library/std/src/sys/wasi/net.rs
+++ b/library/std/src/sys/wasi/net.rs
@@ -1,10 +1,10 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
+use super::fd::WasiFd;
 use crate::convert::TryFrom;
 use crate::fmt;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-use crate::sys::fd::WasiFd;
 use crate::sys::{unsupported, Void};
 use crate::sys_common::FromInner;
 use crate::time::Duration;
diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs
index d82f6f41186..209d5b996e5 100644
--- a/library/std/src/sys/wasi/stdio.rs
+++ b/library/std/src/sys/wasi/stdio.rs
@@ -1,8 +1,8 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
+use super::fd::WasiFd;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
-use crate::sys::fd::WasiFd;
 
 pub struct Stdin;
 pub struct Stdout;
diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs
index 3d680a7f2d9..67412e16779 100644
--- a/library/std/src/sys/windows/ext/process.rs
+++ b/library/std/src/sys/windows/ext/process.rs
@@ -105,6 +105,22 @@ pub trait CommandExt: Sealed {
     /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
     #[stable(feature = "windows_process_extensions", since = "1.16.0")]
     fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
+
+    /// Forces all arguments to be wrapped in quote (`"`) characters.
+    ///
+    /// This is useful for passing arguments to [MSYS2/Cygwin][1] based
+    /// executables: these programs will expand unquoted arguments containing
+    /// wildcard characters (`?` and `*`) by searching for any file paths
+    /// matching the wildcard pattern.
+    ///
+    /// Adding quotes has no effect when passing arguments to programs
+    /// that use [msvcrt][2]. This includes programs built with both
+    /// MinGW and MSVC.
+    ///
+    /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
+    /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
+    #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
+    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
 }
 
 #[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -113,4 +129,9 @@ impl CommandExt for process::Command {
         self.as_inner_mut().creation_flags(flags);
         self
     }
+
+    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
+        self.as_inner_mut().force_quotes(enabled);
+        self
+    }
 }
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index c10c0df4a3a..b8f512f6a23 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -8,7 +8,9 @@ mod tests;
 pub const MAIN_SEP_STR: &str = "\\";
 pub const MAIN_SEP: char = '\\';
 
-// Safety: `bytes` must be a valid wtf8 encoded slice
+/// # Safety
+///
+/// `bytes` must be a valid wtf8 encoded slice
 #[inline]
 unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr {
     // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8,
@@ -130,7 +132,7 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
             // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index.
             let path = &path.bytes()[separator_end..];
 
-            // Safety: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\')
+            // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\')
             // is encoded in a single byte, therefore `bytes[separator_start]` and
             // `bytes[separator_end]` must be code point boundaries and thus
             // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices.
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 243065b94b1..83d37795ee5 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -78,6 +78,7 @@ pub struct Command {
     stdin: Option<Stdio>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
+    force_quotes_enabled: bool,
 }
 
 pub enum Stdio {
@@ -109,6 +110,7 @@ impl Command {
             stdin: None,
             stdout: None,
             stderr: None,
+            force_quotes_enabled: false,
         }
     }
 
@@ -134,6 +136,10 @@ impl Command {
         self.flags = flags;
     }
 
+    pub fn force_quotes(&mut self, enabled: bool) {
+        self.force_quotes_enabled = enabled;
+    }
+
     pub fn get_program(&self) -> &OsStr {
         &self.program
     }
@@ -181,7 +187,7 @@ impl Command {
         si.dwFlags = c::STARTF_USESTDHANDLES;
 
         let program = program.as_ref().unwrap_or(&self.program);
-        let mut cmd_str = make_command_line(program, &self.args)?;
+        let mut cmd_str = make_command_line(program, &self.args, self.force_quotes_enabled)?;
         cmd_str.push(0); // add null terminator
 
         // stolen from the libuv code.
@@ -467,7 +473,7 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
 
 // Produces a wide string *without terminating null*; returns an error if
 // `prog` or any of the `args` contain a nul.
-fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
+fn make_command_line(prog: &OsStr, args: &[OsString], force_quotes: bool) -> io::Result<Vec<u16>> {
     // Encode the command and arguments in a command line string such
     // that the spawned process may recover them using CommandLineToArgvW.
     let mut cmd: Vec<u16> = Vec::new();
@@ -476,7 +482,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
     append_arg(&mut cmd, prog, true)?;
     for arg in args {
         cmd.push(' ' as u16);
-        append_arg(&mut cmd, arg, false)?;
+        append_arg(&mut cmd, arg, force_quotes)?;
     }
     return Ok(cmd);
 
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
index 81627ad139b..8830ae049c6 100644
--- a/library/std/src/sys/windows/process/tests.rs
+++ b/library/std/src/sys/windows/process/tests.rs
@@ -3,29 +3,41 @@ use crate::ffi::{OsStr, OsString};
 
 #[test]
 fn test_make_command_line() {
-    fn test_wrapper(prog: &str, args: &[&str]) -> String {
+    fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
         let command_line = &make_command_line(
             OsStr::new(prog),
             &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
+            force_quotes,
         )
         .unwrap();
         String::from_utf16(command_line).unwrap()
     }
 
-    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc");
+    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
 
     assert_eq!(
-        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
         "\"C:\\Program Files\\blah\\blah.exe\" aaa"
     );
     assert_eq!(
-        test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
+        "\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
+    );
+    assert_eq!(
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
+        "\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
+    );
+    assert_eq!(
+        test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
         "\"C:\\Program Files\\test\" aa\\\"bb"
     );
-    assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\"");
-    assert_eq!(test_wrapper("echo", &["\" \\\" \\", "\\"]), "\"echo\" \"\\\" \\\\\\\" \\\\\" \\");
+    assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
+    assert_eq!(
+        test_wrapper("echo", &["\" \\\" \\", "\\"], false),
+        "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
+    );
     assert_eq!(
-        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
+        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
         "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
     );
 }
diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs
index 41e8ad77294..3705d641a1b 100644
--- a/library/std/src/sys_common/rwlock.rs
+++ b/library/std/src/sys_common/rwlock.rs
@@ -86,62 +86,3 @@ impl RWLock {
         self.0.destroy()
     }
 }
-
-// the cfg annotations only exist due to dead code warnings. the code itself is portable
-#[cfg(unix)]
-pub struct StaticRWLock(RWLock);
-
-#[cfg(unix)]
-impl StaticRWLock {
-    pub const fn new() -> StaticRWLock {
-        StaticRWLock(RWLock::new())
-    }
-
-    /// Acquires shared access to the underlying lock, blocking the current
-    /// thread to do so.
-    ///
-    /// The lock is automatically unlocked when the returned guard is dropped.
-    #[inline]
-    pub fn read_with_guard(&'static self) -> RWLockReadGuard {
-        // Safety: All methods require static references, therefore self
-        // cannot be moved between invocations.
-        unsafe {
-            self.0.read();
-        }
-        RWLockReadGuard(&self.0)
-    }
-
-    /// Acquires write access to the underlying lock, blocking the current thread
-    /// to do so.
-    ///
-    /// The lock is automatically unlocked when the returned guard is dropped.
-    #[inline]
-    pub fn write_with_guard(&'static self) -> RWLockWriteGuard {
-        // Safety: All methods require static references, therefore self
-        // cannot be moved between invocations.
-        unsafe {
-            self.0.write();
-        }
-        RWLockWriteGuard(&self.0)
-    }
-}
-
-#[cfg(unix)]
-pub struct RWLockReadGuard(&'static RWLock);
-
-#[cfg(unix)]
-impl Drop for RWLockReadGuard {
-    fn drop(&mut self) {
-        unsafe { self.0.read_unlock() }
-    }
-}
-
-#[cfg(unix)]
-pub struct RWLockWriteGuard(&'static RWLock);
-
-#[cfg(unix)]
-impl Drop for RWLockWriteGuard {
-    fn drop(&mut self) {
-        unsafe { self.0.write_unlock() }
-    }
-}
diff --git a/library/std/src/sys_common/thread_local_dtor.rs b/library/std/src/sys_common/thread_local_dtor.rs
index 6f5ebf4a271..f9971fb6f21 100644
--- a/library/std/src/sys_common/thread_local_dtor.rs
+++ b/library/std/src/sys_common/thread_local_dtor.rs
@@ -1,6 +1,6 @@
 //! Thread-local destructor
 //!
-//! Besides thread-local "keys" (pointer-sized non-adressable thread-local store
+//! Besides thread-local "keys" (pointer-sized non-addressable thread-local store
 //! with an associated destructor), many platforms also provide thread-local
 //! destructors that are not associated with any particular data. These are
 //! often more efficient.