diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 99140bec17029..86de37820003a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,7 +26,7 @@ name: CI
       - "**"
 defaults:
   run:
-    shell: "python src/ci/exec-with-shell.py {0}"
+    shell: bash
 jobs:
   pr:
     name: PR
@@ -54,7 +54,6 @@ jobs:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
       - name: checkout the source code
         uses: actions/checkout@v1
         with:
@@ -66,77 +65,59 @@ jobs:
         if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
-        shell: bash
         env:
           EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
         if: success() && !env.SKIP_JOB
       - name: decide whether to skip this job
         run: src/ci/scripts/should-skip-this.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install awscli
         run: src/ci/scripts/install-awscli.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install WIX
         run: src/ci/scripts/install-wix.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: ensure the build happens on a partition with enough space
         run: src/ci/scripts/symlink-build-dir.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install MSYS2
         run: src/ci/scripts/install-msys2.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install MinGW
         run: src/ci/scripts/install-mingw.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install ninja
         run: src/ci/scripts/install-ninja.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: enable ipv6 on Docker
         run: src/ci/scripts/enable-docker-ipv6.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: checkout submodules
         run: src/ci/scripts/checkout-submodules.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: ensure line endings are correct
         run: src/ci/scripts/verify-line-endings.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
@@ -144,7 +125,6 @@ jobs:
         if: success() && !env.SKIP_JOB
       - name: upload artifacts to S3
         run: src/ci/scripts/upload-artifacts.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
@@ -173,7 +153,6 @@ jobs:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
       - name: checkout the source code
         uses: actions/checkout@v1
         with:
@@ -185,77 +164,59 @@ jobs:
         if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
-        shell: bash
         env:
           EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
         if: success() && !env.SKIP_JOB
       - name: decide whether to skip this job
         run: src/ci/scripts/should-skip-this.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install awscli
         run: src/ci/scripts/install-awscli.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install WIX
         run: src/ci/scripts/install-wix.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: ensure the build happens on a partition with enough space
         run: src/ci/scripts/symlink-build-dir.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install MSYS2
         run: src/ci/scripts/install-msys2.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install MinGW
         run: src/ci/scripts/install-mingw.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install ninja
         run: src/ci/scripts/install-ninja.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: enable ipv6 on Docker
         run: src/ci/scripts/enable-docker-ipv6.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: checkout submodules
         run: src/ci/scripts/checkout-submodules.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: ensure line endings are correct
         run: src/ci/scripts/verify-line-endings.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
@@ -263,7 +224,6 @@ jobs:
         if: success() && !env.SKIP_JOB
       - name: upload artifacts to S3
         run: src/ci/scripts/upload-artifacts.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
@@ -510,7 +470,6 @@ jobs:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
       - name: checkout the source code
         uses: actions/checkout@v1
         with:
@@ -522,77 +481,59 @@ jobs:
         if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
-        shell: bash
         env:
           EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
         if: success() && !env.SKIP_JOB
       - name: decide whether to skip this job
         run: src/ci/scripts/should-skip-this.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install awscli
         run: src/ci/scripts/install-awscli.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install WIX
         run: src/ci/scripts/install-wix.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: ensure the build happens on a partition with enough space
         run: src/ci/scripts/symlink-build-dir.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install MSYS2
         run: src/ci/scripts/install-msys2.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install MinGW
         run: src/ci/scripts/install-mingw.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install ninja
         run: src/ci/scripts/install-ninja.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: enable ipv6 on Docker
         run: src/ci/scripts/enable-docker-ipv6.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: checkout submodules
         run: src/ci/scripts/checkout-submodules.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: ensure line endings are correct
         run: src/ci/scripts/verify-line-endings.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
@@ -600,7 +541,6 @@ jobs:
         if: success() && !env.SKIP_JOB
       - name: upload artifacts to S3
         run: src/ci/scripts/upload-artifacts.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
@@ -655,7 +595,6 @@ jobs:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
       - name: checkout the source code
         uses: actions/checkout@v1
         with:
@@ -667,77 +606,59 @@ jobs:
         if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
-        shell: bash
         env:
           EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
         if: success() && !env.SKIP_JOB
       - name: decide whether to skip this job
         run: src/ci/scripts/should-skip-this.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install awscli
         run: src/ci/scripts/install-awscli.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install WIX
         run: src/ci/scripts/install-wix.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: ensure the build happens on a partition with enough space
         run: src/ci/scripts/symlink-build-dir.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install MSYS2
         run: src/ci/scripts/install-msys2.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install MinGW
         run: src/ci/scripts/install-mingw.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: install ninja
         run: src/ci/scripts/install-ninja.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: enable ipv6 on Docker
         run: src/ci/scripts/enable-docker-ipv6.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: checkout submodules
         run: src/ci/scripts/checkout-submodules.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: ensure line endings are correct
         run: src/ci/scripts/verify-line-endings.sh
-        shell: bash
         if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
@@ -745,7 +666,6 @@ jobs:
         if: success() && !env.SKIP_JOB
       - name: upload artifacts to S3
         run: src/ci/scripts/upload-artifacts.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
diff --git a/Cargo.lock b/Cargo.lock
index 28ff6b3b1ebf2..3ee7d07900700 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2142,6 +2142,12 @@ dependencies = [
  "winapi 0.3.8",
 ]
 
+[[package]]
+name = "pathdiff"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877630b3de15c0b64cc52f659345724fbf6bdad9bd9566699fc53688f3c34a34"
+
 [[package]]
 name = "percent-encoding"
 version = "1.0.1"
@@ -3318,6 +3324,7 @@ dependencies = [
  "log",
  "memmap",
  "num_cpus",
+ "pathdiff",
  "rustc_apfloat",
  "rustc_ast",
  "rustc_attr",
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 1dfa635c694ac..c3f1bac177de7 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -349,6 +349,7 @@ def __init__(self):
         self.use_vendored_sources = ''
         self.verbose = False
         self.git_version = None
+        self.nix_deps_dir = None
 
     def download_stage0(self):
         """Fetch the build system for Rust, written in Rust
@@ -388,8 +389,12 @@ def support_xz():
             filename = "rustc-{}-{}{}".format(rustc_channel, self.build,
                                               tarball_suffix)
             self._download_stage0_helper(filename, "rustc", tarball_suffix)
-            self.fix_executable("{}/bin/rustc".format(self.bin_root()))
-            self.fix_executable("{}/bin/rustdoc".format(self.bin_root()))
+            self.fix_bin_or_dylib("{}/bin/rustc".format(self.bin_root()))
+            self.fix_bin_or_dylib("{}/bin/rustdoc".format(self.bin_root()))
+            lib_dir = "{}/lib".format(self.bin_root())
+            for lib in os.listdir(lib_dir):
+                if lib.endswith(".so"):
+                    self.fix_bin_or_dylib("{}/{}".format(lib_dir, lib))
             with output(self.rustc_stamp()) as rust_stamp:
                 rust_stamp.write(self.date)
 
@@ -408,7 +413,7 @@ def support_xz():
             filename = "cargo-{}-{}{}".format(cargo_channel, self.build,
                                               tarball_suffix)
             self._download_stage0_helper(filename, "cargo", tarball_suffix)
-            self.fix_executable("{}/bin/cargo".format(self.bin_root()))
+            self.fix_bin_or_dylib("{}/bin/cargo".format(self.bin_root()))
             with output(self.cargo_stamp()) as cargo_stamp:
                 cargo_stamp.write(self.date)
 
@@ -421,8 +426,8 @@ def support_xz():
                 [channel, date] = rustfmt_channel.split('-', 1)
                 filename = "rustfmt-{}-{}{}".format(channel, self.build, tarball_suffix)
                 self._download_stage0_helper(filename, "rustfmt-preview", tarball_suffix, date)
-                self.fix_executable("{}/bin/rustfmt".format(self.bin_root()))
-                self.fix_executable("{}/bin/cargo-fmt".format(self.bin_root()))
+                self.fix_bin_or_dylib("{}/bin/rustfmt".format(self.bin_root()))
+                self.fix_bin_or_dylib("{}/bin/cargo-fmt".format(self.bin_root()))
                 with output(self.rustfmt_stamp()) as rustfmt_stamp:
                     rustfmt_stamp.write(self.date + self.rustfmt_channel)
 
@@ -440,12 +445,12 @@ def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None):
             get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
         unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose)
 
-    @staticmethod
-    def fix_executable(fname):
-        """Modifies the interpreter section of 'fname' to fix the dynamic linker
+    def fix_bin_or_dylib(self, fname):
+        """Modifies the interpreter section of 'fname' to fix the dynamic linker,
+        or the RPATH section, to fix the dynamic library search path
 
         This method is only required on NixOS and uses the PatchELF utility to
-        change the dynamic linker of ELF executables.
+        change the interpreter/RPATH of ELF executables.
 
         Please see https://nixos.org/patchelf.html for more information
         """
@@ -472,38 +477,61 @@ def fix_executable(fname):
         nix_os_msg = "info: you seem to be running NixOS. Attempting to patch"
         print(nix_os_msg, fname)
 
-        try:
-            interpreter = subprocess.check_output(
-                ["patchelf", "--print-interpreter", fname])
-            interpreter = interpreter.strip().decode(default_encoding)
-        except subprocess.CalledProcessError as reason:
-            print("warning: failed to call patchelf:", reason)
-            return
-
-        loader = interpreter.split("/")[-1]
-
-        try:
-            ldd_output = subprocess.check_output(
-                ['ldd', '/run/current-system/sw/bin/sh'])
-            ldd_output = ldd_output.strip().decode(default_encoding)
-        except subprocess.CalledProcessError as reason:
-            print("warning: unable to call ldd:", reason)
-            return
-
-        for line in ldd_output.splitlines():
-            libname = line.split()[0]
-            if libname.endswith(loader):
-                loader_path = libname[:len(libname) - len(loader)]
-                break
+        # Only build `stage0/.nix-deps` once.
+        nix_deps_dir = self.nix_deps_dir
+        if not nix_deps_dir:
+            nix_deps_dir = "{}/.nix-deps".format(self.bin_root())
+            if not os.path.exists(nix_deps_dir):
+                os.makedirs(nix_deps_dir)
+
+            nix_deps = [
+                # Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
+                "stdenv.cc.bintools",
+
+                # Needed as a system dependency of `libLLVM-*.so`.
+                "zlib",
+
+                # Needed for patching ELF binaries (see doc comment above).
+                "patchelf",
+            ]
+
+            # Run `nix-build` to "build" each dependency (which will likely reuse
+            # the existing `/nix/store` copy, or at most download a pre-built copy).
+            # Importantly, we don't rely on `nix-build` printing the `/nix/store`
+            # path on stdout, but use `-o` to symlink it into `stage0/.nix-deps/$dep`,
+            # ensuring garbage collection will never remove the `/nix/store` path
+            # (which would break our patched binaries that hardcode those paths).
+            for dep in nix_deps:
+                try:
+                    subprocess.check_output([
+                        "nix-build", "<nixpkgs>",
+                        "-A", dep,
+                        "-o", "{}/{}".format(nix_deps_dir, dep),
+                    ])
+                except subprocess.CalledProcessError as reason:
+                    print("warning: failed to call nix-build:", reason)
+                    return
+
+            self.nix_deps_dir = nix_deps_dir
+
+        patchelf = "{}/patchelf/bin/patchelf".format(nix_deps_dir)
+
+        if fname.endswith(".so"):
+            # Dynamic library, patch RPATH to point to system dependencies.
+            dylib_deps = ["zlib"]
+            rpath_entries = [
+                # Relative default, all binary and dynamic libraries we ship
+                # appear to have this (even when `../lib` is redundant).
+                "$ORIGIN/../lib",
+            ] + ["{}/{}/lib".format(nix_deps_dir, dep) for dep in dylib_deps]
+            patchelf_args = ["--set-rpath", ":".join(rpath_entries)]
         else:
-            print("warning: unable to find the path to the dynamic linker")
-            return
-
-        correct_interpreter = loader_path + loader
+            bintools_dir = "{}/stdenv.cc.bintools".format(nix_deps_dir)
+            with open("{}/nix-support/dynamic-linker".format(bintools_dir)) as dynamic_linker:
+                patchelf_args = ["--set-interpreter", dynamic_linker.read().rstrip()]
 
         try:
-            subprocess.check_output(
-                ["patchelf", "--set-interpreter", correct_interpreter, fname])
+            subprocess.check_output([patchelf] + patchelf_args + [fname])
         except subprocess.CalledProcessError as reason:
             print("warning: failed to call patchelf:", reason)
             return
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 7266625ff39f8..dcdc681e87dbb 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -160,11 +160,6 @@ macro_rules! install {
                 config.extended && config.tools.as_ref()
                     .map_or(true, |t| t.contains($path))
             }
-
-            #[allow(dead_code)]
-            fn should_install(builder: &Builder<'_>) -> bool {
-                builder.config.tools.as_ref().map_or(false, |t| t.contains($path))
-            }
         }
 
         impl Step for $name {
@@ -211,8 +206,7 @@ install!((self, builder, _config),
         install_cargo(builder, self.compiler.stage, self.target);
     };
     Rls, "rls", Self::should_build(_config), only_hosts: true, {
-        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() ||
-            Self::should_install(builder) {
+        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() {
             install_rls(builder, self.compiler.stage, self.target);
         } else {
             builder.info(
@@ -222,27 +216,14 @@ install!((self, builder, _config),
     };
     RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
         builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target });
-        if Self::should_install(builder) {
-            install_rust_analyzer(builder, self.compiler.stage, self.target);
-        } else {
-            builder.info(
-                &format!("skipping Install rust-analyzer stage{} ({})", self.compiler.stage, self.target),
-            );
-        }
+        install_rust_analyzer(builder, self.compiler.stage, self.target);
     };
     Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
         builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target });
