diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index 17d2b3386f5fe..1dcc4d147acf2 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -9,7 +9,7 @@ use rustc_hir_pretty as pprust_hir;
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_mir::util::{write_mir_graphviz, write_mir_pretty};
-use rustc_session::config::{Input, PpMode, PpSourceMode};
+use rustc_session::config::{Input, PpHirMode, PpMode, PpSourceMode};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::FileName;
@@ -42,43 +42,41 @@ where
     F: FnOnce(&dyn PrinterSupport) -> A,
 {
     match *ppmode {
-        PpmNormal | PpmEveryBodyLoops | PpmExpanded => {
+        Normal | EveryBodyLoops | Expanded => {
             let annotation = NoAnn { sess, tcx };
             f(&annotation)
         }
 
-        PpmIdentified | PpmExpandedIdentified => {
+        Identified | ExpandedIdentified => {
             let annotation = IdentifiedAnnotation { sess, tcx };
             f(&annotation)
         }
-        PpmExpandedHygiene => {
+        ExpandedHygiene => {
             let annotation = HygieneAnnotation { sess };
             f(&annotation)
         }
-        _ => panic!("Should use call_with_pp_support_hir"),
     }
 }
-fn call_with_pp_support_hir<A, F>(ppmode: &PpSourceMode, tcx: TyCtxt<'_>, f: F) -> A
+fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A
 where
     F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate<'_>) -> A,
 {
     match *ppmode {
-        PpmNormal => {
+        PpHirMode::Normal => {
             let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) };
             f(&annotation, tcx.hir().krate())
         }
 
-        PpmIdentified => {
+        PpHirMode::Identified => {
             let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) };
             f(&annotation, tcx.hir().krate())
         }
-        PpmTyped => {
+        PpHirMode::Typed => {
             abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess);
 
             let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) };
             tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().krate()))
         }
-        _ => panic!("Should use call_with_pp_support"),
     }
 }
 