-        if Self::should_install(builder) {
-            install_clippy(builder, self.compiler.stage, self.target);
-        } else {
-            builder.info(
-                &format!("skipping Install clippy stage{} ({})", self.compiler.stage, self.target),
-            );
-        }
+        install_clippy(builder, self.compiler.stage, self.target);
     };
     Miri, "miri", Self::should_build(_config), only_hosts: true, {
-        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() ||
-            Self::should_install(builder) {
+        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() {
             install_miri(builder, self.compiler.stage, self.target);
         } else {
             builder.info(
@@ -254,7 +235,7 @@ install!((self, builder, _config),
         if builder.ensure(dist::Rustfmt {
             compiler: self.compiler,
             target: self.target
-        }).is_some() || Self::should_install(builder) {
+        }).is_some() {
             install_rustfmt(builder, self.compiler.stage, self.target);
         } else {
             builder.info(
diff --git a/src/ci/exec-with-shell.py b/src/ci/exec-with-shell.py
deleted file mode 100755
index 26ce69e33d9c3..0000000000000
--- a/src/ci/exec-with-shell.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-# A simple wrapper that forwards the arguments to bash, unless the
-# CI_OVERRIDE_SHELL environment variable is present: in that case the content
-# of that environment variable is used as the shell path.
-
-import os
-import sys
-import subprocess
-
-try:
-    shell = os.environ["CI_OVERRIDE_SHELL"]
-except KeyError:
-    shell = "bash"
-
-res = subprocess.call([shell] + sys.argv[1:])
-sys.exit(res)
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 0b3b77f217dbd..5573d87aa2e55 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -79,7 +79,6 @@ x--expand-yaml-anchors--remove:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
 
       - name: checkout the source code
         uses: actions/checkout@v1
@@ -95,7 +94,6 @@ x--expand-yaml-anchors--remove:
 
       - name: add extra environment variables
         run: src/ci/scripts/setup-environment.sh
-        shell: bash
         env:
           # Since it's not possible to merge `${{ matrix.env }}` with the other
           # variables in `job.<name>.env`, the variables defined in the matrix
@@ -106,67 +104,54 @@ x--expand-yaml-anchors--remove:
 
       - name: decide whether to skip this job
         run: src/ci/scripts/should-skip-this.sh
-        shell: bash
         <<: *step
 
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
-        shell: bash
         <<: *step
 
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
-        shell: bash
         <<: *step
 
       - name: install awscli
         run: src/ci/scripts/install-awscli.sh
-        shell: bash
         <<: *step
 
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
-        shell: bash
         <<: *step
 
       - name: install clang
         run: src/ci/scripts/install-clang.sh
-        shell: bash
         <<: *step
 
       - name: install WIX
         run: src/ci/scripts/install-wix.sh
-        shell: bash
         <<: *step
 
       - name: ensure the build happens on a partition with enough space
         run: src/ci/scripts/symlink-build-dir.sh
-        shell: bash
         <<: *step
 
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         <<: *step
 
       - name: install MSYS2
         run: src/ci/scripts/install-msys2.sh
-        shell: bash
         <<: *step
 
       - name: install MinGW
         run: src/ci/scripts/install-mingw.sh
-        shell: bash
         <<: *step
 
       - name: install ninja
         run: src/ci/scripts/install-ninja.sh
-        shell: bash
         <<: *step
 
       - name: enable ipv6 on Docker
         run: src/ci/scripts/enable-docker-ipv6.sh
-        shell: bash
         <<: *step
 
       # Disable automatic line ending conversion (again). On Windows, when we're
@@ -176,22 +161,18 @@ x--expand-yaml-anchors--remove:
       # appropriate line endings.
       - name: disable git crlf conversion
         run: src/ci/scripts/disable-git-crlf-conversion.sh
-        shell: bash
         <<: *step
 
       - name: checkout submodules
         run: src/ci/scripts/checkout-submodules.sh
-        shell: bash
         <<: *step
 
       - name: ensure line endings are correct
         run: src/ci/scripts/verify-line-endings.sh
-        shell: bash
         <<: *step
 
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }}
           AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
@@ -200,7 +181,6 @@ x--expand-yaml-anchors--remove:
 
       - name: upload artifacts to S3
         run: src/ci/scripts/upload-artifacts.sh
-        shell: bash
         env:
           AWS_ACCESS_KEY_ID: ${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}
           AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}
@@ -250,18 +230,10 @@ on:
 
 defaults:
   run:
-    # While on Linux and macOS builders it just forwards the arguments to the
-    # system bash, this wrapper allows switching from the host's bash.exe to
-    # the one we install along with MSYS2 mid-build on Windows.
-    #
-    # Once the step to install MSYS2 is executed, the CI_OVERRIDE_SHELL
-    # environment variable is set pointing to our MSYS2's bash.exe. From that
-    # moment the host's bash.exe will not be called anymore.
-    #
-    # This is needed because we can't launch our own bash.exe from the host
-    # bash.exe, as that would load two different cygwin1.dll in memory, causing
-    # "cygwin heap mismatch" errors.
-    shell: python src/ci/exec-with-shell.py {0}
+    # On Linux, macOS, and Windows, use the system-provided bash as the default
+    # shell. (This should only make a difference on Windows, where the default
+    # shell is PowerShell.)
+    shell: bash
 
 jobs:
   pr:
diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh
index 3a0c965a67710..185d361582505 100755
--- a/src/ci/scripts/install-msys2.sh
+++ b/src/ci/scripts/install-msys2.sh
@@ -12,9 +12,6 @@ if isWindows; then
     mkdir -p "${msys2Path}/home/${USERNAME}"
     ciCommandAddPath "${msys2Path}/usr/bin"
 
-    echo "switching shell to use our own bash"
-    ciCommandSetEnv CI_OVERRIDE_SHELL "${msys2Path}/usr/bin/bash.exe"
-
     # Detect the native Python version installed on the agent. On GitHub
     # Actions, the C:\hostedtoolcache\windows\Python directory contains a
     # subdirectory for each installed Python version.
diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs
index d8959966fe5ad..530cb0c91b8e3 100644
--- a/src/liballoc/collections/btree/set.rs
+++ b/src/liballoc/collections/btree/set.rs
@@ -22,7 +22,6 @@ use super::Recover;
 /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
 ///
-/// [`BTreeMap`]: struct.BTreeMap.html
 /// [`Ord`]: ../../std/cmp/trait.Ord.html
 /// [`Cell`]: ../../std/cell/struct.Cell.html
 /// [`RefCell`]: ../../std/cell/struct.RefCell.html
@@ -78,8 +77,7 @@ impl<T: Clone> Clone for BTreeSet<T> {
 /// This `struct` is created by the [`iter`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`iter`]: struct.BTreeSet.html#method.iter
+/// [`iter`]: BTreeSet::iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
     iter: Keys<'a, T, ()>,
@@ -97,8 +95,7 @@ impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
 /// This `struct` is created by the [`into_iter`] method on [`BTreeSet`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`into_iter`]: struct.BTreeSet.html#method.into_iter
+/// [`into_iter`]: BTreeSet#method.into_iter
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct IntoIter<T> {
@@ -110,8 +107,7 @@ pub struct IntoIter<T> {
 /// This `struct` is created by the [`range`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`range`]: struct.BTreeSet.html#method.range
+/// [`range`]: BTreeSet::range
 #[derive(Debug)]
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct Range<'a, T: 'a> {
@@ -194,8 +190,7 @@ where
 /// This `struct` is created by the [`difference`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`difference`]: struct.BTreeSet.html#method.difference
+/// [`difference`]: BTreeSet::difference
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Difference<'a, T: 'a> {
     inner: DifferenceInner<'a, T>,
@@ -227,8 +222,7 @@ impl<T: fmt::Debug> fmt::Debug for Difference<'_, T> {
 /// This `struct` is created by the [`symmetric_difference`] method on
 /// [`BTreeSet`]. See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`symmetric_difference`]: struct.BTreeSet.html#method.symmetric_difference
+/// [`symmetric_difference`]: BTreeSet::symmetric_difference
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SymmetricDifference<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
 
@@ -244,8 +238,7 @@ impl<T: fmt::Debug> fmt::Debug for SymmetricDifference<'_, T> {
 /// This `struct` is created by the [`intersection`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`intersection`]: struct.BTreeSet.html#method.intersection
+/// [`intersection`]: BTreeSet::intersection
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Intersection<'a, T: 'a> {
     inner: IntersectionInner<'a, T>,
@@ -277,8 +270,7 @@ impl<T: fmt::Debug> fmt::Debug for Intersection<'_, T> {
 /// This `struct` is created by the [`union`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`union`]: struct.BTreeSet.html#method.union
+/// [`union`]: BTreeSet::union
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Union<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
 
diff --git a/src/libcore/lazy.rs b/src/libcore/lazy.rs
new file mode 100644
index 0000000000000..5cf7217ef11e8
--- /dev/null
+++ b/src/libcore/lazy.rs
@@ -0,0 +1,379 @@
+//! Lazy values and one-time initialization of static data.
+
+use crate::cell::{Cell, UnsafeCell};
+use crate::fmt;
+use crate::mem;
+use crate::ops::Deref;
+
+/// A cell which can be written to only once.
+///
+/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value.
+/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::lazy::OnceCell;
+///
+/// let cell = OnceCell::new();
+/// assert!(cell.get().is_none());
+///
+/// let value: &String = cell.get_or_init(|| {
+///     "Hello, World!".to_string()
+/// });
+/// assert_eq!(value, "Hello, World!");
+/// assert!(cell.get().is_some());
+/// ```
+#[unstable(feature = "once_cell", issue = "74465")]
+pub struct OnceCell<T> {
+    // Invariant: written to at most once.
+    inner: UnsafeCell<Option<T>>,
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> Default for OnceCell<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.get() {
+            Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
+            None => f.write_str("OnceCell(Uninit)"),
+        }
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Clone> Clone for OnceCell<T> {
+    fn clone(&self) -> OnceCell<T> {
+        let res = OnceCell::new();
+        if let Some(value) = self.get() {
+            match res.set(value.clone()) {
+                Ok(()) => (),
+                Err(_) => unreachable!(),
+            }
+        }
+        res
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: PartialEq> PartialEq for OnceCell<T> {
+    fn eq(&self, other: &Self) -> bool {
+        self.get() == other.get()
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Eq> Eq for OnceCell<T> {}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> From<T> for OnceCell<T> {
+    fn from(value: T) -> Self {
+        OnceCell { inner: UnsafeCell::new(Some(value)) }
+    }
+}
+
+impl<T> OnceCell<T> {
+    /// Creates a new empty cell.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub const fn new() -> OnceCell<T> {
+        OnceCell { inner: UnsafeCell::new(None) }
+    }
+
+    /// Gets the reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get(&self) -> Option<&T> {
+        // Safety: Safe due to `inner`'s invariant
+        unsafe { &*self.inner.get() }.as_ref()
+    }
+
+    /// Gets the mutable reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_mut(&mut self) -> Option<&mut T> {
+        // Safety: Safe because we have unique access
+        unsafe { &mut *self.inner.get() }.as_mut()
+    }
+
+    /// Sets the contents of the cell to `value`.
+    ///
+    /// # Errors
+    ///
+    /// This method returns `Ok(())` if the cell was empty and `Err(value)` if
+    /// it was full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let cell = OnceCell::new();
+    /// assert!(cell.get().is_none());
+    ///
+    /// assert_eq!(cell.set(92), Ok(()));
+    /// assert_eq!(cell.set(62), Err(62));
+    ///
+    /// assert!(cell.get().is_some());
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn set(&self, value: T) -> Result<(), T> {
+        // Safety: Safe because we cannot have overlapping mutable borrows
+        let slot = unsafe { &*self.inner.get() };
+        if slot.is_some() {
+            return Err(value);
+        }
+
+        // Safety: This is the only place where we set the slot, no races
+        // due to reentrancy/concurrency are possible, and we've
+        // checked that slot is currently `None`, so this write
+        // maintains the `inner`'s invariant.
+        let slot = unsafe { &mut *self.inner.get() };
+        *slot = Some(value);
+        Ok(())
+    }
+
+    /// Gets the contents of the cell, initializing it with `f`
+    /// if the cell was empty.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`. Doing
+    /// so results in a panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let cell = OnceCell::new();
+    /// let value = cell.get_or_init(|| 92);
+    /// assert_eq!(value, &92);
+    /// let value = cell.get_or_init(|| unreachable!());
+    /// assert_eq!(value, &92);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_or_init<F>(&self, f: F) -> &T
+    where
+        F: FnOnce() -> T,
+    {
+        match self.get_or_try_init(|| Ok::<T, !>(f())) {
+            Ok(val) => val,
+        }
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if
+    /// the cell was empty. If the cell was empty and `f` failed, an
+    /// error is returned.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`. Doing
+    /// so results in a panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let cell = OnceCell::new();
+    /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
+    /// assert!(cell.get().is_none());
+    /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
+    ///     Ok(92)
+    /// });
+    /// assert_eq!(value, Ok(&92));
+    /// assert_eq!(cell.get(), Some(&92))
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
+    where
+        F: FnOnce() -> Result<T, E>,
+    {
+        if let Some(val) = self.get() {
+            return Ok(val);
+        }
+        let val = f()?;
+        // Note that *some* forms of reentrant initialization might lead to
+        // UB (see `reentrant_init` test). I believe that just removing this
+        // `assert`, while keeping `set/get` would be sound, but it seems
+        // better to panic, rather than to silently use an old value.
+        assert!(self.set(val).is_ok(), "reentrant init");
+        Ok(self.get().unwrap())
+    }
+
+    /// Consumes the cell, returning the wrapped value.
+    ///
+    /// Returns `None` if the cell was empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let cell: OnceCell<String> = OnceCell::new();
+    /// assert_eq!(cell.into_inner(), None);
+    ///
+    /// let cell = OnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn into_inner(self) -> Option<T> {
+        // Because `into_inner` takes `self` by value, the compiler statically verifies
+        // that it is not currently borrowed. So it is safe to move out `Option<T>`.
+        self.inner.into_inner()
+    }
+
+    /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
+    ///
+    /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
+    ///
+    /// Safety is guaranteed by requiring a mutable reference.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let mut cell: OnceCell<String> = OnceCell::new();
+    /// assert_eq!(cell.take(), None);
+    ///
+    /// let mut cell = OnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.take(), Some("hello".to_string()));
+    /// assert_eq!(cell.get(), None);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn take(&mut self) -> Option<T> {
+        mem::take(self).into_inner()
+    }
+}
+
+/// A value which is initialized on the first access.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::lazy::Lazy;
+///
+/// let lazy: Lazy<i32> = Lazy::new(|| {
+///     println!("initializing");
+///     92
+/// });
+/// println!("ready");
+/// println!("{}", *lazy);
+/// println!("{}", *lazy);
+///
+/// // Prints:
+/// //   ready
+/// //   initializing
+/// //   92
+/// //   92
+/// ```
+#[unstable(feature = "once_cell", issue = "74465")]
+pub struct Lazy<T, F = fn() -> T> {
+    cell: OnceCell<T>,
+    init: Cell<Option<F>>,
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
+    }
+}
+
+impl<T, F> Lazy<T, F> {
+    /// Creates a new lazy value with the given initializing function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// # fn main() {
+    /// use std::lazy::Lazy;
+    ///
+    /// let hello = "Hello, World!".to_string();
+    ///
+    /// let lazy = Lazy::new(|| hello.to_uppercase());
+    ///
+    /// assert_eq!(&*lazy, "HELLO, WORLD!");
+    /// # }
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub const fn new(init: F) -> Lazy<T, F> {
+        Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) }
+    }
+}
+
+impl<T, F: FnOnce() -> T> Lazy<T, F> {
+    /// Forces the evaluation of this lazy value and returns a reference to
+    /// the result.
+    ///
+    /// This is equivalent to the `Deref` impl, but is explicit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::Lazy;
+    ///
+    /// let lazy = Lazy::new(|| 92);
+    ///
+    /// assert_eq!(Lazy::force(&lazy), &92);
+    /// assert_eq!(&*lazy, &92);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn force(this: &Lazy<T, F>) -> &T {
+        this.cell.get_or_init(|| match this.init.take() {
+            Some(f) => f(),
+            None => panic!("`Lazy` instance has previously been poisoned"),
+        })
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        Lazy::force(self)
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Default> Default for Lazy<T> {
+    /// Creates a new lazy value using `Default` as the initializing function.
+    fn default() -> Lazy<T> {
+        Lazy::new(T::default)
+    }
+}
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 2f2206a117cf7..1621cf7975166 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -239,6 +239,8 @@ pub mod char;
 pub mod ffi;
 #[cfg(not(test))] // See #65860
 pub mod iter;
+#[unstable(feature = "once_cell", issue = "74465")]
+pub mod lazy;
 pub mod option;
 pub mod panic;
 pub mod panicking;
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 309a4ddb00657..20b2c3d3c965a 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -6095,7 +6095,7 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
 ///
 /// Behavior is undefined if any of the following conditions are violated:
 ///
-/// * `data` must be [valid] for writes for `len * mem::size_of::<T>()` many bytes,
+/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::<T>()` many bytes,
 ///   and it must be properly aligned. This means in particular:
 ///
 ///     * The entire memory range of this slice must be contained within a single allocated object!
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 86e8d5c42b7ad..faf58cafbb70b 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -31,9 +31,8 @@ pub mod lossy;
 /// `FromStr`'s [`from_str`] method is often used implicitly, through
 /// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples.
 ///
-/// [`from_str`]: #tymethod.from_str
-/// [`str`]: ../../std/primitive.str.html
-/// [`parse`]: ../../std/primitive.str.html#method.parse
+/// [`from_str`]: FromStr::from_str
+/// [`parse`]: str::parse
 ///
 /// `FromStr` does not have a lifetime parameter, and so you can only parse types
 /// that do not contain a lifetime parameter themselves. In other words, you can
@@ -143,7 +142,7 @@ impl FromStr for bool {
 
 /// An error returned when parsing a `bool` using [`from_str`] fails
 ///
-/// [`from_str`]: ../../std/primitive.bool.html#method.from_str
+/// [`from_str`]: FromStr::from_str
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct ParseBoolError {
@@ -266,8 +265,7 @@ impl Utf8Error {
 /// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid
 /// UTF-8, and then does the conversion.
 ///
-/// [`&str`]: ../../std/primitive.str.html
-/// [`u8`]: ../../std/primitive.u8.html
+/// [`&str`]: str
 /// [byteslice]: ../../std/primitive.slice.html
 ///
 /// If you are sure that the byte slice is valid UTF-8, and you don't want to
@@ -398,7 +396,7 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
 /// it are valid UTF-8. If this constraint is violated, undefined behavior
 /// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8.
 ///
-/// [`&str`]: ../../std/primitive.str.html
+/// [`&str`]: str
 ///
 /// # Examples
 ///
@@ -429,9 +427,7 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
 /// Converts a slice of bytes to a string slice without checking
 /// that the string contains valid UTF-8; mutable version.
 ///
-/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
-///
-/// [fromutf8]: fn.from_utf8_unchecked.html
+/// See the immutable version, [`from_utf8_unchecked()`] for more information.
 ///
 /// # Examples
 ///
@@ -476,13 +472,11 @@ Section: Iterators
 
 /// An iterator over the [`char`]s of a string slice.
 ///
-/// [`char`]: ../../std/primitive.char.html
 ///
 /// This struct is created by the [`chars`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`chars`]: ../../std/primitive.str.html#method.chars
-/// [`str`]: ../../std/primitive.str.html
+/// [`chars`]: str::chars
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Chars<'a> {
@@ -676,13 +670,10 @@ impl<'a> Chars<'a> {
 
 /// An iterator over the [`char`]s of a string slice, and their positions.
 ///
-/// [`char`]: ../../std/primitive.char.html
-///
 /// This struct is created by the [`char_indices`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`char_indices`]: ../../std/primitive.str.html#method.char_indices
-/// [`str`]: ../../std/primitive.str.html
+/// [`char_indices`]: str::char_indices
 #[derive(Clone, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct CharIndices<'a> {
@@ -756,8 +747,7 @@ impl<'a> CharIndices<'a> {
 /// This struct is created by the [`bytes`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`bytes`]: ../../std/primitive.str.html#method.bytes
-/// [`str`]: ../../std/primitive.str.html
+/// [`bytes`]: str::bytes
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone, Debug)]
 pub struct Bytes<'a>(Copied<slice::Iter<'a, u8>>);
@@ -1249,12 +1239,12 @@ generate_pattern_iterators! {
     forward:
         /// Created with the method [`split`].
         ///
-        /// [`split`]: ../../std/primitive.str.html#method.split
+        /// [`split`]: str::split
         struct Split;
     reverse:
         /// Created with the method [`rsplit`].
         ///
-        /// [`rsplit`]: ../../std/primitive.str.html#method.rsplit
+        /// [`rsplit`]: str::rsplit
         struct RSplit;
     stability:
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -1267,12 +1257,12 @@ generate_pattern_iterators! {
     forward:
         /// Created with the method [`split_terminator`].
         ///
-        /// [`split_terminator`]: ../../std/primitive.str.html#method.split_terminator
+        /// [`split_terminator`]: str::split_terminator
         struct SplitTerminator;
     reverse:
         /// Created with the method [`rsplit_terminator`].
         ///
-        /// [`rsplit_terminator`]: ../../std/primitive.str.html#method.rsplit_terminator
+        /// [`rsplit_terminator`]: str::rsplit_terminator
         struct RSplitTerminator;
     stability:
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -1343,12 +1333,12 @@ generate_pattern_iterators! {
     forward:
         /// Created with the method [`splitn`].
         ///
-        /// [`splitn`]: ../../std/primitive.str.html#method.splitn
+        /// [`splitn`]: str::splitn
         struct SplitN;
     reverse:
         /// Created with the method [`rsplitn`].
         ///
-        /// [`rsplitn`]: ../../std/primitive.str.html#method.rsplitn
+        /// [`rsplitn`]: str::rsplitn
         struct RSplitN;
     stability:
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -1398,12 +1388,12 @@ generate_pattern_iterators! {
     forward:
         /// Created with the method [`match_indices`].
         ///
-        /// [`match_indices`]: ../../std/primitive.str.html#method.match_indices
+        /// [`match_indices`]: str::match_indices
         struct MatchIndices;
     reverse:
         /// Created with the method [`rmatch_indices`].
         ///
-        /// [`rmatch_indices`]: ../../std/primitive.str.html#method.rmatch_indices
+        /// [`rmatch_indices`]: str::rmatch_indices
         struct RMatchIndices;
     stability:
         #[stable(feature = "str_match_indices", since = "1.5.0")]
@@ -1455,12 +1445,12 @@ generate_pattern_iterators! {
     forward:
         /// Created with the method [`matches`].
         ///
-        /// [`matches`]: ../../std/primitive.str.html#method.matches
+        /// [`matches`]: str::matches
         struct Matches;
     reverse:
         /// Created with the method [`rmatches`].
         ///
-        /// [`rmatches`]: ../../std/primitive.str.html#method.rmatches
+        /// [`rmatches`]: str::rmatches
         struct RMatches;
     stability:
         #[stable(feature = "str_matches", since = "1.2.0")]
@@ -1474,8 +1464,7 @@ generate_pattern_iterators! {
 /// This struct is created with the [`lines`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`lines`]: ../../std/primitive.str.html#method.lines
-/// [`str`]: ../../std/primitive.str.html
+/// [`lines`]: str::lines
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone, Debug)]
 pub struct Lines<'a>(Map<SplitTerminator<'a, char>, LinesAnyMap>);
@@ -1513,7 +1502,7 @@ impl FusedIterator for Lines<'_> {}
 
 /// Created with the method [`lines_any`].
 ///
-/// [`lines_any`]: ../../std/primitive.str.html#method.lines_any
+/// [`lines_any`]: str::lines_any
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
 #[derive(Clone, Debug)]
@@ -2347,9 +2336,7 @@ impl str {
     }
 
     /// Converts a string slice to a byte slice. To convert the byte slice back
-    /// into a string slice, use the [`str::from_utf8`] function.
-    ///
-    /// [`str::from_utf8`]: ./str/fn.from_utf8.html
+    /// into a string slice, use the [`from_utf8`] function.
     ///
     /// # Examples
     ///
@@ -2429,8 +2416,7 @@ impl str {
     /// The caller must ensure that the returned pointer is never written to.
     /// If you need to mutate the contents of the string slice, use [`as_mut_ptr`].
     ///
-    /// [`u8`]: primitive.u8.html
-    /// [`as_mut_ptr`]: #method.as_mut_ptr
+    /// [`as_mut_ptr`]: str::as_mut_ptr
     ///
     /// # Examples
     ///
@@ -2455,8 +2441,6 @@ impl str {
     ///
     /// It is your responsibility to make sure that the string slice only gets
     /// modified in a way that it remains valid UTF-8.
-    ///
-    /// [`u8`]: primitive.u8.html
     #[stable(feature = "str_as_mut_ptr", since = "1.36.0")]
     #[inline]
     pub fn as_mut_ptr(&mut self) -> *mut u8 {
@@ -2468,8 +2452,6 @@ impl str {
     /// This is the non-panicking alternative to indexing the `str`. Returns
     /// [`None`] whenever equivalent indexing operation would panic.
     ///
-    /// [`None`]: option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2495,8 +2477,6 @@ impl str {
     /// This is the non-panicking alternative to indexing the `str`. Returns
     /// [`None`] whenever equivalent indexing operation would panic.
     ///
-    /// [`None`]: option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2600,8 +2580,7 @@ impl str {
     /// This is generally not recommended, use with caution! For a safe
     /// alternative see [`str`] and [`Index`].
     ///
-    /// [`str`]: primitive.str.html
-    /// [`Index`]: ops/trait.Index.html
+    /// [`Index`]: crate::ops::Index
     ///
     /// This new slice goes from `begin` to `end`, including `begin` but
     /// excluding `end`.
@@ -2609,7 +2588,7 @@ impl str {
     /// To get a mutable string slice instead, see the
     /// [`slice_mut_unchecked`] method.
     ///
-    /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked
+    /// [`slice_mut_unchecked`]: str::slice_mut_unchecked
     ///
     /// # Safety
     ///
@@ -2652,8 +2631,7 @@ impl str {
     /// This is generally not recommended, use with caution! For a safe
     /// alternative see [`str`] and [`IndexMut`].
     ///
-    /// [`str`]: primitive.str.html
-    /// [`IndexMut`]: ops/trait.IndexMut.html
+    /// [`IndexMut`]: crate::ops::IndexMut
     ///
     /// This new slice goes from `begin` to `end`, including `begin` but
     /// excluding `end`.
@@ -2661,7 +2639,7 @@ impl str {
     /// To get an immutable string slice instead, see the
     /// [`slice_unchecked`] method.
     ///
-    /// [`slice_unchecked`]: #method.slice_unchecked
+    /// [`slice_unchecked`]: str::slice_unchecked
     ///
     /// # Safety
     ///
@@ -2692,7 +2670,7 @@ impl str {
     /// To get mutable string slices instead, see the [`split_at_mut`]
     /// method.
     ///
-    /// [`split_at_mut`]: #method.split_at_mut
+    /// [`split_at_mut`]: str::split_at_mut
     ///
     /// # Panics
     ///
@@ -2733,7 +2711,7 @@ impl str {
     ///
     /// To get immutable string slices instead, see the [`split_at`] method.
     ///
-    /// [`split_at`]: #method.split_at
+    /// [`split_at`]: str::split_at
     ///
     /// # Panics
     ///
@@ -2913,7 +2891,7 @@ impl str {
     /// Core Property `White_Space`. If you only want to split on ASCII whitespace
     /// instead, use [`split_ascii_whitespace`].
     ///
-    /// [`split_ascii_whitespace`]: #method.split_ascii_whitespace
+    /// [`split_ascii_whitespace`]: str::split_ascii_whitespace
     ///
     /// # Examples
     ///
@@ -2954,7 +2932,7 @@ impl str {
     ///
     /// To split by Unicode `Whitespace` instead, use [`split_whitespace`].
     ///
-    /// [`split_whitespace`]: #method.split_whitespace
+    /// [`split_whitespace`]: str::split_whitespace
     ///
     /// # Examples
     ///
@@ -3068,8 +3046,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3095,8 +3072,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3121,8 +3097,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3150,9 +3125,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`None`]: option/enum.Option.html#variant.None
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3199,9 +3172,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`None`]: option/enum.Option.html#variant.None
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3247,8 +3218,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3256,12 +3226,10 @@ impl str {
     /// allows a reverse search and forward/reverse search yields the same
     /// elements. This is true for, e.g., [`char`], but not for `&str`.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rsplit`] method can be used.
     ///
-    /// [`rsplit`]: #method.rsplit
+    /// [`rsplit`]: str::rsplit
     ///
     /// # Examples
     ///
@@ -3348,7 +3316,7 @@ impl str {
     ///
     /// Use [`split_whitespace`] for this behavior.
     ///
-    /// [`split_whitespace`]: #method.split_whitespace
+    /// [`split_whitespace`]: str::split_whitespace
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
@@ -3369,8 +3337,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3409,8 +3376,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3418,11 +3384,9 @@ impl str {
     /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
     /// search yields the same elements.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// For iterating from the front, the [`split`] method can be used.
     ///
-    /// [`split`]: #method.split
+    /// [`split`]: str::split
     ///
     /// # Examples
     ///
@@ -3463,13 +3427,12 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// Equivalent to [`split`], except that the trailing substring
     /// is skipped if empty.
     ///
-    /// [`split`]: #method.split
+    /// [`split`]: str::split
     ///
     /// This method can be used for string data that is _terminated_,
     /// rather than _separated_ by a pattern.
@@ -3480,12 +3443,10 @@ impl str {
     /// allows a reverse search and forward/reverse search yields the same
     /// elements. This is true for, e.g., [`char`], but not for `&str`.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rsplit_terminator`] method can be used.
     ///
-    /// [`rsplit_terminator`]: #method.rsplit_terminator
+    /// [`rsplit_terminator`]: str::rsplit_terminator
     ///
     /// # Examples
     ///
@@ -3510,13 +3471,12 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// Equivalent to [`split`], except that the trailing substring is
     /// skipped if empty.
     ///
-    /// [`split`]: #method.split
+    /// [`split`]: str::split
     ///
     /// This method can be used for string data that is _terminated_,
     /// rather than _separated_ by a pattern.
@@ -3530,7 +3490,7 @@ impl str {
     /// For iterating from the front, the [`split_terminator`] method can be
     /// used.
     ///
-    /// [`split_terminator`]: #method.split_terminator
+    /// [`split_terminator`]: str::split_terminator
     ///
     /// # Examples
     ///
@@ -3559,8 +3519,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3570,7 +3529,7 @@ impl str {
     /// If the pattern allows a reverse search, the [`rsplitn`] method can be
     /// used.
     ///
-    /// [`rsplitn`]: #method.rsplitn
+    /// [`rsplitn`]: str::rsplitn
     ///
     /// # Examples
     ///
@@ -3612,8 +3571,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3622,7 +3580,7 @@ impl str {
     ///
     /// For splitting from the front, the [`splitn`] method can be used.
     ///
-    /// [`splitn`]: #method.splitn
+    /// [`splitn`]: str::splitn
     ///
     /// # Examples
     ///
@@ -3660,8 +3618,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3669,12 +3626,10 @@ impl str {
     /// allows a reverse search and forward/reverse search yields the same
     /// elements. This is true for, e.g., [`char`], but not for `&str`.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rmatches`] method can be used.
     ///
-    /// [`rmatches`]: #method.rmatches
+    /// [`rmatches`]: str::matches
     ///
     /// # Examples
     ///
@@ -3699,8 +3654,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3708,11 +3662,9 @@ impl str {
     /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
     /// search yields the same elements.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// For iterating from the front, the [`matches`] method can be used.
     ///
-    /// [`matches`]: #method.matches
+    /// [`matches`]: str::matches
     ///
     /// # Examples
     ///
@@ -3743,8 +3695,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3752,12 +3703,10 @@ impl str {
     /// allows a reverse search and forward/reverse search yields the same
     /// elements. This is true for, e.g., [`char`], but not for `&str`.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rmatch_indices`] method can be used.
     ///
-    /// [`rmatch_indices`]: #method.rmatch_indices
+    /// [`rmatch_indices`]: str::match_indices
     ///
     /// # Examples
     ///
@@ -3788,8 +3737,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3797,11 +3745,9 @@ impl str {
     /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
     /// search yields the same elements.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// For iterating from the front, the [`match_indices`] method can be used.
     ///
-    /// [`match_indices`]: #method.match_indices
+    /// [`match_indices`]: str::match_indices
     ///
     /// # Examples
     ///
@@ -4009,8 +3955,7 @@ impl str {
     /// The [pattern] can be a [`char`], a slice of [`char`]s, or a function
     /// or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -4057,8 +4002,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Text directionality
     ///
@@ -4102,8 +4046,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -4130,8 +4073,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -4157,8 +4099,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Text directionality
     ///
@@ -4206,8 +4147,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Text directionality
     ///
@@ -4243,8 +4183,7 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Text directionality
     ///
@@ -4292,15 +4231,14 @@ impl str {
     /// you're trying to parse into.
     ///
     /// `parse` can parse any type that implements the [`FromStr`] trait.
-    ///
-    /// [`FromStr`]: str/trait.FromStr.html
+
     ///
     /// # Errors
     ///
     /// Will return [`Err`] if it's not possible to parse this string slice into
     /// the desired type.
     ///
-    /// [`Err`]: str/trait.FromStr.html#associatedtype.Err
+    /// [`Err`]: FromStr::Err
     ///
     /// # Examples
     ///
@@ -4428,8 +4366,6 @@ impl str {
     /// Note: only extended grapheme codepoints that begin the string will be
     /// escaped.
     ///
-    /// [`char::escape_debug`]: ../std/primitive.char.html#method.escape_debug
-    ///
     /// # Examples
     ///
     /// As an iterator:
@@ -4474,8 +4410,6 @@ impl str {
 
     /// Return an iterator that escapes each char in `self` with [`char::escape_default`].
     ///
-    /// [`char::escape_default`]: ../std/primitive.char.html#method.escape_default
-    ///
     /// # Examples
     ///
     /// As an iterator:
@@ -4512,8 +4446,6 @@ impl str {
 
     /// Return an iterator that escapes each char in `self` with [`char::escape_unicode`].
     ///
-    /// [`char::escape_unicode`]: ../std/primitive.char.html#method.escape_unicode
-    ///
     /// # Examples
     ///
     /// As an iterator:
@@ -4596,8 +4528,7 @@ impl Default for &mut str {
 /// This struct is created by the [`split_whitespace`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace
-/// [`str`]: ../../std/primitive.str.html
+/// [`split_whitespace`]: str::split_whitespace
 #[stable(feature = "split_whitespace", since = "1.1.0")]
 #[derive(Clone, Debug)]
 pub struct SplitWhitespace<'a> {
@@ -4610,8 +4541,7 @@ pub struct SplitWhitespace<'a> {
 /// This struct is created by the [`split_ascii_whitespace`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`split_ascii_whitespace`]: ../../std/primitive.str.html#method.split_ascii_whitespace
-/// [`str`]: ../../std/primitive.str.html
+/// [`split_ascii_whitespace`]: str::split_ascii_whitespace
 #[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
 #[derive(Clone, Debug)]
 pub struct SplitAsciiWhitespace<'a> {
@@ -4626,8 +4556,7 @@ pub struct SplitAsciiWhitespace<'a> {
 /// This struct is created by the [`split_inclusive`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`split_inclusive`]: ../../std/primitive.str.html#method.split_inclusive
-/// [`str`]: ../../std/primitive.str.html
+/// [`split_inclusive`]: str::split_inclusive
 #[unstable(feature = "split_inclusive", issue = "72360")]
 pub struct SplitInclusive<'a, P: Pattern<'a>>(SplitInternal<'a, P>);
 
@@ -4761,13 +4690,10 @@ impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
 
 /// An iterator of [`u16`] over the string encoded as UTF-16.
 ///
-/// [`u16`]: ../../std/primitive.u16.html
-///
 /// This struct is created by the [`encode_utf16`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16
-/// [`str`]: ../../std/primitive.str.html
+/// [`encode_utf16`]: str::encode_utf16
 #[derive(Clone)]
 #[stable(feature = "encode_utf16", since = "1.8.0")]
 pub struct EncodeUtf16<'a> {
@@ -4818,8 +4744,6 @@ impl<'a> Iterator for EncodeUtf16<'a> {
 impl FusedIterator for EncodeUtf16<'_> {}
 
 /// The return type of [`str::escape_debug`].
-///
-/// [`str::escape_debug`]: ../../std/primitive.str.html#method.escape_debug
 #[stable(feature = "str_escape", since = "1.34.0")]
 #[derive(Clone, Debug)]
 pub struct EscapeDebug<'a> {
@@ -4830,8 +4754,6 @@ pub struct EscapeDebug<'a> {
 }
 
 /// The return type of [`str::escape_default`].
-///
-/// [`str::escape_default`]: ../../std/primitive.str.html#method.escape_default
 #[stable(feature = "str_escape", since = "1.34.0")]
 #[derive(Clone, Debug)]
 pub struct EscapeDefault<'a> {
@@ -4839,8 +4761,6 @@ pub struct EscapeDefault<'a> {
 }
 
 /// The return type of [`str::escape_unicode`].
-///
-/// [`str::escape_unicode`]: ../../std/primitive.str.html#method.escape_unicode
 #[stable(feature = "str_escape", since = "1.34.0")]
 #[derive(Clone, Debug)]
 pub struct EscapeUnicode<'a> {
diff --git a/src/libcore/tests/lazy.rs b/src/libcore/tests/lazy.rs
new file mode 100644
index 0000000000000..1c0bddb9aef62
--- /dev/null
+++ b/src/libcore/tests/lazy.rs
@@ -0,0 +1,124 @@
+use core::{
+    cell::Cell,
+    lazy::{Lazy, OnceCell},
+    sync::atomic::{AtomicUsize, Ordering::SeqCst},
+};
+
+#[test]
+fn once_cell() {
+    let c = OnceCell::new();
+    assert!(c.get().is_none());
+    c.get_or_init(|| 92);
+    assert_eq!(c.get(), Some(&92));
+
+    c.get_or_init(|| panic!("Kabom!"));
+    assert_eq!(c.get(), Some(&92));
+}
+
+#[test]
+fn once_cell_get_mut() {
+    let mut c = OnceCell::new();
+    assert!(c.get_mut().is_none());
+    c.set(90).unwrap();
+    *c.get_mut().unwrap() += 2;
+    assert_eq!(c.get_mut(), Some(&mut 92));
+}
+
+#[test]
+fn once_cell_drop() {
+    static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
+    struct Dropper;
+    impl Drop for Dropper {
+        fn drop(&mut self) {
+            DROP_CNT.fetch_add(1, SeqCst);
+        }
+    }
+
+    let x = OnceCell::new();
+    x.get_or_init(|| Dropper);
+    assert_eq!(DROP_CNT.load(SeqCst), 0);
+    drop(x);
+    assert_eq!(DROP_CNT.load(SeqCst), 1);
+}
+
+#[test]
+fn unsync_once_cell_drop_empty() {
+    let x = OnceCell::<&'static str>::new();
+    drop(x);
+}
+
+#[test]
+fn clone() {
+    let s = OnceCell::new();
+    let c = s.clone();
+    assert!(c.get().is_none());
+
+    s.set("hello").unwrap();
+    let c = s.clone();
+    assert_eq!(c.get().map(|c| *c), Some("hello"));
+}
+
+#[test]
+fn from_impl() {
+    assert_eq!(OnceCell::from("value").get(), Some(&"value"));
+    assert_ne!(OnceCell::from("foo").get(), Some(&"bar"));
+}
+
+#[test]
+fn partialeq_impl() {
+    assert!(OnceCell::from("value") == OnceCell::from("value"));
+    assert!(OnceCell::from("foo") != OnceCell::from("bar"));
+
+    assert!(OnceCell::<&'static str>::new() == OnceCell::new());
+    assert!(OnceCell::<&'static str>::new() != OnceCell::from("value"));
+}
+
+#[test]
+fn into_inner() {
+    let cell: OnceCell<&'static str> = OnceCell::new();
+    assert_eq!(cell.into_inner(), None);
+    let cell = OnceCell::new();
+    cell.set("hello").unwrap();
+    assert_eq!(cell.into_inner(), Some("hello"));
+}
+
+#[test]
+fn lazy_new() {
+    let called = Cell::new(0);
+    let x = Lazy::new(|| {
+        called.set(called.get() + 1);
+        92
+    });
+
+    assert_eq!(called.get(), 0);
+
+    let y = *x - 30;
+    assert_eq!(y, 62);
+    assert_eq!(called.get(), 1);
+
+    let y = *x - 30;
+    assert_eq!(y, 62);
+    assert_eq!(called.get(), 1);
+}
+
+#[test]
+fn aliasing_in_get() {
+    let x = OnceCell::new();
+    x.set(42).unwrap();
+    let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
+    let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>`   |
+    println!("{}", at_x); // <------- up until here ---------------------------+
+}
+
+#[test]
+#[should_panic(expected = "reentrant init")]
+fn reentrant_init() {
+    let x: OnceCell<Box<i32>> = OnceCell::new();
+    let dangling_ref: Cell<Option<&i32>> = Cell::new(None);
+    x.get_or_init(|| {
+        let r = x.get_or_init(|| Box::new(92));
+        dangling_ref.set(Some(r));
+        Box::new(62)
+    });
+    eprintln!("use after free: {:?}", dangling_ref.get().unwrap());
+}
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 090ce47174566..47ed6db6c677b 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -43,6 +43,7 @@
 #![feature(option_unwrap_none)]
 #![feature(peekable_next_if)]
 #![feature(partition_point)]
+#![feature(once_cell)]
 #![feature(unsafe_block_in_unsafe_fn)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
@@ -62,6 +63,7 @@ mod fmt;
 mod hash;
 mod intrinsics;
 mod iter;
+mod lazy;
 mod manually_drop;
 mod mem;
 mod nonzero;
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index eeb6b4aabcf29..e100e0095c92a 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -18,6 +18,7 @@ log = "0.4.5"
 libc = "0.2.50"
 jobserver = "0.1.11"
 tempfile = "3.1"
+pathdiff = "0.2.0"
 
 rustc_serialize = { path = "../librustc_serialize" }
 rustc_ast = { path = "../librustc_ast" }
diff --git a/src/librustc_codegen_ssa/back/rpath.rs b/src/librustc_codegen_ssa/back/rpath.rs
index c02e4f279b1fb..005d2efdd3b26 100644
--- a/src/librustc_codegen_ssa/back/rpath.rs
+++ b/src/librustc_codegen_ssa/back/rpath.rs
@@ -1,3 +1,4 @@
+use pathdiff::diff_paths;
 use rustc_data_structures::fx::FxHashSet;
 use std::env;
 use std::fs;
@@ -109,37 +110,7 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> Str
 // In particular, this handles the case on unix where both paths are
 // absolute but with only the root as the common directory.
 fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
-    use std::path::Component;
-
-    if path.is_absolute() != base.is_absolute() {
-        path.is_absolute().then(|| PathBuf::from(path))
-    } else {
-        let mut ita = path.components();
-        let mut itb = base.components();
-        let mut comps: Vec<Component<'_>> = vec![];
-        loop {
-            match (ita.next(), itb.next()) {
-                (None, None) => break,
-                (Some(a), None) => {
-                    comps.push(a);
-                    comps.extend(ita.by_ref());
-                    break;
-                }
-                (None, _) => comps.push(Component::ParentDir),
-                (Some(a), Some(b)) if comps.is_empty() && a == b => (),
-                (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
-                (Some(_), Some(b)) if b == Component::ParentDir => return None,
-                (Some(a), Some(_)) => {
-                    comps.push(Component::ParentDir);
-                    comps.extend(itb.map(|_| Component::ParentDir));
-                    comps.push(a);
-                    comps.extend(ita.by_ref());
-                    break;
-                }
-            }
-        }
-        Some(comps.iter().map(|c| c.as_os_str()).collect())
-    }
+    diff_paths(path, base)
 }
 
 fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String {
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 8c82765c45d43..1affc9457b89e 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -531,6 +531,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         match ty.kind {
             ty::FnPtr(_) => true,
             ty::Ref(..) => true,
+            ty::Adt(def, _)
+                if def.is_box() && matches!(self.mode, ImproperCTypesMode::Definitions) =>
+            {
+                true
+            }
             ty::Adt(def, substs) if def.repr.transparent() && !def.is_union() => {
                 let guaranteed_nonnull_optimization = self
                     .cx
@@ -558,7 +563,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     }
 
     /// Check if this enum can be safely exported based on the "nullable pointer optimization".
-    /// Currently restricted to function pointers, references, `core::num::NonZero*`,
+    /// Currently restricted to function pointers, boxes, references, `core::num::NonZero*`,
     /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
     fn is_repr_nullable_ptr(
         &self,
@@ -692,6 +697,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         match ty.kind {
+            ty::Adt(def, _)
+                if def.is_box() && matches!(self.mode, ImproperCTypesMode::Definitions) =>
+            {
+                FfiSafe
+            }
+
             ty::Adt(def, substs) => {
                 if def.is_phantom_data() {
                     return FfiPhantom(ty);
diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs
index b7dccb8d8ce6d..a68301385b7a5 100644
--- a/src/librustc_middle/lib.rs
+++ b/src/librustc_middle/lib.rs
@@ -27,6 +27,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(cmp_min_max_by)]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(const_fn_transmute)]
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index 82daae7d921b2..8ae9269a6bf68 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -876,6 +876,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     .iter_enumerated()
                     .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
 
+                let mut niche_filling_layout = None;
+
                 // Niche-filling enum optimization.
                 if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants {
                     let mut dataful_variant = None;
@@ -972,7 +974,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                             let largest_niche =
                                 Niche::from_scalar(dl, offset, niche_scalar.clone());
 
-                            return Ok(tcx.intern_layout(Layout {
+                            niche_filling_layout = Some(Layout {
                                 variants: Variants::Multiple {
                                     tag: niche_scalar,
                                     tag_encoding: TagEncoding::Niche {
@@ -991,7 +993,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                                 largest_niche,
                                 size,
                                 align,
-                            }));
+                            });
                         }
                     }
                 }
@@ -1214,7 +1216,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone());
 
-                tcx.intern_layout(Layout {
+                let tagged_layout = Layout {
                     variants: Variants::Multiple {
                         tag,
                         tag_encoding: TagEncoding::Direct,
@@ -1229,7 +1231,23 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     abi,
                     align,
                     size,
-                })
+                };
+
+                let best_layout = match (tagged_layout, niche_filling_layout) {
+                    (tagged_layout, Some(niche_filling_layout)) => {
+                        // Pick the smaller layout; otherwise,
+                        // pick the layout with the larger niche; otherwise,
+                        // pick tagged as it has simpler codegen.
+                        cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
+                            let niche_size =
+                                layout.largest_niche.as_ref().map_or(0, |n| n.available(dl));
+                            (layout.size, cmp::Reverse(niche_size))
+                        })
+                    }
+                    (tagged_layout, None) => tagged_layout,
+                };
+
+                tcx.intern_layout(best_layout)
             }
 
             // Types with no meaningful known layout.
diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs
new file mode 100644
index 0000000000000..86e1cfae582e8
--- /dev/null
+++ b/src/libstd/lazy.rs
@@ -0,0 +1,844 @@
+//! Lazy values and one-time initialization of static data.
+
+use crate::{
+    cell::{Cell, UnsafeCell},
+    fmt,
+    mem::{self, MaybeUninit},
+    ops::{Deref, Drop},
+    panic::{RefUnwindSafe, UnwindSafe},
+    sync::Once,
+};
+
+#[doc(inline)]
+#[unstable(feature = "once_cell", issue = "74465")]
+pub use core::lazy::*;
+
+/// A synchronization primitive which can be written to only once.
+///
+/// This type is a thread-safe `OnceCell`.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::lazy::SyncOnceCell;
+///
+/// static CELL: SyncOnceCell<String> = SyncOnceCell::new();
+/// assert!(CELL.get().is_none());
+///
+/// std::thread::spawn(|| {
+///     let value: &String = CELL.get_or_init(|| {
+///         "Hello, World!".to_string()
+///     });
+///     assert_eq!(value, "Hello, World!");
+/// }).join().unwrap();
+///
+/// let value: Option<&String> = CELL.get();
+/// assert!(value.is_some());
+/// assert_eq!(value.unwrap().as_str(), "Hello, World!");
+/// ```
+#[unstable(feature = "once_cell", issue = "74465")]
+pub struct SyncOnceCell<T> {
+    once: Once,
+    // Whether or not the value is initialized is tracked by `state_and_queue`.
+    value: UnsafeCell<MaybeUninit<T>>,
+}
+
+// Why do we need `T: Send`?
+// Thread A creates a `SyncOnceCell` and shares it with
+// scoped thread B, which fills the cell, which is
+// then destroyed by A. That is, destructor observes
+// a sent value.
+#[unstable(feature = "once_cell", issue = "74465")]
+unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {}
+#[unstable(feature = "once_cell", issue = "74465")]
+unsafe impl<T: Send> Send for SyncOnceCell<T> {}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {}
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> Default for SyncOnceCell<T> {
+    fn default() -> SyncOnceCell<T> {
+        SyncOnceCell::new()
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.get() {
+            Some(v) => f.debug_tuple("Once").field(v).finish(),
+            None => f.write_str("Once(Uninit)"),
+        }
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Clone> Clone for SyncOnceCell<T> {
+    fn clone(&self) -> SyncOnceCell<T> {
+        let cell = Self::new();
+        if let Some(value) = self.get() {
+            match cell.set(value.clone()) {
+                Ok(()) => (),
+                Err(_) => unreachable!(),
+            }
+        }
+        cell
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> From<T> for SyncOnceCell<T> {
+    fn from(value: T) -> Self {
+        let cell = Self::new();
+        match cell.set(value) {
+            Ok(()) => cell,
+            Err(_) => unreachable!(),
+        }
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: PartialEq> PartialEq for SyncOnceCell<T> {
+    fn eq(&self, other: &SyncOnceCell<T>) -> bool {
+        self.get() == other.get()
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Eq> Eq for SyncOnceCell<T> {}
+
+impl<T> SyncOnceCell<T> {
+    /// Creates a new empty cell.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub const fn new() -> SyncOnceCell<T> {
+        SyncOnceCell { once: Once::new(), value: UnsafeCell::new(MaybeUninit::uninit()) }
+    }
+
+    /// Gets the reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty, or being initialized. This
+    /// method never blocks.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get(&self) -> Option<&T> {
+        if self.is_initialized() {
+            // Safe b/c checked is_initialized
+            Some(unsafe { self.get_unchecked() })
+        } else {
+            None
+        }
+    }
+
+    /// Gets the mutable reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty. This method never blocks.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_mut(&mut self) -> Option<&mut T> {
+        if self.is_initialized() {
+            // Safe b/c checked is_initialized and we have a unique access
+            Some(unsafe { self.get_unchecked_mut() })
+        } else {
+            None
+        }
+    }
+
+    /// Sets the contents of this cell to `value`.
+    ///
+    /// Returns `Ok(())` if the cell's value was updated.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// static CELL: SyncOnceCell<i32> = SyncOnceCell::new();
+    ///
+    /// fn main() {
+    ///     assert!(CELL.get().is_none());
+    ///
+    ///     std::thread::spawn(|| {
+    ///         assert_eq!(CELL.set(92), Ok(()));
+    ///     }).join().unwrap();
+    ///
+    ///     assert_eq!(CELL.set(62), Err(62));
+    ///     assert_eq!(CELL.get(), Some(&92));
+    /// }
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn set(&self, value: T) -> Result<(), T> {
+        let mut value = Some(value);
+        self.get_or_init(|| value.take().unwrap());
+        match value {
+            None => Ok(()),
+            Some(value) => Err(value),
+        }
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if the cell
+    /// was empty.
+    ///
+    /// Many threads may call `get_or_init` concurrently with different
+    /// initializing functions, but it is guaranteed that only one function
+    /// will be executed.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`. The
+    /// exact outcome is unspecified. Current implementation deadlocks, but
+    /// this may be changed to a panic in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// let value = cell.get_or_init(|| 92);
+    /// assert_eq!(value, &92);
+    /// let value = cell.get_or_init(|| unreachable!());
+    /// assert_eq!(value, &92);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_or_init<F>(&self, f: F) -> &T
+    where
+        F: FnOnce() -> T,
+    {
+        match self.get_or_try_init(|| Ok::<T, !>(f())) {
+            Ok(val) => val,
+        }
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if
+    /// the cell was empty. If the cell was empty and `f` failed, an
+    /// error is returned.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and
+    /// the cell remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`.
+    /// The exact outcome is unspecified. Current implementation
+    /// deadlocks, but this may be changed to a panic in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
+    /// assert!(cell.get().is_none());
+    /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
+    ///     Ok(92)
+    /// });
+    /// assert_eq!(value, Ok(&92));
+    /// assert_eq!(cell.get(), Some(&92))
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
+    where
+        F: FnOnce() -> Result<T, E>,
+    {
+        // Fast path check
+        // NOTE: We need to perform an acquire on the state in this method
+        // in order to correctly synchronize `SyncLazy::force`. This is
+        // currently done by calling `self.get()`, which in turn calls
+        // `self.is_initialized()`, which in turn performs the acquire.
+        if let Some(value) = self.get() {
+            return Ok(value);
+        }
+        self.initialize(f)?;
+
+        debug_assert!(self.is_initialized());
+
+        // Safety: The inner value has been initialized
+        Ok(unsafe { self.get_unchecked() })
+    }
+
+    /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns
+    /// `None` if the cell was empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell: SyncOnceCell<String> = SyncOnceCell::new();
+    /// assert_eq!(cell.into_inner(), None);
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn into_inner(mut self) -> Option<T> {
+        // Safety: Safe because we immediately free `self` without dropping
+        let inner = unsafe { self.take_inner() };
+
+        // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set
+        // the state to uninitialized.
+        mem::ManuallyDrop::new(self);
+        inner
+    }
+
+    /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
+    ///
+    /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized.
+    ///
+    /// Safety is guaranteed by requiring a mutable reference.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let mut cell: SyncOnceCell<String> = SyncOnceCell::new();
+    /// assert_eq!(cell.take(), None);
+    ///
+    /// let mut cell = SyncOnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.take(), Some("hello".to_string()));
+    /// assert_eq!(cell.get(), None);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn take(&mut self) -> Option<T> {
+        mem::take(self).into_inner()
+    }
+
+    /// Takes the wrapped value out of a `SyncOnceCell`.
+    /// Afterwards the cell is no longer initialized.
+    ///
+    /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell
+    /// are valid. Only used by `into_inner` and `drop`.
+    unsafe fn take_inner(&mut self) -> Option<T> {
+        // The mutable reference guarantees there are no other threads that can observe us
+        // taking out the wrapped value.
+        // Right after this function `self` is supposed to be freed, so it makes little sense
+        // to atomically set the state to uninitialized.
+        if self.is_initialized() {
+            let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit()));
+            Some(value.into_inner().assume_init())
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn is_initialized(&self) -> bool {
+        self.once.is_completed()
+    }
+
+    #[cold]
+    fn initialize<F, E>(&self, f: F) -> Result<(), E>
+    where
+        F: FnOnce() -> Result<T, E>,
+    {
+        let mut res: Result<(), E> = Ok(());
+        let slot = &self.value;
+
+        // Ignore poisoning from other threads
+        // If another thread panics, then we'll be able to run our closure
+        self.once.call_once_force(|p| {
+            match f() {
+                Ok(value) => {
+                    unsafe { (&mut *slot.get()).write(value) };
+                }
+                Err(e) => {
+                    res = Err(e);
+
+                    // Treat the underlying `Once` as poisoned since we
+                    // failed to initialize our value. Calls
+                    p.poison();
+                }
+            }
+        });
+        res
+    }
+
+    /// Safety: The value must be initialized
+    unsafe fn get_unchecked(&self) -> &T {
+        debug_assert!(self.is_initialized());
+        (&*self.value.get()).get_ref()
+    }
+
+    /// Safety: The value must be initialized
+    unsafe fn get_unchecked_mut(&mut self) -> &mut T {
+        debug_assert!(self.is_initialized());
+        (&mut *self.value.get()).get_mut()
+    }
+}
+
+impl<T> Drop for SyncOnceCell<T> {
+    fn drop(&mut self) {
+        // Safety: The cell is being dropped, so it can't be accessed again
+        unsafe { self.take_inner() };
+    }
+}
+
+/// A value which is initialized on the first access.
+///
+/// This type is a thread-safe `Lazy`, and can be used in statics.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::collections::HashMap;
+///
+/// use std::lazy::SyncLazy;
+///
+/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| {
+///     println!("initializing");
+///     let mut m = HashMap::new();
+///     m.insert(13, "Spica".to_string());
+///     m.insert(74, "Hoyten".to_string());
+///     m
+/// });
+///
+/// fn main() {
+///     println!("ready");
+///     std::thread::spawn(|| {
+///         println!("{:?}", HASHMAP.get(&13));
+///     }).join().unwrap();
+///     println!("{:?}", HASHMAP.get(&74));
+///
+///     // Prints:
+///     //   ready
+///     //   initializing
+///     //   Some("Spica")
+///     //   Some("Hoyten")
+/// }
+/// ```
+#[unstable(feature = "once_cell", issue = "74465")]
+pub struct SyncLazy<T, F = fn() -> T> {
+    cell: SyncOnceCell<T>,
+    init: Cell<Option<F>>,
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
+    }
+}
+
+// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine
+// to not impl `Sync` for `F`
+// we do create a `&mut Option<F>` in `force`, but this is
+// properly synchronized, so it only happens once
+// so it also does not contribute to this impl.
+#[unstable(feature = "once_cell", issue = "74465")]
+unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {}
+// auto-derived `Send` impl is OK.
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T, F: RefUnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {}
+
+impl<T, F> SyncLazy<T, F> {
+    /// Creates a new lazy value with the given initializing
+    /// function.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub const fn new(f: F) -> SyncLazy<T, F> {
+        SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) }
+    }
+}
+
+impl<T, F: FnOnce() -> T> SyncLazy<T, F> {
+    /// Forces the evaluation of this lazy value and
+    /// returns a reference to result. This is equivalent
+    /// to the `Deref` impl, but is explicit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncLazy;
+    ///
+    /// let lazy = SyncLazy::new(|| 92);
+    ///
+    /// assert_eq!(SyncLazy::force(&lazy), &92);
+    /// assert_eq!(&*lazy, &92);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn force(this: &SyncLazy<T, F>) -> &T {
+        this.cell.get_or_init(|| match this.init.take() {
+            Some(f) => f(),
+            None => panic!("Lazy instance has previously been poisoned"),
+        })
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        SyncLazy::force(self)
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Default> Default for SyncLazy<T> {
+    /// Creates a new lazy value using `Default` as the initializing function.
+    fn default() -> SyncLazy<T> {
+        SyncLazy::new(T::default)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::{
+        lazy::{Lazy, SyncLazy, SyncOnceCell},
+        panic,
+        sync::{
+            atomic::{AtomicUsize, Ordering::SeqCst},
+            mpsc::channel,
+            Mutex,
+        },
+    };
+
+    #[test]
+    fn lazy_default() {
+        static CALLED: AtomicUsize = AtomicUsize::new(0);
+
+        struct Foo(u8);
+        impl Default for Foo {
+            fn default() -> Self {
+                CALLED.fetch_add(1, SeqCst);
+                Foo(42)
+            }
+        }
+
+        let lazy: Lazy<Mutex<Foo>> = <_>::default();
+
+        assert_eq!(CALLED.load(SeqCst), 0);
+
+        assert_eq!(lazy.lock().unwrap().0, 42);
+        assert_eq!(CALLED.load(SeqCst), 1);
+
+        lazy.lock().unwrap().0 = 21;
+
+        assert_eq!(lazy.lock().unwrap().0, 21);
+        assert_eq!(CALLED.load(SeqCst), 1);
+    }
+
+    #[test]
+    fn lazy_poisoning() {
+        let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
+        for _ in 0..2 {
+            let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
+            assert!(res.is_err());
+        }
+    }
+
+    // miri doesn't support threads
+    #[cfg(not(miri))]
+    fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
+        crate::thread::spawn(f).join().unwrap()
+    }
+
+    #[cfg(not(miri))]
+    fn spawn(f: impl FnOnce() + Send + 'static) {
+        let _ = crate::thread::spawn(f);
+    }
+
+    // "stub threads" for Miri
+    #[cfg(miri)]
+    fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
+        f(())
+    }
+
+    #[cfg(miri)]
+    fn spawn(f: impl FnOnce() + Send + 'static) {
+        f(())
+    }
+
+    #[test]
+    fn sync_once_cell() {
+        static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
+
+        assert!(ONCE_CELL.get().is_none());
+
+        spawn_and_wait(|| {
+            ONCE_CELL.get_or_init(|| 92);
+            assert_eq!(ONCE_CELL.get(), Some(&92));
+        });
+
+        ONCE_CELL.get_or_init(|| panic!("Kabom!"));
+        assert_eq!(ONCE_CELL.get(), Some(&92));
+    }
+
+    #[test]
+    fn sync_once_cell_get_mut() {
+        let mut c = SyncOnceCell::new();
+        assert!(c.get_mut().is_none());
+        c.set(90).unwrap();
+        *c.get_mut().unwrap() += 2;
+        assert_eq!(c.get_mut(), Some(&mut 92));
+    }
+
+    #[test]
+    fn sync_once_cell_get_unchecked() {
+        let c = SyncOnceCell::new();
+        c.set(92).unwrap();
+        unsafe {
+            assert_eq!(c.get_unchecked(), &92);
+        }
+    }
+
+    #[test]
+    fn sync_once_cell_drop() {
+        static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
+        struct Dropper;
+        impl Drop for Dropper {
+            fn drop(&mut self) {
+                DROP_CNT.fetch_add(1, SeqCst);
+            }
+        }
+
+        let x = SyncOnceCell::new();
+        spawn_and_wait(move || {
+            x.get_or_init(|| Dropper);
+            assert_eq!(DROP_CNT.load(SeqCst), 0);
+            drop(x);
+        });
+
+        assert_eq!(DROP_CNT.load(SeqCst), 1);
+    }
+
+    #[test]
+    fn sync_once_cell_drop_empty() {
+        let x = SyncOnceCell::<String>::new();
+        drop(x);
+    }
+
+    #[test]
+    fn clone() {
+        let s = SyncOnceCell::new();
+        let c = s.clone();
+        assert!(c.get().is_none());
+
+        s.set("hello".to_string()).unwrap();
+        let c = s.clone();
+        assert_eq!(c.get().map(String::as_str), Some("hello"));
+    }
+
+    #[test]
+    fn get_or_try_init() {
+        let cell: SyncOnceCell<String> = SyncOnceCell::new();
+        assert!(cell.get().is_none());
+
+        let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
+        assert!(res.is_err());
+        assert!(!cell.is_initialized());
+        assert!(cell.get().is_none());
+
+        assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
+
+        assert_eq!(
+            cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())),
+            Ok(&"hello".to_string())
+        );
+        assert_eq!(cell.get(), Some(&"hello".to_string()));
+    }
+
+    #[test]
+    fn from_impl() {
+        assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
+        assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
+    }
+
+    #[test]
+    fn partialeq_impl() {
+        assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
+        assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
+
+        assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
+        assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
+    }
+
+    #[test]
+    fn into_inner() {
+        let cell: SyncOnceCell<String> = SyncOnceCell::new();
+        assert_eq!(cell.into_inner(), None);
+        let cell = SyncOnceCell::new();
+        cell.set("hello".to_string()).unwrap();
+        assert_eq!(cell.into_inner(), Some("hello".to_string()));
+    }
+
+    #[test]
+    fn sync_lazy_new() {
+        static CALLED: AtomicUsize = AtomicUsize::new(0);
+        static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
+            CALLED.fetch_add(1, SeqCst);
+            92
+        });
+
+        assert_eq!(CALLED.load(SeqCst), 0);
+
+        spawn_and_wait(|| {
+            let y = *SYNC_LAZY - 30;
+            assert_eq!(y, 62);
+            assert_eq!(CALLED.load(SeqCst), 1);
+        });
+
+        let y = *SYNC_LAZY - 30;
+        assert_eq!(y, 62);
+        assert_eq!(CALLED.load(SeqCst), 1);
+    }
+
+    #[test]
+    fn sync_lazy_default() {
+        static CALLED: AtomicUsize = AtomicUsize::new(0);
+
+        struct Foo(u8);
+        impl Default for Foo {
+            fn default() -> Self {
+                CALLED.fetch_add(1, SeqCst);
+                Foo(42)
+            }
+        }
+
+        let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
+
+        assert_eq!(CALLED.load(SeqCst), 0);
+
+        assert_eq!(lazy.lock().unwrap().0, 42);
+        assert_eq!(CALLED.load(SeqCst), 1);
+
+        lazy.lock().unwrap().0 = 21;
+
+        assert_eq!(lazy.lock().unwrap().0, 21);
+        assert_eq!(CALLED.load(SeqCst), 1);
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // leaks memory
+    fn static_sync_lazy() {
+        static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
+            let mut xs = Vec::new();
+            xs.push(1);
+            xs.push(2);
+            xs.push(3);
+            xs
+        });
+
+        spawn_and_wait(|| {
+            assert_eq!(&*XS, &vec![1, 2, 3]);
+        });
+
+        assert_eq!(&*XS, &vec![1, 2, 3]);
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // leaks memory
+    fn static_sync_lazy_via_fn() {
+        fn xs() -> &'static Vec<i32> {
+            static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
+            XS.get_or_init(|| {
+                let mut xs = Vec::new();
+                xs.push(1);
+                xs.push(2);
+                xs.push(3);
+                xs
+            })
+        }
+        assert_eq!(xs(), &vec![1, 2, 3]);
+    }
+
+    #[test]
+    fn sync_lazy_poisoning() {
+        let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
+        for _ in 0..2 {
+            let res = panic::catch_unwind(|| x.len());
+            assert!(res.is_err());
+        }
+    }
+
+    #[test]
+    fn is_sync_send() {
+        fn assert_traits<T: Send + Sync>() {}
+        assert_traits::<SyncOnceCell<String>>();
+        assert_traits::<SyncLazy<String>>();
+    }
+
+    #[test]
+    fn eval_once_macro() {
+        macro_rules! eval_once {
+            (|| -> $ty:ty {
+                $($body:tt)*
+            }) => {{
+                static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
+                fn init() -> $ty {
+                    $($body)*
+                }
+                ONCE_CELL.get_or_init(init)
+            }};
+        }
+
+        let fib: &'static Vec<i32> = eval_once! {
+            || -> Vec<i32> {
+                let mut res = vec![1, 1];
+                for i in 0..10 {
+                    let next = res[i] + res[i + 1];
+                    res.push(next);
+                }
+                res
+            }
+        };
+        assert_eq!(fib[5], 8)
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // deadlocks without real threads
+    fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
+        static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
+
+        let n_readers = 10;
+        let n_writers = 3;
+        const MSG: &str = "Hello, World";
+
+        let (tx, rx) = channel();
+
+        for _ in 0..n_readers {
+            let tx = tx.clone();
+            spawn(move || {
+                loop {
+                    if let Some(msg) = ONCE_CELL.get() {
+                        tx.send(msg).unwrap();
+                        break;
+                    }
+                }
+            });
+        }
+        for _ in 0..n_writers {
+            spawn(move || {
+                let _ = ONCE_CELL.set(MSG.to_owned());
+            });
+        }
+
+        for _ in 0..n_readers {
+            let msg = rx.recv().unwrap();
+            assert_eq!(msg, MSG);
+        }
+    }
+}
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 54fc35b20f7c9..be8d9f7a7c9cd 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -287,6 +287,7 @@
 #![feature(linkage)]
 #![feature(llvm_asm)]
 #![feature(log_syntax)]
+#![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
 #![feature(min_specialization)]
@@ -294,6 +295,7 @@
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(nll)]
+#![feature(once_cell)]
 #![feature(optin_builtin_traits)]
 #![feature(or_patterns)]
 #![feature(panic_info_message)]
@@ -477,6 +479,9 @@ pub mod process;
 pub mod sync;
 pub mod time;
 
+#[unstable(feature = "once_cell", issue = "74465")]
+pub mod lazy;
+
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub mod task {
     //! Types and Traits for working with asynchronous tasks.
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 7dc822db3d027..64260990824b8 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -132,6 +132,7 @@ unsafe impl Send for Once {}
 #[derive(Debug)]
 pub struct OnceState {
     poisoned: bool,
+    set_state_on_drop_to: Cell<usize>,
 }
 
 /// Initialization value for static [`Once`] values.
@@ -321,7 +322,7 @@ impl Once {
         }
 
         let mut f = Some(f);
-        self.call_inner(true, &mut |p| f.take().unwrap()(&OnceState { poisoned: p }));
+        self.call_inner(true, &mut |p| f.take().unwrap()(p));
     }
 
     /// Returns `true` if some `call_once` call has completed
@@ -385,7 +386,7 @@ impl Once {
     // currently no way to take an `FnOnce` and call it via virtual dispatch
     // without some allocation overhead.
     #[cold]
-    fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(bool)) {
+    fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) {
         let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire);
         loop {
             match state_and_queue {
@@ -413,8 +414,12 @@ impl Once {
                     };
                     // Run the initialization function, letting it know if we're
                     // poisoned or not.
-                    init(state_and_queue == POISONED);
-                    waiter_queue.set_state_on_drop_to = COMPLETE;
+                    let init_state = OnceState {
+                        poisoned: state_and_queue == POISONED,
+                        set_state_on_drop_to: Cell::new(COMPLETE),
+                    };
+                    init(&init_state);
+                    waiter_queue.set_state_on_drop_to = init_state.set_state_on_drop_to.get();
                     break;
                 }
                 _ => {
@@ -554,6 +559,14 @@ impl OnceState {
     pub fn poisoned(&self) -> bool {
         self.poisoned
     }
+
+    /// Poison the associated [`Once`] without explicitly panicking.
+    ///
+    /// [`Once`]: struct.Once.html
+    // NOTE: This is currently only exposed for the `lazy` module
+    pub(crate) fn poison(&self) {
+        self.set_state_on_drop_to.set(POISONED);
+    }
 }
 
 #[cfg(all(test, not(target_os = "emscripten")))]
diff --git a/src/test/codegen/atomic-operations.rs b/src/test/codegen/atomic-operations.rs
new file mode 100644
index 0000000000000..ff94ac8543f8b
--- /dev/null
+++ b/src/test/codegen/atomic-operations.rs
@@ -0,0 +1,60 @@
+// Code generation of atomic operations.
+//
+// compile-flags: -O
+#![crate_type = "lib"]
+
+use std::sync::atomic::{AtomicI32, Ordering::*};
+
+// CHECK-LABEL: @compare_exchange
+#[no_mangle]
+pub fn compare_exchange(a: &AtomicI32) {
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 10 monotonic monotonic
+    let _ = a.compare_exchange(0, 10, Relaxed, Relaxed);
+
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 20 release monotonic
+    let _ = a.compare_exchange(0, 20, Release, Relaxed);
+
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 30 acquire monotonic
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 31 acquire acquire
+    let _ = a.compare_exchange(0, 30, Acquire, Relaxed);
+    let _ = a.compare_exchange(0, 31, Acquire, Acquire);
+
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 40 acq_rel monotonic
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 41 acq_rel acquire
+    let _ = a.compare_exchange(0, 40, AcqRel, Relaxed);
+    let _ = a.compare_exchange(0, 41, AcqRel, Acquire);
+
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 50 seq_cst monotonic
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 51 seq_cst acquire
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 52 seq_cst seq_cst
+    let _ = a.compare_exchange(0, 50, SeqCst, Relaxed);
+    let _ = a.compare_exchange(0, 51, SeqCst, Acquire);
+    let _ = a.compare_exchange(0, 52, SeqCst, SeqCst);
+}
+
+// CHECK-LABEL: @compare_exchange_weak
+#[no_mangle]
+pub fn compare_exchange_weak(w: &AtomicI32) {
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 10 monotonic monotonic
+    let _ = w.compare_exchange_weak(1, 10, Relaxed, Relaxed);
+
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 20 release monotonic
+    let _ = w.compare_exchange_weak(1, 20, Release, Relaxed);
+
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 30 acquire monotonic
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 31 acquire acquire
+    let _ = w.compare_exchange_weak(1, 30, Acquire, Relaxed);
+    let _ = w.compare_exchange_weak(1, 31, Acquire, Acquire);
+
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 40 acq_rel monotonic
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 41 acq_rel acquire
+    let _ = w.compare_exchange_weak(1, 40, AcqRel, Relaxed);
+    let _ = w.compare_exchange_weak(1, 41, AcqRel, Acquire);
+
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 50 seq_cst monotonic
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 51 seq_cst acquire
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 52 seq_cst seq_cst
+    let _ = w.compare_exchange_weak(1, 50, SeqCst, Relaxed);
+    let _ = w.compare_exchange_weak(1, 51, SeqCst, Acquire);
+    let _ = w.compare_exchange_weak(1, 52, SeqCst, SeqCst);
+}
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs
index db15ececfa436..ea75a3d040358 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs
@@ -1,3 +1,6 @@
+// compile-flags: -Zsave-analysis
+// Regression test for #69414 ^
+
 use std::marker::PhantomData;
 
 struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
index 35996e833610d..616f0fa8f1af0 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
@@ -1,11 +1,11 @@
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
+  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:6:22
    |
 LL | struct B<T, const N: T>(PhantomData<[T; N]>);
    |                      ^ the type must not depend on the parameter `T`
 
 error[E0658]: const generics are unstable
-  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19
+  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:6:19
    |
 LL | struct B<T, const N: T>(PhantomData<[T; N]>);
    |                   ^
diff --git a/src/test/ui/lint/lint-ctypes-fn.rs b/src/test/ui/lint/lint-ctypes-fn.rs
index 67dd7abcf79ef..aa02e57866328 100644
--- a/src/test/ui/lint/lint-ctypes-fn.rs
+++ b/src/test/ui/lint/lint-ctypes-fn.rs
@@ -71,7 +71,8 @@ pub extern "C" fn str_type(p: &str) { }
 //~^ ERROR: uses type `str`
 
 pub extern "C" fn box_type(p: Box<u32>) { }
-//~^ ERROR uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn opt_box_type(p: Option<Box<u32>>) { }
 
 pub extern "C" fn char_type(p: char) { }
 //~^ ERROR uses type `char`
@@ -106,7 +107,6 @@ pub extern "C" fn fn_type2(p: fn()) { }
 //~^ ERROR uses type `fn()`
 
 pub extern "C" fn fn_contained(p: RustBadRet) { }
-//~^ ERROR: uses type `std::boxed::Box<u32>`
 
 pub extern "C" fn transparent_i128(p: TransparentI128) { }
 //~^ ERROR: uses type `i128`
@@ -115,7 +115,6 @@ pub extern "C" fn transparent_str(p: TransparentStr) { }
 //~^ ERROR: uses type `str`
 
 pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
-//~^ ERROR: uses type `std::boxed::Box<u32>`
 
 pub extern "C" fn good3(fptr: Option<extern fn()>) { }
 
diff --git a/src/test/ui/lint/lint-ctypes-fn.stderr b/src/test/ui/lint/lint-ctypes-fn.stderr
index 66cf195327890..d0a449514e50e 100644
--- a/src/test/ui/lint/lint-ctypes-fn.stderr
+++ b/src/test/ui/lint/lint-ctypes-fn.stderr
@@ -21,17 +21,8 @@ LL | pub extern "C" fn str_type(p: &str) { }
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
 
-error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:73:31
-   |
-LL | pub extern "C" fn box_type(p: Box<u32>) { }
-   |                               ^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
-
 error: `extern` fn uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:76:32
+  --> $DIR/lint-ctypes-fn.rs:77:32
    |
 LL | pub extern "C" fn char_type(p: char) { }
    |                                ^^^^ not FFI-safe
@@ -40,7 +31,7 @@ LL | pub extern "C" fn char_type(p: char) { }
    = note: the `char` type has no C equivalent
 
 error: `extern` fn uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:79:32
+  --> $DIR/lint-ctypes-fn.rs:80:32
    |
 LL | pub extern "C" fn i128_type(p: i128) { }
    |                                ^^^^ not FFI-safe
@@ -48,7 +39,7 @@ LL | pub extern "C" fn i128_type(p: i128) { }
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` fn uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:82:32
+  --> $DIR/lint-ctypes-fn.rs:83:32
    |
 LL | pub extern "C" fn u128_type(p: u128) { }
    |                                ^^^^ not FFI-safe
@@ -56,7 +47,7 @@ LL | pub extern "C" fn u128_type(p: u128) { }
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:85:33
+  --> $DIR/lint-ctypes-fn.rs:86:33
    |
 LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    |                                 ^^^^^^^^^^ not FFI-safe
@@ -65,7 +56,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:88:34
+  --> $DIR/lint-ctypes-fn.rs:89:34
    |
 LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    |                                  ^^^^^^^ not FFI-safe
@@ -74,7 +65,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:91:32
+  --> $DIR/lint-ctypes-fn.rs:92:32
    |
 LL | pub extern "C" fn zero_size(p: ZeroSize) { }
    |                                ^^^^^^^^ not FFI-safe
@@ -88,7 +79,7 @@ LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:94:40
+  --> $DIR/lint-ctypes-fn.rs:95:40
    |
 LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -101,7 +92,7 @@ LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:97:51
+  --> $DIR/lint-ctypes-fn.rs:98:51
    |
 LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
    |                                                   ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -109,7 +100,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:102:30
+  --> $DIR/lint-ctypes-fn.rs:103:30
    |
 LL | pub extern "C" fn fn_type(p: RustFn) { }
    |                              ^^^^^^ not FFI-safe
@@ -118,7 +109,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { }
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:105:31
+  --> $DIR/lint-ctypes-fn.rs:106:31
    |
 LL | pub extern "C" fn fn_type2(p: fn()) { }
    |                               ^^^^ not FFI-safe
@@ -126,15 +117,6 @@ LL | pub extern "C" fn fn_type2(p: fn()) { }
    = help: consider using an `extern fn(...) -> ...` function pointer instead
    = note: this function pointer has Rust-specific calling convention
 
-error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:108:35
-   |
-LL | pub extern "C" fn fn_contained(p: RustBadRet) { }
-   |                                   ^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
-
 error: `extern` fn uses type `i128`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:111:39
    |
@@ -152,17 +134,8 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
 
-error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:117:37
-   |
-LL | pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
-   |                                     ^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
-
 error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:161:43
+  --> $DIR/lint-ctypes-fn.rs:160:43
    |
 LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
    |                                           ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -170,7 +143,7 @@ LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:174:39
+  --> $DIR/lint-ctypes-fn.rs:173:39
    |
 LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
    |                                       ^^^^^^ not FFI-safe
@@ -179,7 +152,7 @@ LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
    = note: this struct has unspecified layout
 
 error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:177:41
+  --> $DIR/lint-ctypes-fn.rs:176:41
    |
 LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
    |                                         ^^^^^^ not FFI-safe
@@ -187,5 +160,5 @@ LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
-error: aborting due to 20 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/src/test/ui/lint/lint-ctypes.rs b/src/test/ui/lint/lint-ctypes.rs
index a439a1f339aea..bdf95350c7045 100644
--- a/src/test/ui/lint/lint-ctypes.rs
+++ b/src/test/ui/lint/lint-ctypes.rs
@@ -48,6 +48,8 @@ extern {
     pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
     pub fn str_type(p: &str); //~ ERROR: uses type `str`
     pub fn box_type(p: Box<u32>); //~ ERROR uses type `std::boxed::Box<u32>`
+    pub fn opt_box_type(p: Option<Box<u32>>);
+    //~^ ERROR uses type `std::option::Option<std::boxed::Box<u32>>`
     pub fn char_type(p: char); //~ ERROR uses type `char`
     pub fn i128_type(p: i128); //~ ERROR uses type `i128`
     pub fn u128_type(p: u128); //~ ERROR uses type `u128`
diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr
index 9821f858d9caf..13b9adca3f9f5 100644
--- a/src/test/ui/lint/lint-ctypes.stderr
+++ b/src/test/ui/lint/lint-ctypes.stderr
@@ -58,8 +58,17 @@ LL |     pub fn box_type(p: Box<u32>);
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
+error: `extern` block uses type `std::option::Option<std::boxed::Box<u32>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:51:28
+   |
+LL |     pub fn opt_box_type(p: Option<Box<u32>>);
+   |                            ^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
 error: `extern` block uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:51:25
+  --> $DIR/lint-ctypes.rs:53:25
    |
 LL |     pub fn char_type(p: char);
    |                         ^^^^ not FFI-safe
@@ -68,7 +77,7 @@ LL |     pub fn char_type(p: char);
    = note: the `char` type has no C equivalent
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:52:25
+  --> $DIR/lint-ctypes.rs:54:25
    |
 LL |     pub fn i128_type(p: i128);
    |                         ^^^^ not FFI-safe
@@ -76,7 +85,7 @@ LL |     pub fn i128_type(p: i128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:53:25
+  --> $DIR/lint-ctypes.rs:55:25
    |
 LL |     pub fn u128_type(p: u128);
    |                         ^^^^ not FFI-safe
@@ -84,7 +93,7 @@ LL |     pub fn u128_type(p: u128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:54:26
+  --> $DIR/lint-ctypes.rs:56:26
    |
 LL |     pub fn trait_type(p: &dyn Clone);
    |                          ^^^^^^^^^^ not FFI-safe
@@ -92,7 +101,7 @@ LL |     pub fn trait_type(p: &dyn Clone);
    = note: trait objects have no C equivalent
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:55:26
+  --> $DIR/lint-ctypes.rs:57:26
    |
 LL |     pub fn tuple_type(p: (i32, i32));
    |                          ^^^^^^^^^^ not FFI-safe
@@ -101,7 +110,7 @@ LL |     pub fn tuple_type(p: (i32, i32));
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:56:27
+  --> $DIR/lint-ctypes.rs:58:27
    |
 LL |     pub fn tuple_type2(p: I32Pair);
    |                           ^^^^^^^ not FFI-safe
@@ -110,7 +119,7 @@ LL |     pub fn tuple_type2(p: I32Pair);
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:57:25
+  --> $DIR/lint-ctypes.rs:59:25
    |
 LL |     pub fn zero_size(p: ZeroSize);
    |                         ^^^^^^^^ not FFI-safe
@@ -124,7 +133,7 @@ LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:58:33
+  --> $DIR/lint-ctypes.rs:60:33
    |
 LL |     pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -137,7 +146,7 @@ LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:61:12
+  --> $DIR/lint-ctypes.rs:63:12
    |
 LL |         -> ::std::marker::PhantomData<bool>;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -145,7 +154,7 @@ LL |         -> ::std::marker::PhantomData<bool>;
    = note: composed only of `PhantomData`
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:62:23
+  --> $DIR/lint-ctypes.rs:64:23
    |
 LL |     pub fn fn_type(p: RustFn);
    |                       ^^^^^^ not FFI-safe
@@ -154,7 +163,7 @@ LL |     pub fn fn_type(p: RustFn);
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:63:24
+  --> $DIR/lint-ctypes.rs:65:24
    |
 LL |     pub fn fn_type2(p: fn());
    |                        ^^^^ not FFI-safe
@@ -163,7 +172,7 @@ LL |     pub fn fn_type2(p: fn());
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:64:28
+  --> $DIR/lint-ctypes.rs:66:28
    |
 LL |     pub fn fn_contained(p: RustBadRet);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -172,7 +181,7 @@ LL |     pub fn fn_contained(p: RustBadRet);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:65:32
+  --> $DIR/lint-ctypes.rs:67:32
    |
 LL |     pub fn transparent_i128(p: TransparentI128);
    |                                ^^^^^^^^^^^^^^^ not FFI-safe
@@ -180,7 +189,7 @@ LL |     pub fn transparent_i128(p: TransparentI128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:66:31
+  --> $DIR/lint-ctypes.rs:68:31
    |
 LL |     pub fn transparent_str(p: TransparentStr);
    |                               ^^^^^^^^^^^^^^ not FFI-safe
@@ -189,7 +198,7 @@ LL |     pub fn transparent_str(p: TransparentStr);
    = note: string slices have no C equivalent
 
 error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:67:30
+  --> $DIR/lint-ctypes.rs:69:30
    |
 LL |     pub fn transparent_fn(p: TransparentBadFn);
    |                              ^^^^^^^^^^^^^^^^ not FFI-safe
@@ -198,7 +207,7 @@ LL |     pub fn transparent_fn(p: TransparentBadFn);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:68:27
+  --> $DIR/lint-ctypes.rs:70:27
    |
 LL |     pub fn raw_array(arr: [u8; 8]);
    |                           ^^^^^^^ not FFI-safe
@@ -207,7 +216,7 @@ LL |     pub fn raw_array(arr: [u8; 8]);
    = note: passing raw arrays by value is not FFI-safe
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:70:34
+  --> $DIR/lint-ctypes.rs:72:34
    |
 LL |     pub static static_u128_type: u128;
    |                                  ^^^^ not FFI-safe
@@ -215,12 +224,12 @@ LL |     pub static static_u128_type: u128;
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:71:40
+  --> $DIR/lint-ctypes.rs:73:40
    |
 LL |     pub static static_u128_array_type: [u128; 16];
    |                                        ^^^^^^^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: aborting due to 23 previous errors
+error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout
index 301edc0d086b1..1894cd218ee34 100644
--- a/src/test/ui/print_type_sizes/niche-filling.stdout
+++ b/src/test/ui/print_type_sizes/niche-filling.stdout
@@ -8,12 +8,12 @@ print-type-size     variant `Some`: 12 bytes
 print-type-size         field `.0`: 12 bytes
 print-type-size     variant `None`: 0 bytes
 print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 1 bytes
 print-type-size     variant `Record`: 7 bytes
-print-type-size         field `.val`: 4 bytes
-print-type-size         field `.post`: 2 bytes
 print-type-size         field `.pre`: 1 bytes
+print-type-size         field `.post`: 2 bytes
+print-type-size         field `.val`: 4 bytes
 print-type-size     variant `None`: 0 bytes
-print-type-size     end padding: 1 bytes
 print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
 print-type-size     discriminant: 4 bytes
 print-type-size     variant `Some`: 4 bytes
diff --git a/src/test/ui/type-sizes.rs b/src/test/ui/type-sizes.rs
index 6a3f3c98f127a..73a11a5e743f6 100644
--- a/src/test/ui/type-sizes.rs
+++ b/src/test/ui/type-sizes.rs
@@ -5,6 +5,7 @@
 #![feature(never_type)]
 
 use std::mem::size_of;
+use std::num::NonZeroU8;
 
 struct t {a: u8, b: i8}
 struct u {a: u8, b: i8, c: u8}
@@ -102,6 +103,23 @@ enum Option2<A, B> {
     None
 }
 
+// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
+//   Niche-filling:
+//     { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
+//   Tagged:
+//     { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
+// Both are the same size (due to padding),
+// but the tagged layout is better as the tag creates a niche with 254 invalid values,
+// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
+pub enum CanBeNicheFilledButShouldnt {
+    A(NonZeroU8, u32),
+    B
+}
+pub enum AlwaysTaggedBecauseItHasNoNiche {
+    A(u8, u32),
+    B
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -145,4 +163,11 @@ pub fn main() {
     assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
+
+    assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
+    assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
+    assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
+    assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
+    assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
+    assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
 }
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 703b87634cec3..4abb1db35a02f 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -268,7 +268,7 @@ pub struct Config {
     pub gdb_native_rust: bool,
 
     /// Version of LLDB
-    pub lldb_version: Option<String>,
+    pub lldb_version: Option<u32>,
 
     /// Whether LLDB has native rust support
     pub lldb_native_rust: bool,
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index d6e28e93c9667..e155a9249902f 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -132,32 +132,29 @@ impl EarlyProps {
 
         fn ignore_gdb(config: &Config, line: &str) -> bool {
             if let Some(actual_version) = config.gdb_version {
-                if line.starts_with("min-gdb-version") {
-                    let (start_ver, end_ver) = extract_gdb_version_range(line);
+                if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) {
+                    let (start_ver, end_ver) = extract_gdb_version_range(rest);
 
                     if start_ver != end_ver {
                         panic!("Expected single GDB version")
                     }
                     // Ignore if actual version is smaller the minimum required
                     // version
-                    actual_version < start_ver
-                } else if line.starts_with("ignore-gdb-version") {
-                    let (min_version, max_version) = extract_gdb_version_range(line);
+                    return actual_version < start_ver;
+                } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) {
+                    let (min_version, max_version) = extract_gdb_version_range(rest);
 
                     if max_version < min_version {
                         panic!("Malformed GDB version range: max < min")
                     }
 
-                    actual_version >= min_version && actual_version <= max_version
-                } else {
-                    false
+                    return actual_version >= min_version && actual_version <= max_version;
                 }
-            } else {
-                false
             }
+            false
         }
 
-        // Takes a directive of the form "ignore-gdb-version <version1> [- <version2>]",
+        // Takes a directive of the form "<version1> [- <version2>]",
         // returns the numeric representation of <version1> and <version2> as
         // tuple: (<version1> as u32, <version2> as u32)
         // If the <version2> part is omitted, the second component of the tuple
@@ -173,14 +170,14 @@ impl EarlyProps {
                 .take(3) // 3 or more = invalid, so take at most 3.
                 .collect::<Vec<Option<u32>>>();
 
-            match range_components.len() {
-                1 => {
-                    let v = range_components[0].unwrap();
+            match *range_components {
+                [v] => {
+                    let v = v.unwrap();
                     (v, v)
                 }
-                2 => {
-                    let v_min = range_components[0].unwrap();
-                    let v_max = range_components[1].expect(ERROR_MESSAGE);
+                [min, max] => {
+                    let v_min = min.unwrap();
+                    let v_max = max.expect(ERROR_MESSAGE);
                     (v_min, v_max)
                 }
                 _ => panic!(ERROR_MESSAGE),
@@ -188,16 +185,17 @@ impl EarlyProps {
         }
 
         fn ignore_lldb(config: &Config, line: &str) -> bool {
-            if let Some(ref actual_version) = config.lldb_version {
-                if line.starts_with("min-lldb-version") {
-                    let min_version = line
-                        .trim_end()
-                        .rsplit(' ')
-                        .next()
-                        .expect("Malformed lldb version directive");
+            if let Some(actual_version) = config.lldb_version {
+                if let Some(min_version) = line.strip_prefix("min-lldb-version:").map(str::trim) {
+                    let min_version = min_version.parse().unwrap_or_else(|e| {
+                        panic!(
+                            "Unexpected format of LLDB version string: {}\n{:?}",
+                            min_version, e
+                        );
+                    });
                     // Ignore if actual version is smaller the minimum required
                     // version
-                    lldb_version_to_int(actual_version) < lldb_version_to_int(min_version)
+                    actual_version < min_version
                 } else if line.starts_with("rust-lldb") && !config.lldb_native_rust {
                     true
                 } else {
@@ -944,12 +942,6 @@ impl Config {
     }
 }
 
-pub fn lldb_version_to_int(version_string: &str) -> isize {
-    let error_string =
-        format!("Encountered LLDB version string with unexpected format: {}", version_string);
-    version_string.parse().expect(&error_string)
-}
-
 fn expand_variables(mut value: String, config: &Config) -> String {
     const CWD: &'static str = "{{cwd}}";
     const SRC_BASE: &'static str = "{{src-base}}";
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 97272f1a9c1b6..049bf44d6fd96 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -165,9 +165,13 @@ pub fn parse_config(args: Vec<String>) -> Config {
     let cdb = analyze_cdb(matches.opt_str("cdb"), &target);
     let (gdb, gdb_version, gdb_native_rust) =
         analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path);
-    let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version"));
-
-    let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
+    let (lldb_version, lldb_native_rust) = matches
+        .opt_str("lldb-version")
+        .as_deref()
+        .and_then(extract_lldb_version)
+        .map(|(v, b)| (Some(v), b))
+        .unwrap_or((None, false));
+    let color = match matches.opt_str("color").as_deref() {
         Some("auto") | None => ColorConfig::AutoColor,
         Some("always") => ColorConfig::AlwaysColor,
         Some("never") => ColorConfig::NeverColor,
@@ -251,7 +255,7 @@ pub fn log_config(config: &Config) {
     logv(c, format!("stage_id: {}", config.stage_id));
     logv(c, format!("mode: {}", config.mode));
     logv(c, format!("run_ignored: {}", config.run_ignored));
-    logv(c, format!("filter: {}", opt_str(&config.filter.as_ref().map(|re| re.to_owned()))));
+    logv(c, format!("filter: {}", opt_str(&config.filter)));
     logv(c, format!("filter_exact: {}", config.filter_exact));
     logv(
         c,
@@ -400,17 +404,14 @@ fn configure_lldb(config: &Config) -> Option<Config> {
         return None;
     }
 
-    if let Some(lldb_version) = config.lldb_version.as_ref() {
-        if lldb_version == "350" {
-            println!(
-                "WARNING: The used version of LLDB ({}) has a \
-                 known issue that breaks debuginfo tests. See \
-                 issue #32520 for more information. Skipping all \
-                 LLDB-based tests!",
-                lldb_version
-            );
-            return None;
-        }
+    if let Some(350) = config.lldb_version {
+        println!(
+            "WARNING: The used version of LLDB (350) has a \
+             known issue that breaks debuginfo tests. See \
+             issue #32520 for more information. Skipping all \
+             LLDB-based tests!",
+        );
+        return None;
     }
 
     // Some older versions of LLDB seem to have problems with multiple
@@ -722,9 +723,7 @@ fn make_test_closure(
     let config = config.clone();
     let testpaths = testpaths.clone();
     let revision = revision.cloned();
-    test::DynTestFn(Box::new(move || {
-        runtest::run(config, &testpaths, revision.as_ref().map(|s| s.as_str()))
-    }))
+    test::DynTestFn(Box::new(move || runtest::run(config, &testpaths, revision.as_deref())))
 }
 
 /// Returns `true` if the given target is an Android target for the
@@ -840,75 +839,40 @@ fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
     // This particular form is documented in the GNU coding standards:
     // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
 
-    // don't start parsing in the middle of a number
-    let mut prev_was_digit = false;
-    let mut in_parens = false;
-    for (pos, c) in full_version_line.char_indices() {
-        if in_parens {
-            if c == ')' {
-                in_parens = false;
-            }
-            continue;
-        } else if c == '(' {
-            in_parens = true;
-            continue;
-        }
-
-        if prev_was_digit || !c.is_digit(10) {
-            prev_was_digit = c.is_digit(10);
-            continue;
+    let mut splits = full_version_line.rsplit(' ');
+    let version_string = splits.next().unwrap();
+
+    let mut splits = version_string.split('.');
+    let major = splits.next().unwrap();
+    let minor = splits.next().unwrap();
+    let patch = splits.next();
+
+    let major: u32 = major.parse().unwrap();
+    let (minor, patch): (u32, u32) = match minor.find(not_a_digit) {
+        None => {
+            let minor = minor.parse().unwrap();
+            let patch: u32 = match patch {
+                Some(patch) => match patch.find(not_a_digit) {
+                    None => patch.parse().unwrap(),
+                    Some(idx) if idx > 3 => 0,
+                    Some(idx) => patch[..idx].parse().unwrap(),
+                },
+                None => 0,
+            };
+            (minor, patch)
         }
-
-        prev_was_digit = true;
-
-        let line = &full_version_line[pos..];
-
-        let next_split = match line.find(|c: char| !c.is_digit(10)) {
-            Some(idx) => idx,
-            None => continue, // no minor version
-        };
-
-        if line.as_bytes()[next_split] != b'.' {
-            continue; // no minor version
+        // There is no patch version after minor-date (e.g. "4-2012").
+        Some(idx) => {
+            let minor = minor[..idx].parse().unwrap();
+            (minor, 0)
         }
+    };
 
-        let major = &line[..next_split];
-        let line = &line[next_split + 1..];
-
-        let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) {
-            Some(idx) => {
-                if line.as_bytes()[idx] == b'.' {
-                    let patch = &line[idx + 1..];
-
-                    let patch_len =
-                        patch.find(|c: char| !c.is_digit(10)).unwrap_or_else(|| patch.len());
-                    let patch = &patch[..patch_len];
-                    let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) };
-
-                    (&line[..idx], patch)
-                } else {
-                    (&line[..idx], None)
-                }
-            }
-            None => (line, None),
-        };
-
-        if minor.is_empty() {
-            continue;
-        }
-
-        let major: u32 = major.parse().unwrap();
-        let minor: u32 = minor.parse().unwrap();
-        let patch: u32 = patch.unwrap_or("0").parse().unwrap();
-
-        return Some(((major * 1000) + minor) * 1000 + patch);
-    }
-
-    None
+    Some(((major * 1000) + minor) * 1000 + patch)
 }
 
 /// Returns (LLDB version, LLDB is rust-enabled)
-fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, bool) {
+fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
     // Extract the major LLDB version from the given version string.
     // LLDB version strings are different for Apple and non-Apple platforms.
     // The Apple variant looks like this:
@@ -917,7 +881,7 @@ fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, b
     // lldb-300.2.51 (new versions)
     //
     // We are only interested in the major version number, so this function
-    // will return `Some("179")` and `Some("300")` respectively.
+    // will return `Some(179)` and `Some(300)` respectively.
     //
     // Upstream versions look like:
     // lldb version 6.0.1
@@ -929,53 +893,24 @@ fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, b
     // normally fine because the only non-Apple version we test is
     // rust-enabled.
 
-    if let Some(ref full_version_line) = full_version_line {
-        if !full_version_line.trim().is_empty() {
-            let full_version_line = full_version_line.trim();
-
-            for (pos, l) in full_version_line.char_indices() {
-                if l != 'l' && l != 'L' {
-                    continue;
-                }
-                if pos + 5 >= full_version_line.len() {
-                    continue;
-                }
-                let l = full_version_line[pos + 1..].chars().next().unwrap();
-                if l != 'l' && l != 'L' {
-                    continue;
-                }
-                let d = full_version_line[pos + 2..].chars().next().unwrap();
-                if d != 'd' && d != 'D' {
-                    continue;
-                }
-                let b = full_version_line[pos + 3..].chars().next().unwrap();
-                if b != 'b' && b != 'B' {
-                    continue;
-                }
-                let dash = full_version_line[pos + 4..].chars().next().unwrap();
-                if dash != '-' {
-                    continue;
-                }
-
-                let vers = full_version_line[pos + 5..]
-                    .chars()
-                    .take_while(|c| c.is_digit(10))
-                    .collect::<String>();
-                if !vers.is_empty() {
-                    return (Some(vers), full_version_line.contains("rust-enabled"));
-                }
-            }
+    let full_version_line = full_version_line.trim();
 
-            if full_version_line.starts_with("lldb version ") {
-                let vers = full_version_line[13..]
-                    .chars()
-                    .take_while(|c| c.is_digit(10))
-                    .collect::<String>();
-                if !vers.is_empty() {
-                    return (Some(vers + "00"), full_version_line.contains("rust-enabled"));
-                }
-            }
+    if let Some(apple_ver) =
+        full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-"))
+    {
+        if let Some(idx) = apple_ver.find(not_a_digit) {
+            let version: u32 = apple_ver[..idx].parse().unwrap();
+            return Some((version, full_version_line.contains("rust-enabled")));
+        }
+    } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") {
+        if let Some(idx) = lldb_ver.find(not_a_digit) {
+            let version: u32 = lldb_ver[..idx].parse().unwrap();
+            return Some((version * 100, full_version_line.contains("rust-enabled")));
         }
     }
-    (None, false)
+    None
+}
+
+fn not_a_digit(c: char) -> bool {
+    !c.is_digit(10)
 }
diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs
index 31c151d29e916..237bb756597a3 100644
--- a/src/tools/compiletest/src/tests.rs
+++ b/src/tools/compiletest/src/tests.rs
@@ -2,7 +2,7 @@ use super::*;
 
 #[test]
 fn test_extract_gdb_version() {
-    macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
+    macro_rules! test { ($($expectation:literal: $input:literal,)*) => {{$(
         assert_eq!(extract_gdb_version($input), Some($expectation));
     )*}}}
 
@@ -41,6 +41,17 @@ fn test_extract_gdb_version() {
     }
 }
 
+#[test]
+fn test_extract_lldb_version() {
+    // Apple variants
+    assert_eq!(extract_lldb_version("LLDB-179.5"), Some((179, false)));
+    assert_eq!(extract_lldb_version("lldb-300.2.51"), Some((300, false)));
+
+    // Upstream versions
+    assert_eq!(extract_lldb_version("lldb version 6.0.1"), Some((600, false)));
+    assert_eq!(extract_lldb_version("lldb version 9.0.0"), Some((900, false)));
+}
+
 #[test]
 fn is_test_test() {
     assert_eq!(true, is_test(&OsString::from("a_test.rs")));
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index b7d3d428cd283..559267a494f29 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -123,6 +123,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
     "opaque-debug",
     "parking_lot",
     "parking_lot_core",
+    "pathdiff",
     "pkg-config",
     "polonius-engine",
     "ppv-lite86",