@@ -393,16 +391,13 @@ pub fn print_after_parsing(
 ) {
     let (src, src_name) = get_source(input, sess);
 
-    let mut out = String::new();
-
-    if let PpmSource(s) = ppm {
+    let out = if let Source(s) = ppm {
         // Silently ignores an identified node.
-        let out = &mut out;
         call_with_pp_support(&s, sess, None, move |annotation| {
             debug!("pretty printing source code {:?}", s);
             let sess = annotation.sess();
             let parse = &sess.parse_sess;
-            *out = pprust::print_crate(
+            pprust::print_crate(
                 sess.source_map(),
                 krate,
                 src_name,
@@ -413,7 +408,7 @@ pub fn print_after_parsing(
             )
         })
     } else {
-        unreachable!();
+        unreachable!()
     };
 
     write_or_print(&out, ofile);
@@ -433,17 +428,14 @@ pub fn print_after_hir_lowering<'tcx>(
 
     let (src, src_name) = get_source(input, tcx.sess);
 
-    let mut out = String::new();
-
-    match ppm {
-        PpmSource(s) => {
+    let out = match ppm {
+        Source(s) => {
             // Silently ignores an identified node.
-            let out = &mut out;
             call_with_pp_support(&s, tcx.sess, Some(tcx), move |annotation| {
                 debug!("pretty printing source code {:?}", s);
                 let sess = annotation.sess();
                 let parse = &sess.parse_sess;
-                *out = pprust::print_crate(
+                pprust::print_crate(
                     sess.source_map(),
                     krate,
                     src_name,
@@ -455,26 +447,20 @@ pub fn print_after_hir_lowering<'tcx>(
             })
         }
 
-        PpmHir(s) => {
-            let out = &mut out;
-            call_with_pp_support_hir(&s, tcx, move |annotation, krate| {
-                debug!("pretty printing source code {:?}", s);
-                let sess = annotation.sess();
-                let sm = sess.source_map();
-                *out = pprust_hir::print_crate(sm, krate, src_name, src, annotation.pp_ann())
-            })
-        }
+        Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, krate| {
+            debug!("pretty printing HIR {:?}", s);
+            let sess = annotation.sess();
+            let sm = sess.source_map();
+            pprust_hir::print_crate(sm, krate, src_name, src, annotation.pp_ann())
+        }),
 
-        PpmHirTree(s) => {
-            let out = &mut out;
-            call_with_pp_support_hir(&s, tcx, move |_annotation, krate| {
-                debug!("pretty printing source code {:?}", s);
-                *out = format!("{:#?}", krate);
-            });
-        }
+        HirTree => call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, krate| {
+            debug!("pretty printing HIR tree");
+            format!("{:#?}", krate)
+        }),
 
         _ => unreachable!(),
-    }
+    };
 
     write_or_print(&out, ofile);
 }
@@ -493,14 +479,10 @@ fn print_with_analysis(
     tcx.analysis(LOCAL_CRATE)?;
 
     match ppm {
-        PpmMir | PpmMirCFG => match ppm {
-            PpmMir => write_mir_pretty(tcx, None, &mut out),
-            PpmMirCFG => write_mir_graphviz(tcx, None, &mut out),
-            _ => unreachable!(),
-        },
+        Mir => write_mir_pretty(tcx, None, &mut out).unwrap(),
+        MirCFG => write_mir_graphviz(tcx, None, &mut out).unwrap(),
         _ => unreachable!(),
     }
-    .unwrap();
 
     let out = std::str::from_utf8(&out).unwrap();
     write_or_print(out, ofile);
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 6358855ac322e..5217066bbefde 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -350,7 +350,7 @@ fn configure_and_expand_inner<'a>(
         rustc_builtin_macros::test_harness::inject(&sess, &mut resolver, &mut krate)
     });
 
-    if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty {
+    if let Some(PpMode::Source(PpSourceMode::EveryBodyLoops)) = sess.opts.pretty {
         tracing::debug!("replacing bodies with loop {{}}");
         util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
     }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 81d6c3bbdbba2..38da52b88f369 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2057,40 +2057,21 @@ fn parse_pretty(
     debugging_opts: &DebuggingOptions,
     efmt: ErrorOutputType,
 ) -> Option<PpMode> {
-    let pretty = if debugging_opts.unstable_options {
-        matches.opt_default("pretty", "normal").map(|a| {
-            // stable pretty-print variants only
-            parse_pretty_inner(efmt, &a, false)
-        })
-    } else {
-        None
-    };
-
-    return if pretty.is_none() {
-        debugging_opts.unpretty.as_ref().map(|a| {
-            // extended with unstable pretty-print variants
-            parse_pretty_inner(efmt, &a, true)
-        })
-    } else {
-        pretty
-    };
-
     fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
         use PpMode::*;
-        use PpSourceMode::*;
         let first = match (name, extended) {
-            ("normal", _) => PpmSource(PpmNormal),
-            ("identified", _) => PpmSource(PpmIdentified),
-            ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
-            ("expanded", _) => PpmSource(PpmExpanded),
-            ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
-            ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
-            ("hir", true) => PpmHir(PpmNormal),
-            ("hir,identified", true) => PpmHir(PpmIdentified),
-            ("hir,typed", true) => PpmHir(PpmTyped),
-            ("hir-tree", true) => PpmHirTree(PpmNormal),
-            ("mir", true) => PpmMir,
-            ("mir-cfg", true) => PpmMirCFG,
+            ("normal", _) => Source(PpSourceMode::Normal),
+            ("identified", _) => Source(PpSourceMode::Identified),
+            ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
+            ("expanded", _) => Source(PpSourceMode::Expanded),
+            ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
+            ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
+            ("hir", true) => Hir(PpHirMode::Normal),
+            ("hir,identified", true) => Hir(PpHirMode::Identified),
+            ("hir,typed", true) => Hir(PpHirMode::Typed),
+            ("hir-tree", true) => HirTree,
+            ("mir", true) => Mir,
+            ("mir-cfg", true) => MirCFG,
             _ => {
                 if extended {
                     early_error(
@@ -2119,6 +2100,18 @@ fn parse_pretty(
         tracing::debug!("got unpretty option: {:?}", first);
         first
     }
+
+    if debugging_opts.unstable_options {
+        if let Some(a) = matches.opt_default("pretty", "normal") {
+            // stable pretty-print variants only
+            return Some(parse_pretty_inner(efmt, &a, false));
+        }
+    }
+
+    debugging_opts.unpretty.as_ref().map(|a| {
+        // extended with unstable pretty-print variants
+        parse_pretty_inner(efmt, &a, true)
+    })
 }
 
 pub fn make_crate_type_option() -> RustcOptGroup {
@@ -2226,22 +2219,43 @@ impl fmt::Display for CrateType {
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum PpSourceMode {
-    PpmNormal,
-    PpmEveryBodyLoops,
-    PpmExpanded,
-    PpmIdentified,
-    PpmExpandedIdentified,
-    PpmExpandedHygiene,
-    PpmTyped,
+    /// `--pretty=normal`
+    Normal,
+    /// `-Zunpretty=everybody_loops`
+    EveryBodyLoops,
+    /// `--pretty=expanded`
+    Expanded,
+    /// `--pretty=identified`
+    Identified,
+    /// `--pretty=expanded,identified`
+    ExpandedIdentified,
+    /// `--pretty=expanded,hygiene`
+    ExpandedHygiene,
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum PpHirMode {
+    /// `-Zunpretty=hir`
+    Normal,
+    /// `-Zunpretty=hir,identified`
+    Identified,
+    /// `-Zunpretty=hir,typed`
+    Typed,
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum PpMode {
-    PpmSource(PpSourceMode),
-    PpmHir(PpSourceMode),
-    PpmHirTree(PpSourceMode),
-    PpmMir,
-    PpmMirCFG,
+    /// Options that print the source code, i.e.
+    /// `--pretty` and `-Zunpretty=everybody_loops`
+    Source(PpSourceMode),
+    /// Options that print the HIR, i.e. `-Zunpretty=hir`
+    Hir(PpHirMode),
+    /// `-Zunpretty=hir-tree`
+    HirTree,
+    /// `-Zunpretty=mir`
+    Mir,
+    /// `-Zunpretty=mir-cfg`
+    MirCFG,
 }
 
 impl PpMode {
@@ -2249,22 +2263,19 @@ impl PpMode {
         use PpMode::*;
         use PpSourceMode::*;
         match *self {
-            PpmSource(PpmNormal | PpmIdentified) => false,
+            Source(Normal | Identified) => false,
 
-            PpmSource(
-                PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
-            )
-            | PpmHir(_)
-            | PpmHirTree(_)
-            | PpmMir
-            | PpmMirCFG => true,
-            PpmSource(PpmTyped) => panic!("invalid state"),
+            Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
+            | Hir(_)
+            | HirTree
+            | Mir
+            | MirCFG => true,
         }
     }
 
     pub fn needs_analysis(&self) -> bool {
         use PpMode::*;
-        matches!(*self, PpmMir | PpmMirCFG)
+        matches!(*self, Mir | MirCFG)
     }
 }
 
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 158c214759db2..52cdbde0e9816 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -159,21 +159,21 @@ pub struct Pick<'tcx> {
     pub kind: PickKind<'tcx>,
     pub import_ids: SmallVec<[LocalDefId; 1]>,
 
-    // Indicates that the source expression should be autoderef'd N times
-    //
-    // A = expr | *expr | **expr | ...
+    /// Indicates that the source expression should be autoderef'd N times
+    ///
+    ///     A = expr | *expr | **expr | ...
     pub autoderefs: usize,
 
-    // Indicates that an autoref is applied after the optional autoderefs
-    //
-    // B = A | &A | &mut A
+    /// Indicates that an autoref is applied after the optional autoderefs
+    ///
+    ///     B = A | &A | &mut A
     pub autoref: Option<hir::Mutability>,
 
-    // Indicates that the source expression should be "unsized" to a
-    // target type. This should probably eventually go away in favor
-    // of just coercing method receivers.
-    //
-    // C = B | unsize(B)
+    /// Indicates that the source expression should be "unsized" to a
+    /// target type. This should probably eventually go away in favor
+    /// of just coercing method receivers.
+    ///
+    ///     C = B | unsize(B)
     pub unsize: Option<Ty<'tcx>>,
 }
 
@@ -1090,19 +1090,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             .next()
     }
 
+    /// For each type `T` in the step list, this attempts to find a method where
+    /// the (transformed) self type is exactly `T`. We do however do one
+    /// transformation on the adjustment: if we are passing a region pointer in,
+    /// we will potentially *reborrow* it to a shorter lifetime. This allows us
+    /// to transparently pass `&mut` pointers, in particular, without consuming
+    /// them for their entire lifetime.
     fn pick_by_value_method(
         &mut self,
         step: &CandidateStep<'tcx>,
         self_ty: Ty<'tcx>,
     ) -> Option<PickResult<'tcx>> {
-        //! For each type `T` in the step list, this attempts to find a
-        //! method where the (transformed) self type is exactly `T`. We
-        //! do however do one transformation on the adjustment: if we
-        //! are passing a region pointer in, we will potentially
-        //! *reborrow* it to a shorter lifetime. This allows us to
-        //! transparently pass `&mut` pointers, in particular, without
-        //! consuming them for their entire lifetime.
-
         if step.unsize {
             return None;
         }
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 41ea2760ec570..9a54921f07b49 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1,4 +1,4 @@
-#[doc(include = "panic.md")]
+#[doc = include_str!("panic.md")]
 #[macro_export]
 #[rustc_builtin_macro = "core_panic"]
 #[allow_internal_unstable(edition_panic)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 588bffb57c9c5..32aca8c83924d 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -264,7 +264,6 @@
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
 #![feature(extended_key_value_attributes)]
-#![feature(external_doc)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index c0750f8c0d1b0..b729349cf530f 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -4,7 +4,7 @@
 //! library. Each macro is available for use when linking against the standard
 //! library.
 
-#[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 f61e402e37027..fad5886def700 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -22,6 +22,9 @@ pub use crate::sys::windows_ext as windows;
 #[doc(cfg(target_os = "linux"))]
 pub mod linux;
 
+#[cfg(doc)]
+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.
 
 #[cfg(not(doc))]
diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs
index 22c98d7ade992..50464a050c706 100644
--- a/library/std/src/os/raw/mod.rs
+++ b/library/std/src/os/raw/mod.rs
@@ -18,7 +18,7 @@ macro_rules! type_alias_no_nz {
       $Docfile:tt, $Alias:ident = $Real:ty;
       $( $Cfg:tt )*
     } => {
-        #[doc(include = $Docfile)]
+        #[doc = include_str!($Docfile)]
         $( $Cfg )*
         #[stable(feature = "raw_os", since = "1.1.0")]
         pub type $Alias = $Real;
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index d48d9cb0efce0..d3f53801d2d0f 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,25 @@ 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 = "rust1", since = "1.0.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"]
+        pub mod wasi_ext;
+    }
+}
diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs
index 7559c1f1d9e29..88a27f27f6628 100644
--- a/library/std/src/sys/unix/ext/process.rs
+++ b/library/std/src/sys/unix/ext/process.rs
@@ -172,6 +172,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)
     }
 
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index a96d4aa6a4555..b9dcc4e4b9e38 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/wasi/ext/fs.rs b/library/std/src/sys/wasi/ext/fs.rs
index a8da003d550ac..6472642f03499 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 81413f39dc1cd..d0edfa9f35f90 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
     }
 }
 
 impl AsRawFd for io::Stdout {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stdout.as_raw_fd()
+        libc::STDOUT_FILENO
     }
 }
 
 impl AsRawFd for io::Stderr {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stderr.as_raw_fd()
+        libc::STDERR_FILENO
     }
 }
 
 impl<'a> AsRawFd for io::StdinLock<'a> {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stdin.as_raw_fd()
+        libc::STDIN_FILENO
     }
 }
 
 impl<'a> AsRawFd for io::StdoutLock<'a> {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stdout.as_raw_fd()
+        libc::STDOUT_FILENO
     }
 }
 
 impl<'a> AsRawFd for io::StderrLock<'a> {
     fn as_raw_fd(&self) -> RawFd {
-        sys::stdio::Stderr.as_raw_fd()
+        libc::STDERR_FILENO
     }
 }
diff --git a/library/std/src/sys/wasi/ext/mod.rs b/library/std/src/sys/wasi/ext/mod.rs
index 1cda30edcad0a..8a83b24700391 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;
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 4f7a101d2acbd..29a267053b47d 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -286,8 +286,8 @@ achieve that will result in false positive reports.
 
 Detecting the use of uninitialized memory. The `-Zbuild-std` flag rebuilds and
 instruments the standard library, and is strictly necessary for the correct
-operation of the tool. The `-Zsanitizer-track-origins` enables tracking of the
-origins of uninitialized memory:
+operation of the tool. The `-Zsanitizer-memory-track-origins` enables tracking
+of the origins of uninitialized memory:
 
 ```rust
 use std::mem::MaybeUninit;
diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md
index d44c841d48c66..22780804610b6 100644
--- a/src/doc/unstable-book/src/language-features/lang-items.md
+++ b/src/doc/unstable-book/src/language-features/lang-items.md
@@ -66,7 +66,7 @@ Other features provided by lang items include:
   marked with lang items; those specific four are `eq`, `ord`,
   `deref`, and `add` respectively.
 - stack unwinding and general failure; the `eh_personality`,
-  `panic` and `panic_bounds_checks` lang items.
+  `panic` and `panic_bounds_check` lang items.
 - the traits in `std::marker` used to indicate types of
   various kinds; lang items `send`, `sync` and `copy`.
 - the marker types and variance indicators found in
diff --git a/src/librustdoc/html/static/normalize.css b/src/librustdoc/html/static/normalize.css
index 0e0426279183f..da9a75e3e85e9 100644
--- a/src/librustdoc/html/static/normalize.css
+++ b/src/librustdoc/html/static/normalize.css
@@ -1,2 +1,2 @@
 /* ignore-tidy-linelength */
-/*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index c99e1ecac739c..6d9e3d0b9eab0 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -134,15 +134,20 @@ impl TryFrom<ResolveRes> for Res {
     }
 }
 
-#[derive(Debug)]
 /// A link failed to resolve.
+#[derive(Debug)]
 enum ResolutionFailure<'a> {
     /// This resolved, but with the wrong namespace.
-    ///
-    /// `Namespace` is the namespace specified with a disambiguator
-    /// (as opposed to the actual namespace of the `Res`).
-    WrongNamespace(Res, /* disambiguated */ Namespace),
-    /// The link failed to resolve. `resolution_failure` should look to see if there's
+    WrongNamespace {
+        /// What the link resolved to.
+        res: Res,
+        /// The expected namespace for the resolution, determined from the link's disambiguator.
+        ///
+        /// E.g., for `[fn@Result]` this is [`Namespace::ValueNS`],
+        /// even though `Result`'s actual namespace is [`Namespace::TypeNS`].
+        expected_ns: Namespace,
+    },
+    /// The link failed to resolve. [`resolution_failure`] should look to see if there's
     /// a more helpful error that can be given.
     NotResolved {
         /// The scope the link was resolved in.
@@ -157,12 +162,11 @@ enum ResolutionFailure<'a> {
         unresolved: Cow<'a, str>,
     },
     /// This happens when rustdoc can't determine the parent scope for an item.
-    ///
     /// It is always a bug in rustdoc.
     NoParentItem,
     /// This link has malformed generic parameters; e.g., the angle brackets are unbalanced.
     MalformedGenerics(MalformedGenerics),
-    /// Used to communicate that this should be ignored, but shouldn't be reported to the user
+    /// Used to communicate that this should be ignored, but shouldn't be reported to the user.
     ///
     /// This happens when there is no disambiguator and one of the namespaces
     /// failed to resolve.
@@ -216,7 +220,7 @@ impl ResolutionFailure<'a> {
     /// Returns the full resolution of the link, if present.
     fn full_res(&self) -> Option<Res> {
         match self {
-            Self::WrongNamespace(res, _) => Some(*res),
+            Self::WrongNamespace { res, expected_ns: _ } => Some(*res),
             _ => None,
         }
     }
@@ -1308,20 +1312,20 @@ impl LinkCollector<'_, '_> {
         let extra_fragment = &key.extra_fragment;
 
         match disambiguator.map(Disambiguator::ns) {
-            Some(ns @ (ValueNS | TypeNS)) => {
-                match self.resolve(path_str, ns, base_node, extra_fragment) {
+            Some(expected_ns @ (ValueNS | TypeNS)) => {
+                match self.resolve(path_str, expected_ns, base_node, extra_fragment) {
                     Ok(res) => Some(res),
                     Err(ErrorKind::Resolve(box mut kind)) => {
                         // We only looked in one namespace. Try to give a better error if possible.
                         if kind.full_res().is_none() {
-                            let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
+                            let other_ns = if expected_ns == ValueNS { TypeNS } else { ValueNS };
                             // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
                             // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
                             for &new_ns in &[other_ns, MacroNS] {
                                 if let Some(res) =
                                     self.check_full_res(new_ns, path_str, base_node, extra_fragment)
                                 {
-                                    kind = ResolutionFailure::WrongNamespace(res, ns);
+                                    kind = ResolutionFailure::WrongNamespace { res, expected_ns };
                                     break;
                                 }
                             }
@@ -1396,7 +1400,7 @@ impl LinkCollector<'_, '_> {
                         // Constructors are picked up in the type namespace.
                         match res {
                             Res::Def(DefKind::Ctor(..), _) => {
-                                Err(ResolutionFailure::WrongNamespace(res, TypeNS))
+                                Err(ResolutionFailure::WrongNamespace { res, expected_ns: TypeNS })
                             }
                             _ => {
                                 match (fragment, extra_fragment.clone()) {
@@ -1457,7 +1461,8 @@ impl LinkCollector<'_, '_> {
                             if let Some(res) =
                                 self.check_full_res(ns, path_str, base_node, extra_fragment)
                             {
-                                kind = ResolutionFailure::WrongNamespace(res, MacroNS);
+                                kind =
+                                    ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS };
                                 break;
                             }
                         }
@@ -1889,7 +1894,7 @@ fn resolution_failure(
                 let note = match failure {
                     ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
                     ResolutionFailure::Dummy => continue,
-                    ResolutionFailure::WrongNamespace(res, expected_ns) => {
+                    ResolutionFailure::WrongNamespace { res, expected_ns } => {
                         if let Res::Def(kind, _) = res {
                             let disambiguator = Disambiguator::Kind(kind);
                             suggest_disambiguator(
@@ -1910,7 +1915,7 @@ fn resolution_failure(
                     }
                     ResolutionFailure::NoParentItem => {
                         diag.level = rustc_errors::Level::Bug;
-                        "all intra doc links should have a parent item".to_owned()
+                        "all intra-doc links should have a parent item".to_owned()
                     }
                     ResolutionFailure::MalformedGenerics(variant) => match variant {
                         MalformedGenerics::UnbalancedAngleBrackets => {
diff --git a/src/test/ui/layout/hexagon-enum.rs b/src/test/ui/layout/hexagon-enum.rs
index 4bcfa58f7cf15..8c6c97206649c 100644
--- a/src/test/ui/layout/hexagon-enum.rs
+++ b/src/test/ui/layout/hexagon-enum.rs
@@ -1,4 +1,5 @@
 // compile-flags: --target hexagon-unknown-linux-musl
+// needs-llvm-components: hexagon
 //
 // Verify that the hexagon targets implement the repr(C) for enums correctly.
 //
diff --git a/src/test/ui/layout/hexagon-enum.stderr b/src/test/ui/layout/hexagon-enum.stderr
index 390eff6e5b957..d4676a5afb25e 100644
--- a/src/test/ui/layout/hexagon-enum.stderr
+++ b/src/test/ui/layout/hexagon-enum.stderr
@@ -81,7 +81,7 @@ error: layout_of(A) = Layout {
         raw: 1,
     },
 }
-  --> $DIR/hexagon-enum.rs:15:1
+  --> $DIR/hexagon-enum.rs:16:1
    |
 LL | enum A { Apple }
    | ^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ error: layout_of(B) = Layout {
         raw: 1,
     },
 }
-  --> $DIR/hexagon-enum.rs:19:1
+  --> $DIR/hexagon-enum.rs:20:1
    |
 LL | enum B { Banana = 255, }
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -257,7 +257,7 @@ error: layout_of(C) = Layout {
         raw: 2,
     },
 }
-  --> $DIR/hexagon-enum.rs:23:1
+  --> $DIR/hexagon-enum.rs:24:1
    |
 LL | enum C { Chaenomeles = 256, }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -345,7 +345,7 @@ error: layout_of(P) = Layout {
         raw: 4,
     },
 }
-  --> $DIR/hexagon-enum.rs:27:1
+  --> $DIR/hexagon-enum.rs:28:1
    |
 LL | enum P { Peach = 0x1000_0000isize, }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -433,7 +433,7 @@ error: layout_of(T) = Layout {
         raw: 4,
     },
 }
-  --> $DIR/hexagon-enum.rs:33:1
+  --> $DIR/hexagon-enum.rs:34:1
    |
 LL | enum T { Tangerine = TANGERINE as isize }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/treat-err-as-bug/delay_span_bug.rs b/src/test/ui/treat-err-as-bug/delay_span_bug.rs
index 67846336acaaf..d4d44049c9186 100644
--- a/src/test/ui/treat-err-as-bug/delay_span_bug.rs
+++ b/src/test/ui/treat-err-as-bug/delay_span_bug.rs
@@ -4,6 +4,7 @@
 // error-pattern: [trigger_delay_span_bug] trigger a delay span bug
 // normalize-stderr-test "note: .*\n\n" -> ""
 // normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// rustc-env:RUST_BACKTRACE=0
 
 #![feature(rustc_attrs)]
 
diff --git a/src/test/ui/treat-err-as-bug/delay_span_bug.stderr b/src/test/ui/treat-err-as-bug/delay_span_bug.stderr
index ed65b69ebcab1..c23c2b81b9767 100644
--- a/src/test/ui/treat-err-as-bug/delay_span_bug.stderr
+++ b/src/test/ui/treat-err-as-bug/delay_span_bug.stderr
@@ -1,5 +1,5 @@
 error: internal compiler error: delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]
-  --> $DIR/delay_span_bug.rs:11:1
+  --> $DIR/delay_span_bug.rs:12:1
    |
 LL | fn main() {}
    | ^^^^^^^^^
diff --git a/src/test/ui/treat-err-as-bug/err.rs b/src/test/ui/treat-err-as-bug/err.rs
index 5442d8585941b..de3e9ed6cf910 100644
--- a/src/test/ui/treat-err-as-bug/err.rs
+++ b/src/test/ui/treat-err-as-bug/err.rs
@@ -4,6 +4,7 @@
 // error-pattern: [eval_to_allocation_raw] const-evaluating + checking `C`
 // normalize-stderr-test "note: .*\n\n" -> ""
 // normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// rustc-env:RUST_BACKTRACE=0
 
 #![crate_type = "rlib"]
 
diff --git a/src/test/ui/treat-err-as-bug/err.stderr b/src/test/ui/treat-err-as-bug/err.stderr
index 61eb85c40a112..8f67571c2990e 100644
--- a/src/test/ui/treat-err-as-bug/err.stderr
+++ b/src/test/ui/treat-err-as-bug/err.stderr
@@ -1,5 +1,5 @@
 error[E0080]: could not evaluate static initializer
-  --> $DIR/err.rs:10:21
+  --> $DIR/err.rs:11:21
    |
 LL | pub static C: u32 = 0 - 1;
    |                     ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow