about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-28 07:13:12 +0000
committerbors <bors@rust-lang.org>2023-06-28 07:13:12 +0000
commit984d29d26069590786b47424c8ca205e4f4560cb (patch)
treea400dcb280046d1e426076bd25df1b468aebe6b5 /src
parent662388e17fe4f3a4252f63fd84c05cfd54cc13a0 (diff)
parentde9dc5916456f441286c35452416a3dec0b4c2c0 (diff)
downloadrust-984d29d26069590786b47424c8ca205e4f4560cb.tar.gz
rust-984d29d26069590786b47424c8ca205e4f4560cb.zip
Auto merge of #2944 - oli-obk:rustup, r=oli-obk
Rustup
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/bin/main.rs57
-rw-r--r--src/bootstrap/bootstrap.py155
-rw-r--r--src/bootstrap/bootstrap_test.py94
-rw-r--r--src/bootstrap/config.rs8
-rw-r--r--src/bootstrap/config/tests.rs19
-rwxr-xr-xsrc/bootstrap/configure.py8
-rw-r--r--src/bootstrap/defaults/config.dist.toml (renamed from src/bootstrap/defaults/config.user.toml)0
-rw-r--r--src/bootstrap/doc.rs15
-rw-r--r--src/bootstrap/lib.rs9
-rw-r--r--src/bootstrap/setup.rs16
-rw-r--r--src/bootstrap/test.rs19
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh2
-rw-r--r--src/ci/github-actions/ci.yml19
m---------src/doc/book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md13
-rw-r--r--src/doc/rustc/src/platform-support/esp-idf.md10
-rw-r--r--src/doc/rustc/src/platform-support/loongarch-linux.md2
-rw-r--r--src/doc/rustc/src/platform-support/netbsd.md107
-rw-r--r--src/doc/style-guide/src/statements.md105
-rwxr-xr-xsrc/etc/test-float-parse/runtests.py2
-rw-r--r--src/librustdoc/clean/auto_trait.rs10
-rw-r--r--src/librustdoc/clean/mod.rs152
-rw-r--r--src/librustdoc/clean/simplify.rs4
-rw-r--r--src/librustdoc/clean/types.rs3
-rw-r--r--src/librustdoc/config.rs36
-rw-r--r--src/librustdoc/core.rs7
-rw-r--r--src/librustdoc/doctest.rs11
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css2
-rw-r--r--src/librustdoc/html/static/js/search.js4
-rw-r--r--src/librustdoc/lib.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs1
-rw-r--r--src/tools/clippy/src/driver.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6250.stderr5
-rw-r--r--src/tools/compiletest/src/common.rs90
-rw-r--r--src/tools/compiletest/src/header/needs.rs5
-rw-r--r--src/tools/compiletest/src/runtest.rs2
-rw-r--r--src/tools/error_index_generator/main.rs5
-rw-r--r--src/tools/generate-windows-sys/src/arm_shim.rs20
-rw-r--r--src/tools/generate-windows-sys/src/main.rs4
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs25
-rw-r--r--src/tools/rust-installer/Cargo.toml4
-rw-r--r--src/tools/rust-installer/src/combiner.rs30
-rw-r--r--src/tools/rust-installer/src/compression.rs2
-rw-r--r--src/tools/rust-installer/src/generator.rs28
-rw-r--r--src/tools/rust-installer/src/scripter.rs12
-rw-r--r--src/tools/rust-installer/src/tarballer.rs14
-rw-r--r--src/tools/rust-installer/src/util.rs4
-rw-r--r--src/tools/tidy/src/features.rs8
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
70 files changed, 710 insertions, 611 deletions
diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs
index a80379e85c1..7ce4599c424 100644
--- a/src/bootstrap/bin/main.rs
+++ b/src/bootstrap/bin/main.rs
@@ -5,7 +5,9 @@
 //! parent directory, and otherwise documentation can be found throughout the `build`
 //! directory in each respective module.
 
-use std::env;
+use std::fs::OpenOptions;
+use std::io::Write;
+use std::{env, fs, process};
 
 #[cfg(all(any(unix, windows), not(target_os = "solaris")))]
 use bootstrap::t;
@@ -20,22 +22,32 @@ fn main() {
     #[cfg(all(any(unix, windows), not(target_os = "solaris")))]
     let _build_lock_guard;
     #[cfg(all(any(unix, windows), not(target_os = "solaris")))]
+    // Display PID of process holding the lock
+    // PID will be stored in a lock file
     {
         let path = config.out.join("lock");
-        build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path)));
+        let pid = match fs::read_to_string(&path) {
+            Ok(contents) => contents,
+            Err(_) => String::new(),
+        };
+
+        build_lock =
+            fd_lock::RwLock::new(t!(OpenOptions::new().write(true).create(true).open(&path)));
         _build_lock_guard = match build_lock.try_write() {
-            Ok(lock) => lock,
+            Ok(mut lock) => {
+                t!(lock.write(&process::id().to_string().as_ref()));
+                lock
+            }
             err => {
                 drop(err);
-                if let Some(pid) = get_lock_owner(&path) {
-                    println!("warning: build directory locked by process {pid}, waiting for lock");
-                } else {
-                    println!("warning: build directory locked, waiting for lock");
-                }
-                t!(build_lock.write())
+                println!("warning: build directory locked by process {pid}, waiting for lock");
+                let mut lock = t!(build_lock.write());
+                t!(lock.write(&process::id().to_string().as_ref()));
+                lock
             }
         };
     }
+
     #[cfg(any(not(any(unix, windows)), target_os = "solaris"))]
     println!("warning: file locking not supported for target, not locking build directory");
 
@@ -108,30 +120,3 @@ fn check_version(config: &Config) -> Option<String> {
 
     Some(msg)
 }
-
-/// Get the PID of the process which took the write lock by
-/// parsing `/proc/locks`.
-#[cfg(target_os = "linux")]
-fn get_lock_owner(f: &std::path::Path) -> Option<u64> {
-    use std::fs::File;
-    use std::io::{BufRead, BufReader};
-    use std::os::unix::fs::MetadataExt;
-
-    let lock_inode = std::fs::metadata(f).ok()?.ino();
-    let lockfile = File::open("/proc/locks").ok()?;
-    BufReader::new(lockfile).lines().find_map(|line| {
-        //                       pid--vvvvvv       vvvvvvv--- inode
-        // 21: FLOCK  ADVISORY  WRITE 359238 08:02:3719774 0 EOF
-        let line = line.ok()?;
-        let parts = line.split_whitespace().collect::<Vec<_>>();
-        let (pid, inode) = (parts[4].parse::<u64>().ok()?, &parts[5]);
-        let inode = inode.rsplit_once(':')?.1.parse::<u64>().ok()?;
-        if inode == lock_inode { Some(pid) } else { None }
-    })
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "solaris")))]
-fn get_lock_owner(_: &std::path::Path) -> Option<u64> {
-    // FIXME: Implement on other OS's
-    None
-}
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5714613cdf5..149350e62a0 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -323,6 +323,7 @@ def default_build_triple(verbose):
     cputype_mapper = {
         'BePC': 'i686',
         'aarch64': 'aarch64',
+        'aarch64eb': 'aarch64',
         'amd64': 'x86_64',
         'arm64': 'aarch64',
         'i386': 'i686',
@@ -458,23 +459,51 @@ def unpack_component(download_info):
         verbose=download_info.verbose,
     )
 
-class RustBuild(object):
-    """Provide all the methods required to build Rust"""
+class FakeArgs:
+    """Used for unit tests to avoid updating all call sites"""
     def __init__(self):
-        self.checksums_sha256 = {}
-        self.stage0_compiler = None
-        self.download_url = ''
         self.build = ''
         self.build_dir = ''
         self.clean = False
-        self.config_toml = ''
-        self.rust_root = ''
-        self.use_locked_deps = False
-        self.use_vendored_sources = False
         self.verbose = False
+        self.json_output = False
+        self.color = 'auto'
+        self.warnings = 'default'
+
+class RustBuild(object):
+    """Provide all the methods required to build Rust"""
+    def __init__(self, config_toml="", args=FakeArgs()):
         self.git_version = None
         self.nix_deps_dir = None
         self._should_fix_bins_and_dylibs = None
+        self.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
+
+        self.config_toml = config_toml
+
+        self.clean = args.clean
+        self.json_output = args.json_output
+        self.verbose = args.verbose
+        self.color = args.color
+        self.warnings = args.warnings
+
+        config_verbose_count = self.get_toml('verbose', 'build')
+        if config_verbose_count is not None:
+            self.verbose = max(self.verbose, int(config_verbose_count))
+
+        self.use_vendored_sources = self.get_toml('vendor', 'build') == 'true'
+        self.use_locked_deps = self.get_toml('locked-deps', 'build') == 'true'
+
+        build_dir = args.build_dir or self.get_toml('build-dir', 'build') or 'build'
+        self.build_dir = os.path.abspath(build_dir)
+
+        with open(os.path.join(self.rust_root, "src", "stage0.json")) as f:
+            data = json.load(f)
+        self.checksums_sha256 = data["checksums_sha256"]
+        self.stage0_compiler = Stage0Toolchain(data["compiler"])
+        self.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"]
+
+        self.build = args.build or self.build_triple()
+
 
     def download_toolchain(self):
         """Fetch the build system for Rust, written in Rust
@@ -704,9 +733,10 @@ class RustBuild(object):
         """Return the path for .rustc-stamp at the given stage
 
         >>> rb = RustBuild()
+        >>> rb.build = "host"
         >>> rb.build_dir = "build"
-        >>> rb.rustc_stamp() == os.path.join("build", "stage0", ".rustc-stamp")
-        True
+        >>> expected = os.path.join("build", "host", "stage0", ".rustc-stamp")
+        >>> assert rb.rustc_stamp() == expected, rb.rustc_stamp()
         """
         return os.path.join(self.bin_root(), '.rustc-stamp')
 
@@ -721,15 +751,9 @@ class RustBuild(object):
         """Return the binary root directory for the given stage
 
         >>> rb = RustBuild()
-        >>> rb.build_dir = "build"
-        >>> rb.bin_root() == os.path.join("build", "stage0")
-        True
-
-        When the 'build' property is given should be a nested directory:
-
         >>> rb.build = "devel"
-        >>> rb.bin_root() == os.path.join("build", "devel", "stage0")
-        True
+        >>> expected = os.path.abspath(os.path.join("build", "devel", "stage0"))
+        >>> assert rb.bin_root() == expected, rb.bin_root()
         """
         subdir = "stage0"
         return os.path.join(self.build_dir, self.build, subdir)
@@ -761,9 +785,12 @@ class RustBuild(object):
         >>> rb.get_toml("key1")
         'true'
         """
+        return RustBuild.get_toml_static(self.config_toml, key, section)
 
+    @staticmethod
+    def get_toml_static(config_toml, key, section=None):
         cur_section = None
-        for line in self.config_toml.splitlines():
+        for line in config_toml.splitlines():
             section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
             if section_match is not None:
                 cur_section = section_match.group(1)
@@ -772,7 +799,7 @@ class RustBuild(object):
             if match is not None:
                 value = match.group(1)
                 if section is None or section == cur_section:
-                    return self.get_string(value) or value.strip()
+                    return RustBuild.get_string(value) or value.strip()
         return None
 
     def cargo(self):
@@ -835,13 +862,23 @@ class RustBuild(object):
         """
         return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap")
 
-    def build_bootstrap(self, color, warnings, verbose_count):
+    def build_bootstrap(self):
         """Build bootstrap"""
         env = os.environ.copy()
         if "GITHUB_ACTIONS" in env:
             print("::group::Building bootstrap")
         else:
             print("Building bootstrap", file=sys.stderr)
+
+        args = self.build_bootstrap_cmd(env)
+        # Run this from the source directory so cargo finds .cargo/config
+        run(args, env=env, verbose=self.verbose, cwd=self.rust_root)
+
+        if "GITHUB_ACTIONS" in env:
+            print("::endgroup::")
+
+    def build_bootstrap_cmd(self, env):
+        """For tests."""
         build_dir = os.path.join(self.build_dir, "bootstrap")
         if self.clean and os.path.exists(build_dir):
             shutil.rmtree(build_dir)
@@ -894,10 +931,10 @@ class RustBuild(object):
         if target_linker is not None:
             env["RUSTFLAGS"] += " -C linker=" + target_linker
         env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes"
-        if warnings == "default":
+        if self.warnings == "default":
             deny_warnings = self.get_toml("deny-warnings", "rust") != "false"
         else:
-            deny_warnings = warnings == "deny"
+            deny_warnings = self.warnings == "deny"
         if deny_warnings:
             env["RUSTFLAGS"] += " -Dwarnings"
 
@@ -908,7 +945,7 @@ class RustBuild(object):
                 self.cargo()))
         args = [self.cargo(), "build", "--manifest-path",
                 os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
-        args.extend("--verbose" for _ in range(verbose_count))
+        args.extend("--verbose" for _ in range(self.verbose))
         if self.use_locked_deps:
             args.append("--locked")
         if self.use_vendored_sources:
@@ -918,20 +955,16 @@ class RustBuild(object):
             args.append("build-metrics")
         if self.json_output:
             args.append("--message-format=json")
-        if color == "always":
+        if self.color == "always":
             args.append("--color=always")
-        elif color == "never":
+        elif self.color == "never":
             args.append("--color=never")
         try:
             args += env["CARGOFLAGS"].split()
         except KeyError:
             pass
 
-        # Run this from the source directory so cargo finds .cargo/config
-        run(args, env=env, verbose=self.verbose, cwd=self.rust_root)
-
-        if "GITHUB_ACTIONS" in env:
-            print("::endgroup::")
+        return args
 
     def build_triple(self):
         """Build triple as in LLVM
@@ -981,7 +1014,7 @@ class RustBuild(object):
             if os.path.exists(cargo_dir):
                 shutil.rmtree(cargo_dir)
 
-def parse_args():
+def parse_args(args):
     """Parse the command line arguments that the python script needs."""
     parser = argparse.ArgumentParser(add_help=False)
     parser.add_argument('-h', '--help', action='store_true')
@@ -994,16 +1027,11 @@ def parse_args():
     parser.add_argument('--warnings', choices=['deny', 'warn', 'default'], default='default')
     parser.add_argument('-v', '--verbose', action='count', default=0)
 
-    return parser.parse_known_args(sys.argv)[0]
+    return parser.parse_known_args(args)[0]
 
 def bootstrap(args):
     """Configure, fetch, build and run the initial bootstrap"""
-    # Configure initial bootstrap
-    build = RustBuild()
-    build.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
-    build.verbose = args.verbose != 0
-    build.clean = args.clean
-    build.json_output = args.json_output
+    rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
 
     # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
     # then `config.toml` in the root directory.
@@ -1012,52 +1040,43 @@ def bootstrap(args):
     if using_default_path:
         toml_path = 'config.toml'
         if not os.path.exists(toml_path):
-            toml_path = os.path.join(build.rust_root, toml_path)
+            toml_path = os.path.join(rust_root, toml_path)
 
     # Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
     # but not if `config.toml` hasn't been created.
     if not using_default_path or os.path.exists(toml_path):
         with open(toml_path) as config:
-            build.config_toml = config.read()
+            config_toml = config.read()
+    else:
+        config_toml = ''
 
-    profile = build.get_toml('profile')
+    profile = RustBuild.get_toml_static(config_toml, 'profile')
     if profile is not None:
-        include_file = 'config.{}.toml'.format(profile)
-        include_dir = os.path.join(build.rust_root, 'src', 'bootstrap', 'defaults')
+        # Allows creating alias for profile names, allowing
+        # profiles to be renamed while maintaining back compatibility
+        # Keep in sync with `profile_aliases` in config.rs
+        profile_aliases = {
+            "user": "dist"
+        }
+        include_file = 'config.{}.toml'.format(profile_aliases.get(profile) or profile)
+        include_dir = os.path.join(rust_root, 'src', 'bootstrap', 'defaults')
         include_path = os.path.join(include_dir, include_file)
-        # HACK: This works because `build.get_toml()` returns the first match it finds for a
+        # HACK: This works because `self.get_toml()` returns the first match it finds for a
         # specific key, so appending our defaults at the end allows the user to override them
         with open(include_path) as included_toml:
-            build.config_toml += os.linesep + included_toml.read()
-
-    verbose_count = args.verbose
-    config_verbose_count = build.get_toml('verbose', 'build')
-    if config_verbose_count is not None:
-        verbose_count = max(args.verbose, int(config_verbose_count))
-
-    build.use_vendored_sources = build.get_toml('vendor', 'build') == 'true'
-    build.use_locked_deps = build.get_toml('locked-deps', 'build') == 'true'
+            config_toml += os.linesep + included_toml.read()
 
+    # Configure initial bootstrap
+    build = RustBuild(config_toml, args)
     build.check_vendored_status()
 
-    build_dir = args.build_dir or build.get_toml('build-dir', 'build') or 'build'
-    build.build_dir = os.path.abspath(build_dir)
-
-    with open(os.path.join(build.rust_root, "src", "stage0.json")) as f:
-        data = json.load(f)
-    build.checksums_sha256 = data["checksums_sha256"]
-    build.stage0_compiler = Stage0Toolchain(data["compiler"])
-    build.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"]
-
-    build.build = args.build or build.build_triple()
-
     if not os.path.exists(build.build_dir):
         os.makedirs(build.build_dir)
 
     # Fetch/build the bootstrap
     build.download_toolchain()
     sys.stdout.flush()
-    build.build_bootstrap(args.color, args.warnings, verbose_count)
+    build.build_bootstrap()
     sys.stdout.flush()
 
     # Run the bootstrap
@@ -1077,7 +1096,7 @@ def main():
     if len(sys.argv) > 1 and sys.argv[1] == 'help':
         sys.argv[1] = '-h'
 
-    args = parse_args()
+    args = parse_args(sys.argv)
     help_triggered = args.help or len(sys.argv) == 1
 
     # If the user is asking for help, let them know that the whole download-and-build
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 5ecda83ee66..1294ca9df0d 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -1,4 +1,6 @@
-"""Bootstrap tests"""
+"""Bootstrap tests
+
+Run these with `x test bootstrap`, or `python -m unittest bootstrap_test.py`."""
 
 from __future__ import absolute_import, division, print_function
 import os
@@ -13,6 +15,22 @@ from shutil import rmtree
 import bootstrap
 import configure
 
+def serialize_and_parse(configure_args, bootstrap_args=bootstrap.FakeArgs()):
+    from io import StringIO
+
+    section_order, sections, targets = configure.parse_args(configure_args)
+    buffer = StringIO()
+    configure.write_config_toml(buffer, section_order, targets, sections)
+    build = bootstrap.RustBuild(config_toml=buffer.getvalue(), args=bootstrap_args)
+
+    try:
+        import tomllib
+        # Verify this is actually valid TOML.
+        tomllib.loads(build.config_toml)
+    except ImportError:
+        print("warning: skipping TOML validation, need at least python 3.11", file=sys.stderr)
+    return build
+
 
 class VerifyTestCase(unittest.TestCase):
     """Test Case for verify"""
@@ -77,58 +95,58 @@ class ProgramOutOfDate(unittest.TestCase):
 
 class GenerateAndParseConfig(unittest.TestCase):
     """Test that we can serialize and deserialize a config.toml file"""
-    def serialize_and_parse(self, args):
-        from io import StringIO
-
-        section_order, sections, targets = configure.parse_args(args)
-        buffer = StringIO()
-        configure.write_config_toml(buffer, section_order, targets, sections)
-        build = bootstrap.RustBuild()
-        build.config_toml = buffer.getvalue()
-
-        try:
-            import tomllib
-            # Verify this is actually valid TOML.
-            tomllib.loads(build.config_toml)
-        except ImportError:
-            print("warning: skipping TOML validation, need at least python 3.11", file=sys.stderr)
-        return build
-
     def test_no_args(self):
-        build = self.serialize_and_parse([])
+        build = serialize_and_parse([])
         self.assertEqual(build.get_toml("changelog-seen"), '2')
-        self.assertEqual(build.get_toml("profile"), 'user')
+        self.assertEqual(build.get_toml("profile"), 'dist')
         self.assertIsNone(build.get_toml("llvm.download-ci-llvm"))
 
     def test_set_section(self):
-        build = self.serialize_and_parse(["--set", "llvm.download-ci-llvm"])
+        build = serialize_and_parse(["--set", "llvm.download-ci-llvm"])
         self.assertEqual(build.get_toml("download-ci-llvm", section="llvm"), 'true')
 
     def test_set_target(self):
-        build = self.serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"])
+        build = serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"])
         self.assertEqual(build.get_toml("cc", section="target.x86_64-unknown-linux-gnu"), 'gcc')
 
     def test_set_top_level(self):
-        build = self.serialize_and_parse(["--set", "profile=compiler"])
+        build = serialize_and_parse(["--set", "profile=compiler"])
         self.assertEqual(build.get_toml("profile"), 'compiler')
 
     def test_set_codegen_backends(self):
-        build = self.serialize_and_parse(["--set", "rust.codegen-backends=cranelift"])
+        build = serialize_and_parse(["--set", "rust.codegen-backends=cranelift"])
         self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift']"), -1)
-        build = self.serialize_and_parse(["--set", "rust.codegen-backends=cranelift,llvm"])
+        build = serialize_and_parse(["--set", "rust.codegen-backends=cranelift,llvm"])
         self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift', 'llvm']"), -1)
-        build = self.serialize_and_parse(["--enable-full-tools"])
+        build = serialize_and_parse(["--enable-full-tools"])
         self.assertNotEqual(build.config_toml.find("codegen-backends = ['llvm']"), -1)
 
-if __name__ == '__main__':
-    SUITE = unittest.TestSuite()
-    TEST_LOADER = unittest.TestLoader()
-    SUITE.addTest(doctest.DocTestSuite(bootstrap))
-    SUITE.addTests([
-        TEST_LOADER.loadTestsFromTestCase(VerifyTestCase),
-        TEST_LOADER.loadTestsFromTestCase(GenerateAndParseConfig),
-        TEST_LOADER.loadTestsFromTestCase(ProgramOutOfDate)])
-
-    RUNNER = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)
-    result = RUNNER.run(SUITE)
-    sys.exit(0 if result.wasSuccessful() else 1)
+
+class BuildBootstrap(unittest.TestCase):
+    """Test that we generate the appropriate arguments when building bootstrap"""
+
+    def build_args(self, configure_args=[], args=[], env={}):
+        env = env.copy()
+        env["PATH"] = os.environ["PATH"]
+
+        parsed = bootstrap.parse_args(args)
+        build = serialize_and_parse(configure_args, parsed)
+        build.build_dir = os.environ["BUILD_DIR"]
+        build.build = os.environ["BUILD_PLATFORM"]
+        return build.build_bootstrap_cmd(env), env
+
+    def test_cargoflags(self):
+        args, _ = self.build_args(env={"CARGOFLAGS": "--timings"})
+        self.assertTrue("--timings" in args)
+
+    def test_warnings(self):
+        for toml_warnings in ['false', 'true', None]:
+            configure_args = []
+            if toml_warnings is not None:
+                configure_args = ["--set", "rust.deny-warnings=" + toml_warnings]
+
+            _, env = self.build_args(configure_args, args=["--warnings=warn"])
+            self.assertFalse("-Dwarnings" in env["RUSTFLAGS"])
+
+            _, env = self.build_args(configure_args, args=["--warnings=deny"])
+            self.assertTrue("-Dwarnings" in env["RUSTFLAGS"])
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 8ee63e561ba..b91275e73e9 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -1129,6 +1129,14 @@ impl Config {
         };
 
         if let Some(include) = &toml.profile {
+            // Allows creating alias for profile names, allowing
+            // profiles to be renamed while maintaining back compatibility
+            // Keep in sync with `profile_aliases` in bootstrap.py
+            let profile_aliases = HashMap::from([("user", "dist")]);
+            let include = match profile_aliases.get(include.as_str()) {
+                Some(alias) => alias,
+                None => include.as_str(),
+            };
             let mut include_path = config.src.clone();
             include_path.push("src");
             include_path.push("bootstrap");
diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs
index 4de84b543ed..3bee659abd1 100644
--- a/src/bootstrap/config/tests.rs
+++ b/src/bootstrap/config/tests.rs
@@ -1,5 +1,8 @@
+use crate::config::TomlConfig;
+
 use super::{Config, Flags};
 use clap::CommandFactory;
+use serde::Deserialize;
 use std::{env, path::Path};
 
 fn parse(config: &str) -> Config {
@@ -159,3 +162,19 @@ fn override_toml_duplicate() {
         |&_| toml::from_str("changelog-seen = 0").unwrap(),
     );
 }
+
+#[test]
+fn profile_user_dist() {
+    fn get_toml(file: &Path) -> TomlConfig {
+        let contents = if file.ends_with("config.toml") {
+            "profile = \"user\"".to_owned()
+        } else {
+            assert!(file.ends_with("config.dist.toml"));
+            std::fs::read_to_string(dbg!(file)).unwrap()
+        };
+        toml::from_str(&contents)
+            .and_then(|table: toml::Value| TomlConfig::deserialize(table))
+            .unwrap()
+    }
+    Config::parse_inner(&["check".to_owned()], get_toml);
+}
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index a16f77317c8..e8eebdfb5a5 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -280,7 +280,7 @@ def parse_args(args):
 
     config = {}
 
-    set('build.configure-args', sys.argv[1:], config)
+    set('build.configure-args', args, config)
     apply_args(known_args, option_checking, config)
     return parse_example_config(known_args, config)
 
@@ -400,7 +400,9 @@ def parse_example_config(known_args, config):
     targets = {}
     top_level_keys = []
 
-    for line in open(rust_dir + '/config.example.toml').read().split("\n"):
+    with open(rust_dir + '/config.example.toml') as example_config:
+        example_lines = example_config.read().split("\n")
+    for line in example_lines:
         if cur_section is None:
             if line.count('=') == 1:
                 top_level_key = line.split('=')[0]
@@ -435,7 +437,7 @@ def parse_example_config(known_args, config):
         targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
 
     if 'profile' not in config:
-        set('profile', 'user', config)
+        set('profile', 'dist', config)
     configure_file(sections, top_level_keys, targets, config)
     return section_order, sections, targets
 
diff --git a/src/bootstrap/defaults/config.user.toml b/src/bootstrap/defaults/config.dist.toml
index 25d9e649f23..25d9e649f23 100644
--- a/src/bootstrap/defaults/config.user.toml
+++ b/src/bootstrap/defaults/config.dist.toml
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 8592895423e..1ac52dffe58 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -222,7 +222,7 @@ impl Step for TheBook {
         let shared_assets = builder.ensure(SharedAssets { target });
 
         // build the redirect pages
-        builder.info(&format!("Documenting book redirect pages ({})", target));
+        builder.msg_doc(compiler, "book redirect pages", target);
         for file in t!(fs::read_dir(builder.src.join(&relative_path).join("redirects"))) {
             let file = t!(file);
             let path = file.path();
@@ -306,7 +306,7 @@ impl Step for Standalone {
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
         let compiler = self.compiler;
-        builder.info(&format!("Documenting standalone ({})", target));
+        builder.msg_doc(compiler, "standalone", target);
         let out = builder.doc_out(target);
         t!(fs::create_dir_all(&out));
 
@@ -562,7 +562,7 @@ fn doc_std(
 
     let description =
         format!("library{} in {} format", crate_description(&requested_crates), format.as_str());
-    let _guard = builder.msg(Kind::Doc, stage, &description, compiler.host, target);
+    let _guard = builder.msg_doc(compiler, &description, target);
 
     let target_doc_dir_name = if format == DocumentationFormat::JSON { "json-doc" } else { "doc" };
     let target_dir =
@@ -804,14 +804,7 @@ macro_rules! tool_doc {
                     SourceType::Submodule
                 };
 
-                builder.info(
-                    &format!(
-                        "Documenting stage{} {} ({})",
-                        stage,
-                        stringify!($tool).to_lowercase(),
-                        target,
-                    ),
-                );
+                builder.msg_doc(compiler, stringify!($tool).to_lowercase(), target);
 
                 // Symlink compiler docs to the output directory of rustdoc documentation.
                 let out_dirs = [
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index d389b568f56..c960053d7a0 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1009,6 +1009,15 @@ impl Build {
         self.msg(Kind::Check, self.config.stage, what, self.config.build, target)
     }
 
+    fn msg_doc(
+        &self,
+        compiler: Compiler,
+        what: impl Display,
+        target: impl Into<Option<TargetSelection>> + Copy,
+    ) -> Option<gha::Group> {
+        self.msg(Kind::Doc, compiler.stage, what, compiler.host, target.into())
+    }
+
     fn msg_build(
         &self,
         compiler: Compiler,
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 7eb70de91f8..34c6ccf1365 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -20,7 +20,7 @@ pub enum Profile {
     Codegen,
     Library,
     Tools,
-    User,
+    Dist,
     None,
 }
 
@@ -43,7 +43,7 @@ impl Profile {
     pub fn all() -> impl Iterator<Item = Self> {
         use Profile::*;
         // N.B. these are ordered by how they are displayed, not alphabetically
-        [Library, Compiler, Codegen, Tools, User, None].iter().copied()
+        [Library, Compiler, Codegen, Tools, Dist, None].iter().copied()
     }
 
     pub fn purpose(&self) -> String {
@@ -53,7 +53,7 @@ impl Profile {
             Compiler => "Contribute to the compiler itself",
             Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
             Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)",
-            User => "Install Rust from source",
+            Dist => "Install Rust from source",
             None => "Do not modify `config.toml`"
         }
         .to_string()
@@ -73,7 +73,7 @@ impl Profile {
             Profile::Codegen => "codegen",
             Profile::Library => "library",
             Profile::Tools => "tools",
-            Profile::User => "user",
+            Profile::Dist => "dist",
             Profile::None => "none",
         }
     }
@@ -87,7 +87,7 @@ impl FromStr for Profile {
             "lib" | "library" => Ok(Profile::Library),
             "compiler" => Ok(Profile::Compiler),
             "llvm" | "codegen" => Ok(Profile::Codegen),
-            "maintainer" | "user" => Ok(Profile::User),
+            "maintainer" | "dist" | "user" => Ok(Profile::Dist),
             "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => {
                 Ok(Profile::Tools)
             }
@@ -160,7 +160,7 @@ pub fn setup(config: &Config, profile: Profile) {
             "test src/tools/rustfmt",
         ],
         Profile::Library => &["check", "build", "test library/std", "doc"],
-        Profile::User => &["dist", "build"],
+        Profile::Dist => &["dist", "build"],
     };
 
     println!();
@@ -170,7 +170,7 @@ pub fn setup(config: &Config, profile: Profile) {
         println!("- `x.py {}`", cmd);
     }
 
-    if profile != Profile::User {
+    if profile != Profile::Dist {
         println!(
             "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
         );
@@ -582,7 +582,7 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
             Some(false) => {
                 // exists and is not current version or outdated, so back it up
                 let mut backup = vscode_settings.clone();
-                backup.set_extension("bak");
+                backup.set_extension("json.bak");
                 eprintln!("warning: copying `settings.json` to `settings.json.bak`");
                 fs::copy(&vscode_settings, &backup)?;
                 "Updated"
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 873ed61daf3..ec447a1cd73 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1832,11 +1832,13 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             builder,
         );
 
-        builder.info(&format!(
-            "Check compiletest suite={} mode={} ({} -> {})",
-            suite, mode, &compiler.host, target
-        ));
-        let _time = util::timeit(&builder);
+        let _group = builder.msg(
+            Kind::Test,
+            compiler.stage,
+            &format!("compiletest suite={suite} mode={mode}"),
+            compiler.host,
+            target,
+        );
         crate::render_tests::try_run_tests(builder, &mut cmd, false);
 
         if let Some(compare_mode) = compare_mode {
@@ -2664,7 +2666,12 @@ impl Step for Bootstrap {
     /// Tests the build system itself.
     fn run(self, builder: &Builder<'_>) {
         let mut check_bootstrap = Command::new(&builder.python());
-        check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/"));
+        check_bootstrap
+            .args(["-m", "unittest", "bootstrap_test.py"])
+            .env("BUILD_DIR", &builder.out)
+            .env("BUILD_PLATFORM", &builder.build.build.triple)
+            .current_dir(builder.src.join("src/bootstrap/"))
+            .args(builder.config.test_args());
         try_run(builder, &mut check_bootstrap).unwrap();
 
         let host = builder.config.build;
diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
index 5fbce36c39d..b867db6a1b5 100755
--- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
@@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin"
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard 4362b1885fd369e042a7c0ecd8df3b6cd47fb4e8
+git reset --hard 7018e24d8fe248596819d2e884761676f3542a04
 make -j$(nproc) \
     CC="$bin/clang" \
     NM="$bin/llvm-nm" \
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index a9e42e4a0a0..8907d643182 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -147,13 +147,6 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/verify-channel.sh
         <<: *step
 
-      - name: configure GitHub Actions to kill the build when outdated
-        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-        with:
-          github_token: "${{ secrets.github_token }}"
-        if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'
-        <<: *step
-
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         <<: *step
@@ -305,10 +298,14 @@ defaults:
     # shell is PowerShell.)
     shell: bash
 
+concurrency:
+  # For a given workflow, if we push to the same PR, cancel all previous builds on that PR.
+  # If the push is not attached to a PR, we will cancel all builds related to the same commit SHA.
+  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+  cancel-in-progress: true
+
 jobs:
   pr:
-    permissions:
-      actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds
     <<: *base-ci-job
     name: PR - ${{ matrix.name }}
     env:
@@ -331,8 +328,6 @@ jobs:
             <<: *job-linux-16c
 
   auto:
-    permissions:
-      actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds
     <<: *base-ci-job
     name: auto - ${{ matrix.name }}
     env:
@@ -734,8 +729,6 @@ jobs:
             <<: *job-windows-8c
 
   try:
-    permissions:
-      actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds
     <<: *base-ci-job
     name: try - ${{ matrix.name }}
     env:
diff --git a/src/doc/book b/src/doc/book
-Subproject 8fa6b854d515506d825390fe0d817f5ef0c8935
+Subproject 21cf840842bdf768a798869f06373c96c1cc512
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject b5f018fb5930cb733b0a8aaf2eed975d4771e74
+Subproject c369e4b489332f8721fbae630354fa83385d457
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 553d99b02a53b4133a40d5bd2e19958c67487c0
+Subproject 5ca365eac678cb0d41a20b3204546d6ed70c717
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 8ee9528b72b927cff8fd32346db8bbd1198816f
+Subproject 57636d6926762861f34e030d52ca25a71e95e5b
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject f1e637883fafeb83bdd5906ee7f467e4d35b733
+Subproject 17fe3e948498c50e208047a750f17d6a8d89669
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 1e17a90a842..f8af26326a7 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -40,6 +40,7 @@
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
+    - [\*-unknown-netbsd\*](platform-support/netbsd.md)
     - [*-unknown-openbsd](platform-support/openbsd.md)
     - [\*-unknown-uefi](platform-support/unknown-uefi.md)
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 62f628f8229..6d1729e57b1 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -224,13 +224,14 @@ target | std | host | notes
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ✓ |  | ARM64 HermitCore
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
-`aarch64-unknown-netbsd` | ✓ | ✓ |
+[`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD
 [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
 `aarch64-unknown-redox` | ? |  | ARM64 Redox OS
 `aarch64-uwp-windows-msvc` | ? |  |
 `aarch64-wrs-vxworks` | ? |  |
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
 `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
+[`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
 [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers
 [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).
 `armv4t-none-eabi` | * |  | ARMv4T A32
@@ -238,7 +239,7 @@ target | std | host | notes
 [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE A32
 `armv5te-unknown-linux-uclibceabi` | ? |  | ARMv5TE Linux with uClibc
 `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
-`armv6-unknown-netbsd-eabihf` | ? |  |
+[`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 `armv7-apple-ios` | ✓ |  | ARMv7 iOS, Cortex-a8
 [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? |  | ARM Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
@@ -246,7 +247,7 @@ target | std | host | notes
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7 Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux with uClibc, hardfloat
 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
-`armv7-unknown-netbsd-eabihf` | ✓ | ✓ |
+[`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv7 NetBSD w/hard-float
 `armv7-wrs-vxworks-eabihf` | ? |  |
 [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3
 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
@@ -262,7 +263,7 @@ target | std | host | notes
 `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
 `i686-pc-windows-msvc` | * |  | 32-bit Windows XP support
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
-`i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
+[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
 `i686-uwp-windows-gnu` | ? |  |
 `i686-uwp-windows-msvc` | ? |  |
@@ -283,7 +284,7 @@ target | std | host | notes
 `msp430-none-elf` | * |  | 16-bit MSP430 microcontrollers
 `powerpc-unknown-linux-gnuspe` | ✓ |  | PowerPC SPE Linux
 `powerpc-unknown-linux-musl` | ? |  |
-`powerpc-unknown-netbsd` | ✓ | ✓ |
+[`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems
 `powerpc-unknown-openbsd` | ? |  |
 `powerpc-wrs-vxworks-spe` | ? |  |
 `powerpc-wrs-vxworks` | ? |  |
@@ -307,7 +308,7 @@ target | std | host | notes
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
 `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 3.2, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
-`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
+[`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64
 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
 `thumbv4t-none-eabi` | * |  | ARMv4T T32
 [`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE T32
diff --git a/src/doc/rustc/src/platform-support/esp-idf.md b/src/doc/rustc/src/platform-support/esp-idf.md
index 4bbe35709b0..8f630fa152c 100644
--- a/src/doc/rustc/src/platform-support/esp-idf.md
+++ b/src/doc/rustc/src/platform-support/esp-idf.md
@@ -13,10 +13,12 @@ Targets for the [ESP-IDF](https://github.com/espressif/esp-idf) development fram
 
 The target names follow this format: `$ARCH-esp-espidf`, where `$ARCH` specifies the target processor architecture. The following targets are currently defined:
 
-|          Target name           | Target CPU(s)         | Minimum ESP-IDF version |
-|--------------------------------|-----------------------|-------------------------|
-| `riscv32imc-esp-espidf`        |  [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3)             | `v4.3`                |
-| `riscv32imac-esp-espidf`       |  [ESP32-C6](https://www.espressif.com/en/products/socs/esp32-c6)             | `v5.1`                |
+| Target name              | Target CPU(s)                                                   | Minimum ESP-IDF version |
+| ------------------------ | --------------------------------------------------------------- | ----------------------- |
+| `riscv32imc-esp-espidf`  | [ESP32-C2](https://www.espressif.com/en/products/socs/esp32-c2) | `v5.0`                  |
+| `riscv32imc-esp-espidf`  | [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3) | `v4.3`                  |
+| `riscv32imac-esp-espidf` | [ESP32-C6](https://www.espressif.com/en/products/socs/esp32-c6) | `v5.1`                  |
+| `riscv32imac-esp-espidf` | [ESP32-H2](https://www.espressif.com/en/products/socs/esp32-h2) | `v5.1`                  |
 
 It is recommended to use the latest ESP-IDF stable release if possible.
 
diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md
index 999e71f8028..17e85590f2c 100644
--- a/src/doc/rustc/src/platform-support/loongarch-linux.md
+++ b/src/doc/rustc/src/platform-support/loongarch-linux.md
@@ -28,9 +28,9 @@ While the integer base ABI is implied by the machine field, the floating po
 
 ## Target maintainers
 
-- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn`
 - [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn`
 - [ZHAI Xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn`
+- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn`
 - [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name`
 
 ## Requirements
diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md
new file mode 100644
index 00000000000..a1969524a20
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/netbsd.md
@@ -0,0 +1,107 @@
+# \*-unknown-netbsd
+
+**Tier: 3**
+
+[NetBSD] multi-platform 4.4BSD-based UNIX-like operating system.
+
+[NetBSD]: https://www.NetBSD.org/
+
+The target names follow this format: `$ARCH-unknown-netbsd{-$SUFFIX}`,
+where `$ARCH` specifies the target processor architecture and
+`-$SUFFIX` (optional) might indicate the ABI. The following targets
+are currently defined running NetBSD:
+
+|          Target name           | NetBSD Platform |
+|--------------------------------|-----------------|
+| `amd64-unknown-netbsd`         | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) |
+| `armv7-unknown-netbsd-eabihf`  | [32-bit ARMv7 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) |
+| `armv6-unknown-netbsd-eabihf`  | [32-bit ARMv6 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) |
+| `aarch64-unknown-netbsd`       | [64-bit ARM systems, little-endian](https://wiki.netbsd.org/ports/evbarm/) |
+| `aarch64_be-unknown-netbsd`    | [64-bit ARM systems, big-endian](https://wiki.netbsd.org/ports/evbarm/) |
+| `i586-unknown-netbsd`          | [32-bit i386, restricted to Pentium](https://wiki.netbsd.org/ports/i386/) |
+| `i686-unknown-netbsd`          | [32-bit i386 with SSE](https://wiki.netbsd.org/ports/i386/) |
+| `mipsel-unknown-netbsd`        | [32-bit mips, requires mips32 cpu support](https://wiki.netbsd.org/ports/evbmips/) |
+| `powerpc-unknown-netbsd`       | [Various 32-bit PowerPC systems, e.g. MacPPC](https://wiki.netbsd.org/ports/macppc/) |
+| `sparc64-unknown-netbsd`       | [Sun UltraSPARC systems](https://wiki.netbsd.org/ports/sparc64/) |
+
+All use the "native" `stdc++` library which goes along with the natively
+supplied GNU C++ compiler for the given OS version.  Many of the bootstraps
+are built for NetBSD 9.x, although some exceptions exist (some
+are built for NetBSD 8.x but also work on newer OS versions).
+
+
+## Designated Developers
+
+- [@he32](https://github.com/he32), `he@NetBSD.org`
+- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust
+- [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc.
+- [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself
+
+Fallback to pkgsrc-users@NetBSD.org, or fault reporting via NetBSD's
+bug reporting system.
+
+## Requirements
+
+The `amd64-unknown-netbsd` artifacts is being distributed by the
+rust project.
+
+The other targets are built by the designated developers (see above),
+and the targets are initially cross-compiled, but many if not most
+of them are also built natively as part of testing.
+
+
+## Building
+
+The default build mode for the packages is a native build.
+
+
+## Cross-compilation
+
+These targets can be cross-compiled, and we do that via the pkgsrc
+package(s).
+
+Cross-compilation typically requires the "tools" and "dest" trees
+resulting from a normal cross-build of NetBSD itself, ref. our main
+build script, `build.sh`.
+
+See e.g. [do-cross.mk
+Makefile](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust/do-cross.mk)
+for the Makefile used to cross-build all the above NetBSD targets
+(except for the `amd64` target).
+
+The major option for the rust build is whether to build rust with
+the LLVM rust carries in its distribution, or use the LLVM package
+installed from pkgsrc.  The `PKG_OPTIONS.rust` option is
+`rust-internal-llvm`, ref.  [the rust package's options.mk make
+fragment](https://github.com/NetBSD/pkgsrc/blob/trunk/lang/rust/options.mk).
+It defaults to being set for a few of the above platforms, for
+various reasons (see comments), but is otherwise unset and therefore
+indicates use of the pkgsrc LLVM.
+
+
+## Testing
+
+The Rust testsuite could presumably be run natively.
+
+For the systems where the maintainer can build natively, the rust
+compiler itself is re-built natively.  This involves the rust compiler
+being re-built with the newly self-built rust compiler, so excercises
+the result quite extensively.
+
+Additionally, for some systems we build `librsvg`, and for the more
+capable systems we build and test `firefox` (amd64, i386, aarch64).
+
+
+## Building Rust programs
+
+Rust ships pre-compiled artifacts for the `amd64-unknown-netbsd`
+target.
+
+For the other systems mentioned above, using the `pkgsrc` route is
+probably the easiest, possibly via the `rust-bin` package to save
+time, see the `RUST_TYPE` variable from the `rust.mk` Makefile
+fragment.
+
+The pkgsrc rust package has a few files to assist with building
+pkgsrc packages written in rust, ref. the `rust.mk` and `cargo.mk`
+Makefile fragments in the `lang/rust` package.
diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md
index 62a5a032f07..9bc521e1c7b 100644
--- a/src/doc/style-guide/src/statements.md
+++ b/src/doc/style-guide/src/statements.md
@@ -103,22 +103,69 @@ let Foo {
 
 #### else blocks (let-else statements)
 
-If a let statement contains an `else` component, also known as a let-else statement,
-then the `else` component should be formatted according to the same rules as the `else` block
-in [control flow expressions (i.e. if-else, and if-let-else expressions)](./expressions.md#control-flow-expressions).
-Apply the same formatting rules to the components preceding
-the `else` block (i.e. the `let pattern: Type = initializer_expr ...` portion)
-as described [above](#let-statements)
-
-Similarly to if-else expressions, if the initializer
-expression is multi-lined, then the `else` keyword and opening brace of the block (i.e. `else {`)
-should be put on the same line as the end of the initializer
-expression with a preceding space if all the following are true:
+A let statement can contain an `else` component, making it a let-else statement.
+In this case, always apply the same formatting rules to the components preceding
+the `else` block (i.e. the `let pattern: Type = initializer_expr` portion)
+as described [for other let statements](#let-statements).
+
+The entire let-else statement may be formatted on a single line if all the
+following are true:
+
+* the entire statement is *short*
+* the `else` block contains only a single-line expression and no statements
+* the `else` block contains no comments
+* the let statement components preceding the `else` block can be formatted on a single line
+
+```rust
+let Some(1) = opt else { return };
+```
+
+Formatters may allow users to configure the value of the threshold
+used to determine whether a let-else statement is *short*.
+
+Otherwise, the let-else statement requires some line breaks.
+
+If breaking a let-else statement across multiple lines, never break between the
+`else` and the `{`, and always break before the `}`.
+
+If the let statement components preceding the `else` can be formatted on a
+single line, but the let-else does not qualify to be placed entirely on a
+single line, put the `else {` on the same line as the initializer expression,
+with a space between them, then break the line after the `{`. Indent the
+closing `}` to match the `let`, and indent the contained block one step
+further.
+
+```rust
+let Some(1) = opt else {
+    return;
+};
+
+let Some(1) = opt else {
+    // nope
+    return
+};
+```
+
+If the let statement components preceding the `else` can be formatted on a
+single line, but the `else {` does not fit on the same line, break the line
+before the `else`.
+
+```rust
+    let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name
+    else {
+        return;
+    };
+```
+
+If the initializer expression is multi-line, the `else` keyword and opening
+brace of the block (i.e. `else {`) should be put on the same line as the end of
+the initializer expression, with a space between them, if all the following are
+true:
 
 * The initializer expression ends with one or more closing
   parentheses, square brackets, and/or braces
 * There is nothing else on that line
-* That line is not indented beyond the indent of the first line containing the `let` keyword
+* That line has the same indentation level as the initial `let` keyword.
 
 For example:
 
@@ -135,7 +182,9 @@ let Some(x) = y.foo(
 }
 ```
 
-Otherwise, the `else` keyword and opening brace should be placed on the next line after the end of the initializer expression, and should not be indented (the `else` keyword should be aligned with the `let` keyword).
+Otherwise, the `else` keyword and opening brace should be placed on the next
+line after the end of the initializer expression, and the `else` keyword should
+have the same indentation level as the `let` keyword.
 
 For example:
 
@@ -155,11 +204,6 @@ fn main() {
         return
     };
 
-    let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name
-    else {
-        return;
-    };
-
     let Some(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =
         bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
     else {
@@ -168,31 +212,6 @@ fn main() {
 }
 ```
 
-##### Single line let-else statements
-
-The entire let-else statement may be formatted on a single line if all the following are true:
-
-* the entire statement is *short*
-* the `else` block contains a single-line expression and no statements
-* the `else` block contains no comments
-* the let statement components preceding the `else` block can be formatted on a single line
-
-```rust
-let Some(1) = opt else { return };
-
-let Some(1) = opt else {
-    return;
-};
-
-let Some(1) = opt else {
-    // nope
-    return
-};
-```
-
-Formatters may allow users to configure the value of the threshold
-used to determine whether a let-else statement is *short*.
-
 ### Macros in statement position
 
 A macro use in statement position should use parentheses or square brackets as
diff --git a/src/etc/test-float-parse/runtests.py b/src/etc/test-float-parse/runtests.py
index cf7279534dc..cc5e31a051f 100755
--- a/src/etc/test-float-parse/runtests.py
+++ b/src/etc/test-float-parse/runtests.py
@@ -127,7 +127,7 @@ def write_errors():
         if not have_seen_error:
             have_seen_error = True
             msg("Something is broken:", *args)
-            msg("Future errors logged to errors.txt")
+            msg("Future errors will be logged to errors.txt")
             exit_status = 101
 
 
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 492b0b79557..92bae551644 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -317,14 +317,14 @@ where
         lifetime_predicates
     }
 
-    fn extract_for_generics(&self, pred: ty::Predicate<'tcx>) -> FxHashSet<GenericParamDef> {
+    fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet<GenericParamDef> {
         let bound_predicate = pred.kind();
         let tcx = self.cx.tcx;
         let regions = match bound_predicate.skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_pred)) => {
+            ty::ClauseKind::Trait(poly_trait_pred) => {
                 tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred))
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(poly_proj_pred)) => {
+            ty::ClauseKind::Projection(poly_proj_pred) => {
                 tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred))
             }
             _ => return FxHashSet::default(),
@@ -449,9 +449,7 @@ where
             .filter(|p| {
                 !orig_bounds.contains(p)
                     || match p.kind().skip_binder() {
-                        ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
-                            pred.def_id() == sized_trait
-                        }
+                        ty::ClauseKind::Trait(pred) => pred.def_id() == sized_trait,
                         _ => false,
                     }
             })
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f86c32158e0..b2f9c0bccea 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -326,36 +326,24 @@ fn clean_where_predicate<'tcx>(
 }
 
 pub(crate) fn clean_predicate<'tcx>(
-    predicate: ty::Predicate<'tcx>,
+    predicate: ty::Clause<'tcx>,
     cx: &mut DocContext<'tcx>,
 ) -> Option<WherePredicate> {
     let bound_predicate = predicate.kind();
     match bound_predicate.skip_binder() {
-        ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
-            clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
-        }
-        ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(pred)) => {
-            clean_region_outlives_predicate(pred)
-        }
-        ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(pred)) => {
+        ty::ClauseKind::Trait(pred) => clean_poly_trait_predicate(bound_predicate.rebind(pred), cx),
+        ty::ClauseKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
+        ty::ClauseKind::TypeOutlives(pred) => {
             clean_type_outlives_predicate(bound_predicate.rebind(pred), cx)
         }
-        ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
+        ty::ClauseKind::Projection(pred) => {
             Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
         }
         // FIXME(generic_const_exprs): should this do something?
-        ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => None,
-        ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => None,
-        ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None,
-
-        ty::PredicateKind::Subtype(..)
-        | ty::PredicateKind::AliasRelate(..)
-        | ty::PredicateKind::Coerce(..)
-        | ty::PredicateKind::ObjectSafe(..)
-        | ty::PredicateKind::ClosureKind(..)
-        | ty::PredicateKind::ConstEquate(..)
-        | ty::PredicateKind::Ambiguous
-        | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
+        ty::ClauseKind::ConstEvaluatable(..)
+        | ty::ClauseKind::WellFormed(..)
+        | ty::ClauseKind::ConstArgHasType(..)
+        | ty::ClauseKind::TypeWellFormedFromEnv(..) => None,
     }
 }
 
@@ -791,10 +779,10 @@ fn clean_ty_generics<'tcx>(
         })
         .collect::<ThinVec<GenericParamDef>>();
 
-    // param index -> [(trait DefId, associated type name & generics, type, higher-ranked params)]
+    // param index -> [(trait DefId, associated type name & generics, term, higher-ranked params)]
     let mut impl_trait_proj = FxHashMap::<
         u32,
-        Vec<(DefId, PathSegment, ty::Binder<'_, Ty<'_>>, Vec<GenericParamDef>)>,
+        Vec<(DefId, PathSegment, ty::Binder<'_, ty::Term<'_>>, Vec<GenericParamDef>)>,
     >::default();
 
     let where_predicates = preds
@@ -805,19 +793,17 @@ fn clean_ty_generics<'tcx>(
             let param_idx = (|| {
                 let bound_p = p.kind();
                 match bound_p.skip_binder() {
-                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
+                    ty::ClauseKind::Trait(pred) => {
                         if let ty::Param(param) = pred.self_ty().kind() {
                             return Some(param.index);
                         }
                     }
-                    ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
-                        ty::OutlivesPredicate(ty, _reg),
-                    )) => {
+                    ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
                         if let ty::Param(param) = ty.kind() {
                             return Some(param.index);
                         }
                     }
-                    ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
+                    ty::ClauseKind::Projection(p) => {
                         if let ty::Param(param) = p.projection_ty.self_ty().kind() {
                             projection = Some(bound_p.rebind(p));
                             return Some(param.index);
@@ -852,11 +838,10 @@ fn clean_ty_generics<'tcx>(
                     .as_ref()
                     .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs)))
                 {
-                    // FIXME(...): Remove this unwrap()
                     impl_trait_proj.entry(param_idx).or_default().push((
                         trait_did,
                         name,
-                        rhs.map_bound(|rhs| rhs.ty().unwrap()),
+                        *rhs,
                         p.get_bound_params()
                             .into_iter()
                             .flatten()
@@ -879,15 +864,8 @@ fn clean_ty_generics<'tcx>(
         let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() };
         if let Some(proj) = impl_trait_proj.remove(&idx) {
             for (trait_did, name, rhs, bound_params) in proj {
-                let rhs = clean_middle_ty(rhs, cx, None, None);
-                simplify::merge_bounds(
-                    cx,
-                    &mut bounds,
-                    bound_params,
-                    trait_did,
-                    name,
-                    &Term::Type(rhs),
-                );
+                let rhs = clean_middle_term(rhs, cx);
+                simplify::merge_bounds(cx, &mut bounds, bound_params, trait_did, name, &rhs);
             }
         }
 
@@ -1360,21 +1338,51 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                 }
             }
 
+            let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
             if let ty::TraitContainer = assoc_item.container {
-                let bounds = tcx
-                    .explicit_item_bounds(assoc_item.def_id)
-                    .subst_identity_iter_copied()
-                    .map(|(c, s)| (c.as_predicate(), s));
-                let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
-                let predicates =
-                    tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
-                let mut generics = clean_ty_generics(
-                    cx,
-                    tcx.generics_of(assoc_item.def_id),
-                    ty::GenericPredicates { parent: None, predicates },
-                );
-                // Filter out the bounds that are (likely?) directly attached to the associated type,
-                // as opposed to being located in the where clause.
+                let bounds =
+                    tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied();
+                predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
+            }
+            let mut generics = clean_ty_generics(
+                cx,
+                tcx.generics_of(assoc_item.def_id),
+                ty::GenericPredicates { parent: None, predicates },
+            );
+            // Move bounds that are (likely) directly attached to the parameters of the
+            // (generic) associated type from the where clause to the respective parameter.
+            // There is no guarantee that this is what the user actually wrote but we have
+            // no way of knowing.
+            let mut where_predicates = ThinVec::new();
+            for mut pred in generics.where_predicates {
+                if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
+                    && let Some(GenericParamDef {
+                        kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
+                        ..
+                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
+                {
+                    param_bounds.append(bounds);
+                } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
+                    && let Some(GenericParamDef {
+                        kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
+                        ..
+                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
+                {
+                    param_bounds.extend(bounds.drain(..).map(|bound| match bound {
+                        GenericBound::Outlives(lifetime) => lifetime,
+                        _ => unreachable!(),
+                    }));
+                } else {
+                    where_predicates.push(pred);
+                }
+            }
+            generics.where_predicates = where_predicates;
+
+            if let ty::TraitContainer = assoc_item.container {
+                // Move bounds that are (likely) directly attached to the associated type
+                // from the where-clause to the associated type.
+                // There is no guarantee that this is what the user actually wrote but we have
+                // no way of knowing.
                 let mut bounds: Vec<GenericBound> = Vec::new();
                 generics.where_predicates.retain_mut(|pred| match *pred {
                     WherePredicate::BoundPredicate {
@@ -1431,33 +1439,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                     }
                     None => bounds.push(GenericBound::maybe_sized(cx)),
                 }
-                // Move bounds that are (likely) directly attached to the parameters of the
-                // (generic) associated type from the where clause to the respective parameter.
-                // There is no guarantee that this is what the user actually wrote but we have
-                // no way of knowing.
-                let mut where_predicates = ThinVec::new();
-                for mut pred in generics.where_predicates {
-                    if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
-                    && let Some(GenericParamDef {
-                        kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
-                        ..
-                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
-                    {
-                        param_bounds.append(bounds);
-                    } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
-                    && let Some(GenericParamDef {
-                        kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
-                        ..
-                    }) = generics.params.iter_mut().find(|param| &param.name == arg) {
-                        param_bounds.extend(bounds.drain(..).map(|bound| match bound {
-                            GenericBound::Outlives(lifetime) => lifetime,
-                            _ => unreachable!(),
-                        }));
-                    } else {
-                        where_predicates.push(pred);
-                    }
-                }
-                generics.where_predicates = where_predicates;
 
                 if tcx.defaultness(assoc_item.def_id).has_value() {
                     AssocTypeItem(
@@ -1469,7 +1450,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                                 None,
                             ),
                             generics,
-                            // FIXME: should we obtain the Type from HIR and pass it on here?
                             item_type: None,
                         }),
                         bounds,
@@ -1478,7 +1458,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                     TyAssocTypeItem(generics, bounds)
                 }
             } else {
-                // FIXME: when could this happen? Associated items in inherent impls?
                 AssocTypeItem(
                     Box::new(Typedef {
                         type_: clean_middle_ty(
@@ -1487,12 +1466,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                             Some(assoc_item.def_id),
                             None,
                         ),
-                        generics: Generics {
-                            params: ThinVec::new(),
-                            where_predicates: ThinVec::new(),
-                        },
+                        generics,
                         item_type: None,
                     }),
+                    // Associated types inside trait or inherent impls are not allowed to have
+                    // item bounds. Thus we don't attempt to move any bounds there.
                     Vec::new(),
                 )
             }
@@ -2377,7 +2355,7 @@ fn filter_tokens_from_list(
     tokens
 }
 
-/// When inlining items, we merge its attributes (and all the reexports attributes too) with the
+/// When inlining items, we merge their attributes (and all the reexports attributes too) with the
 /// final reexport. For example:
 ///
 /// ```ignore (just an example)
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index a8221cc9449..65b1b72adc1 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -128,9 +128,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
         .predicates
         .iter()
         .filter_map(|(pred, _)| {
-            if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
-                pred.kind().skip_binder()
-            {
+            if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() {
                 if pred.trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { None }
             } else {
                 None
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5f5cade67a2..26139d52769 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -956,6 +956,8 @@ pub(crate) trait AttributesExt {
                     .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
                     .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
             } else if doc_auto_cfg_active {
+                // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
+                // `doc(cfg())` overrides `cfg()`).
                 self.iter()
                     .filter(|attr| attr.has_name(sym::cfg))
                     .filter_map(|attr| single(attr.meta_item_list()?))
@@ -2387,6 +2389,7 @@ impl ImplKind {
 #[derive(Clone, Debug)]
 pub(crate) struct Import {
     pub(crate) kind: ImportKind,
+    /// The item being re-exported.
     pub(crate) source: ImportSource,
     pub(crate) should_be_displayed: bool,
 }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 9f08609a6d1..217f1a6ee6b 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -15,6 +15,7 @@ use rustc_session::config::{
 use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
+use rustc_session::EarlyErrorHandler;
 use rustc_span::edition::Edition;
 use rustc_target::spec::TargetTriple;
 
@@ -311,32 +312,33 @@ impl Options {
     /// Parses the given command-line for options. If an error message or other early-return has
     /// been printed, returns `Err` with the exit code.
     pub(crate) fn from_matches(
+        handler: &mut EarlyErrorHandler,
         matches: &getopts::Matches,
         args: Vec<String>,
     ) -> Result<(Options, RenderOptions), i32> {
         // Check for unstable options.
-        nightly_options::check_nightly_options(matches, &opts());
+        nightly_options::check_nightly_options(handler, matches, &opts());
 
         if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") {
             crate::usage("rustdoc");
             return Err(0);
         } else if matches.opt_present("version") {
-            rustc_driver::version!("rustdoc", matches);
+            rustc_driver::version!(&handler, "rustdoc", matches);
             return Err(0);
         }
 
-        if rustc_driver::describe_flag_categories(&matches) {
+        if rustc_driver::describe_flag_categories(handler, &matches) {
             return Err(0);
         }
 
-        let color = config::parse_color(matches);
+        let color = config::parse_color(handler, matches);
         let config::JsonConfig { json_rendered, json_unused_externs, .. } =
-            config::parse_json(matches);
-        let error_format = config::parse_error_format(matches, color, json_rendered);
+            config::parse_json(handler, matches);
+        let error_format = config::parse_error_format(handler, matches, color, json_rendered);
         let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
 
-        let codegen_options = CodegenOptions::build(matches, error_format);
-        let unstable_opts = UnstableOptions::build(matches, error_format);
+        let codegen_options = CodegenOptions::build(handler, matches);
+        let unstable_opts = UnstableOptions::build(handler, matches);
 
         let diag = new_handler(error_format, None, diagnostic_width, &unstable_opts);
 
@@ -393,8 +395,7 @@ impl Options {
             && !matches.opt_present("show-coverage")
             && !nightly_options::is_unstable_enabled(matches)
         {
-            rustc_session::early_error(
-                error_format,
+            handler.early_error(
                 "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)",
             );
         }
@@ -432,7 +433,7 @@ impl Options {
             return Err(0);
         }
 
-        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches);
 
         let input = PathBuf::from(if describe_lints {
             "" // dummy, this won't be used
@@ -446,12 +447,9 @@ impl Options {
             &matches.free[0]
         });
 
-        let libs = matches
-            .opt_strs("L")
-            .iter()
-            .map(|s| SearchPath::from_cli_opt(s, error_format))
-            .collect();
-        let externs = parse_externs(matches, &unstable_opts, error_format);
+        let libs =
+            matches.opt_strs("L").iter().map(|s| SearchPath::from_cli_opt(handler, s)).collect();
+        let externs = parse_externs(handler, matches, &unstable_opts);
         let extern_html_root_urls = match parse_extern_html_roots(matches) {
             Ok(ex) => ex,
             Err(err) => {
@@ -589,7 +587,7 @@ impl Options {
             }
         }
 
-        let edition = config::parse_crate_edition(matches);
+        let edition = config::parse_crate_edition(handler, matches);
 
         let mut id_map = html::markdown::IdMap::new();
         let Some(external_html) = ExternalHtml::load(
@@ -623,7 +621,7 @@ impl Options {
             }
         }
 
-        let target = parse_target_triple(matches, error_format);
+        let target = parse_target_triple(handler, matches);
 
         let show_coverage = matches.opt_present("show-coverage");
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index e10a6297775..9687b8b1887 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -13,8 +13,8 @@ use rustc_interface::interface;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
-use rustc_session::lint;
 use rustc_session::Session;
+use rustc_session::{lint, EarlyErrorHandler};
 use rustc_span::symbol::sym;
 use rustc_span::{source_map, Span};
 
@@ -181,6 +181,7 @@ pub(crate) fn new_handler(
 
 /// Parse, resolve, and typecheck the given crate.
 pub(crate) fn create_config(
+    handler: &EarlyErrorHandler,
     RustdocOptions {
         input,
         crate_name,
@@ -258,8 +259,8 @@ pub(crate) fn create_config(
 
     interface::Config {
         opts: sessopts,
-        crate_cfg: interface::parse_cfgspecs(cfgs),
-        crate_check_cfg: interface::parse_check_cfg(check_cfgs),
+        crate_cfg: interface::parse_cfgspecs(handler, cfgs),
+        crate_check_cfg: interface::parse_check_cfg(handler, check_cfgs),
         input,
         output_file: None,
         output_dir: None,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index f6631b66f5b..217257316c8 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -12,7 +12,7 @@ use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_parse::parser::attr::InnerAttrPolicy;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::parse::ParseSess;
-use rustc_session::{lint, Session};
+use rustc_session::{lint, EarlyErrorHandler, Session};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
@@ -85,13 +85,18 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         ..config::Options::default()
     };
 
+    let early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     let mut cfgs = options.cfgs.clone();
     cfgs.push("doc".to_owned());
     cfgs.push("doctest".to_owned());
     let config = interface::Config {
         opts: sessopts,
-        crate_cfg: interface::parse_cfgspecs(cfgs),
-        crate_check_cfg: interface::parse_check_cfg(options.check_cfgs.clone()),
+        crate_cfg: interface::parse_cfgspecs(&early_error_handler, cfgs),
+        crate_check_cfg: interface::parse_check_cfg(
+            &early_error_handler,
+            options.check_cfgs.clone(),
+        ),
         input,
         output_file: None,
         output_dir: None,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index b710311c858..b4aba2993c7 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1408,7 +1408,7 @@ impl clean::FnDecl {
         let amp = if f.alternate() { "&" } else { "&amp;" };
 
         write!(f, "(")?;
-        if let Some(n) = line_wrapping_indent {
+        if let Some(n) = line_wrapping_indent && !self.inputs.values.is_empty() {
             write!(f, "\n{}", Indent(n + 4))?;
         }
         for (i, input) in self.inputs.values.iter().enumerate() {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 21c1eb631e0..b6d90091bba 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -891,8 +891,10 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	color: var(--search-results-grey-color);
 }
 .search-results .result-name .typename {
+	display: inline-block;
 	color: var(--search-results-grey-color);
 	font-size: 0.875rem;
+	width: 6.25rem;
 }
 
 .popover {
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 452348dc865..b8cc0a6db71 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -52,9 +52,9 @@ const longItemTypes = [
     "enum variant",
     "macro",
     "primitive type",
-    "associated type",
+    "assoc type",
     "constant",
-    "associated constant",
+    "assoc const",
     "union",
     "foreign type",
     "keyword",
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index a8cd0ec453e..f28deae791a 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -79,8 +79,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_interface::interface;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
-use rustc_session::getopts;
-use rustc_session::{early_error, early_warn};
+use rustc_session::{getopts, EarlyErrorHandler};
 
 use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
 
@@ -155,6 +154,8 @@ pub fn main() {
         }
     }
 
+    let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     rustc_driver::install_ice_hook(
         "https://github.com/rust-lang/rust/issues/new\
     ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
@@ -170,11 +171,12 @@ pub fn main() {
     // NOTE: The reason this doesn't show double logging when `download-rustc = false` and
     // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
     // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
-    init_logging();
-    rustc_driver::init_env_logger("RUSTDOC_LOG");
 
-    let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() {
-        Some(args) => main_args(&args),
+    init_logging(&handler);
+    rustc_driver::init_env_logger(&handler, "RUSTDOC_LOG");
+
+    let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&handler) {
+        Some(args) => main_args(&mut handler, &args),
         _ =>
         {
             #[allow(deprecated)]
@@ -184,22 +186,19 @@ pub fn main() {
     process::exit(exit_code);
 }
 
-fn init_logging() {
+fn init_logging(handler: &EarlyErrorHandler) {
     let color_logs = match std::env::var("RUSTDOC_LOG_COLOR").as_deref() {
         Ok("always") => true,
         Ok("never") => false,
         Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(),
-        Ok(value) => early_error(
-            ErrorOutputType::default(),
-            format!("invalid log color value '{}': expected one of always, never, or auto", value),
-        ),
-        Err(VarError::NotUnicode(value)) => early_error(
-            ErrorOutputType::default(),
-            format!(
-                "invalid log color value '{}': expected one of always, never, or auto",
-                value.to_string_lossy()
-            ),
-        ),
+        Ok(value) => handler.early_error(format!(
+            "invalid log color value '{}': expected one of always, never, or auto",
+            value
+        )),
+        Err(VarError::NotUnicode(value)) => handler.early_error(format!(
+            "invalid log color value '{}': expected one of always, never, or auto",
+            value.to_string_lossy()
+        )),
     };
     let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG");
     let layer = tracing_tree::HierarchicalLayer::default()
@@ -219,16 +218,13 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).unwrap();
 }
 
-fn get_args() -> Option<Vec<String>> {
+fn get_args(handler: &EarlyErrorHandler) -> Option<Vec<String>> {
     env::args_os()
         .enumerate()
         .map(|(i, arg)| {
             arg.into_string()
                 .map_err(|arg| {
-                    early_warn(
-                        ErrorOutputType::default(),
-                        format!("Argument {} is not valid Unicode: {:?}", i, arg),
-                    );
+                    handler.early_warn(format!("Argument {} is not valid Unicode: {:?}", i, arg));
                 })
                 .ok()
         })
@@ -710,7 +706,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     }
 }
 
-fn main_args(at_args: &[String]) -> MainResult {
+fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult {
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
     // passing empty argument array to execve under some platforms,
@@ -721,7 +717,7 @@ fn main_args(at_args: &[String]) -> MainResult {
     // the compiler with @empty_file as argv[0] and no more arguments.
     let at_args = at_args.get(1..).unwrap_or_default();
 
-    let args = rustc_driver::args::arg_expand_all(at_args);
+    let args = rustc_driver::args::arg_expand_all(handler, at_args);
 
     let mut options = getopts::Options::new();
     for option in opts() {
@@ -730,13 +726,13 @@ fn main_args(at_args: &[String]) -> MainResult {
     let matches = match options.parse(&args) {
         Ok(m) => m,
         Err(err) => {
-            early_error(ErrorOutputType::default(), err.to_string());
+            handler.early_error(err.to_string());
         }
     };
 
     // Note that we discard any distinction between different non-zero exit
     // codes from `from_matches` here.
-    let (options, render_options) = match config::Options::from_matches(&matches, args) {
+    let (options, render_options) = match config::Options::from_matches(handler, &matches, args) {
         Ok(opts) => opts,
         Err(code) => {
             return if code == 0 {
@@ -764,7 +760,7 @@ fn main_args(at_args: &[String]) -> MainResult {
         (false, true) => {
             let input = options.input.clone();
             let edition = options.edition;
-            let config = core::create_config(options, &render_options);
+            let config = core::create_config(handler, options, &render_options);
 
             // `markdown::render` can invoke `doctest::make_test`, which
             // requires session globals and a thread pool, so we use
@@ -797,7 +793,7 @@ fn main_args(at_args: &[String]) -> MainResult {
     let scrape_examples_options = options.scrape_examples_options.clone();
     let bin_crate = options.bin_crate;
 
-    let config = core::create_config(options, &render_options);
+    let config = core::create_config(handler, options, &render_options);
 
     interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index ee6aef71980..1ecaa1a123c 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -27,7 +27,7 @@ use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
     self, Binder, BoundVariableKind, ClauseKind, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
-    PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
+    ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::sym, Span, Symbol};
@@ -1133,7 +1133,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
     let projection_predicates = predicates
         .iter()
         .filter_map(|predicate| {
-            if let PredicateKind::Clause(ClauseKind::Projection(projection_predicate)) = predicate.kind().skip_binder() {
+            if let ClauseKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
                 Some(projection_predicate)
             } else {
                 None
@@ -1147,7 +1147,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
     if predicates
         .iter()
         .filter_map(|predicate| {
-            if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder()
+            if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
                 && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx)
             {
                 Some(trait_predicate.trait_ref.def_id)
@@ -1209,7 +1209,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
         }
 
         predicates.iter().all(|predicate| {
-            if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder()
+            if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
                 && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
                 && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
                 && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 8d84e756ff8..10a2f0cb1e7 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, Binder, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind,
-    TraitPredicate, Ty, TyCtxt,
+    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
+    ToPredicate, TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
@@ -503,7 +503,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
 
     let ty_predicates = tcx.predicates_of(did).predicates;
     for (p, _) in ty_predicates {
-        if let PredicateKind::Clause(ClauseKind::Trait(p)) = p.kind().skip_binder()
+        if let ClauseKind::Trait(p) = p.kind().skip_binder()
             && p.trait_ref.def_id == eq_trait_id
             && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
             && p.constness == BoundConstness::NotConst
@@ -514,13 +514,13 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
     }
 
     ParamEnv::new(
-        tcx.mk_predicates_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
+        tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
-                tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
+                ClauseKind::Trait(TraitPredicate {
                     trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
-                }))))
+                }).to_predicate(tcx)
             }),
         )),
         Reveal::UserFacing,
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 5f1fdf00be8..10b5e1edf92 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -206,6 +206,12 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
                 NeverLoopResult::AlwaysBreak,
             )
         }),
+        ExprKind::Become(e) => {
+            combine_seq(
+                never_loop_expr(e, ignore_ids, main_loop_id),
+                NeverLoopResult::AlwaysBreak,
+            )
+        }
         ExprKind::InlineAsm(asm) => asm
             .operands
             .iter()
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 7945275393c..93ef07d36ae 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -329,6 +329,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
             ExprKind::Field(..) |
             ExprKind::Index(..) |
             ExprKind::Ret(..) |
+            ExprKind::Become(..) |
             ExprKind::Repeat(..) |
             ExprKind::Yield(..) => walk_expr(self, ex),
             ExprKind::AddrOf(_, _, _) |
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index cf85d3174db..0699997d0d2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -16,7 +16,7 @@ use rustc_hir::{
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty};
+use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol};
 
@@ -175,7 +175,7 @@ fn check_collect_into_intoiterator<'tcx>(
                 .caller_bounds()
                 .into_iter()
                 .filter_map(|p| {
-                    if let PredicateKind::Clause(ClauseKind::Trait(t)) = p.kind().skip_binder()
+                    if let ClauseKind::Trait(t) = p.kind().skip_binder()
                             && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) {
                                 Some(t.self_ty())
                             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 06fa95cd657..80eb00a1b42 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -14,7 +14,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, ProjectionPredicate, TraitPredicate, Ty};
 use rustc_span::{sym, Symbol};
 use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
 
@@ -345,12 +345,12 @@ fn get_input_traits_and_projections<'tcx>(
     let mut projection_predicates = Vec::new();
     for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() {
         match predicate.kind().skip_binder() {
-            PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) => {
+            ClauseKind::Trait(trait_predicate) => {
                 if trait_predicate.trait_ref.self_ty() == input {
                     trait_predicates.push(trait_predicate);
                 }
             },
-            PredicateKind::Clause(ClauseKind::Projection(projection_predicate)) => {
+            ClauseKind::Projection(projection_predicate) => {
                 if projection_predicate.projection_ty.self_ty() == input {
                     projection_predicates.push(projection_predicate);
                 }
@@ -407,7 +407,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
 
                         let mut trait_predicates = cx.tcx.param_env(callee_def_id)
                             .caller_bounds().iter().filter(|predicate| {
-                            if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate))
+                            if let ClauseKind::Trait(trait_predicate)
                                     = predicate.kind().skip_binder()
                                 && trait_predicate.trait_ref.self_ty() == *param_ty
                             {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 3773975e955..c0970048cdf 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
             .filter_map(|pred| {
                 // Note that we do not want to deal with qualified predicates here.
                 match pred.kind().no_bound_vars() {
-                    Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) if pred.def_id() != sized_trait => {
+                    Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => {
                         Some(pred)
                     },
                     _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index a375e5d5b4c..99a1d197678 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -4,7 +4,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_middle::ty::{ClauseKind, GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
+use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, BytePos, Span};
 
@@ -45,7 +45,7 @@ fn get_trait_predicates_for_trait_id<'tcx>(
     let mut preds = Vec::new();
     for (pred, _) in generics.predicates {
         if_chain! {
-            if let PredicateKind::Clause(ClauseKind::Trait(poly_trait_pred)) = pred.kind().skip_binder();
+            if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder();
             let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred));
             if let Some(trait_def_id) = trait_id;
             if trait_def_id == trait_pred.trait_ref.def_id;
@@ -63,7 +63,7 @@ fn get_projection_pred<'tcx>(
     trait_pred: TraitPredicate<'tcx>,
 ) -> Option<ProjectionPredicate<'tcx>> {
     generics.predicates.iter().find_map(|(proj_pred, _)| {
-        if let ty::PredicateKind::Clause(ClauseKind::Projection(pred)) = proj_pred.kind().skip_binder() {
+        if let ClauseKind::Projection(pred) = proj_pred.kind().skip_binder() {
             let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred));
             if projection_pred.projection_ty.substs == trait_pred.trait_ref.substs {
                 return Some(projection_pred);
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 3c2bf5abab2..6b51974d739 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -559,6 +559,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Ret({value})");
                 value.if_some(|e| self.expr(e));
             },
+            ExprKind::Become(value) => {
+                bind!(self, value);
+                kind!("Become({value})");
+                self.expr(value);
+            },
             ExprKind::InlineAsm(_) => {
                 kind!("InlineAsm(_)");
                 out!("// unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment");
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 941df3318ae..659c693f87a 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{def_id::DefId, Block, Expr, ExprKind, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, PredicateKind};
+use rustc_middle::ty;
 use rustc_span::{sym, Symbol};
 use std::cmp;
 use std::ops;
@@ -73,7 +73,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
             .flat_map(|v| v.fields.iter())
             .any(|x| matches!(cx.tcx.type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_)))
             && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() {
-                PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
+                ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
                 _ => true,
             })
             && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
@@ -191,6 +191,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 ExprKind::Break(..)
                 | ExprKind::Continue(_)
                 | ExprKind::Ret(_)
+                | ExprKind::Become(_)
                 | ExprKind::InlineAsm(_)
                 | ExprKind::Yield(..)
                 | ExprKind::Err(_) => {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index a49246a7832..3e1d7356414 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -845,6 +845,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_expr(e);
                 }
             },
+            ExprKind::Become(f) => {
+                self.hash_expr(f);
+            },
             ExprKind::Path(ref qpath) => {
                 self.hash_qpath(qpath);
             },
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index a10eb8646af..b7e83ce6caa 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -21,35 +21,6 @@ type McfResult = Result<(), (Span, Cow<'static, str>)>;
 
 pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) -> McfResult {
     let def_id = body.source.def_id();
-    let mut current = def_id;
-    loop {
-        let predicates = tcx.predicates_of(current);
-        for (predicate, _) in predicates.predicates {
-            match predicate.kind().skip_binder() {
-                ty::PredicateKind::Clause(
-                    ty::ClauseKind::RegionOutlives(_)
-                    | ty::ClauseKind::TypeOutlives(_)
-                    | ty::ClauseKind::Projection(_)
-                    | ty::ClauseKind::Trait(..)
-                    | ty::ClauseKind::ConstArgHasType(..),
-                )
-                | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                | ty::PredicateKind::ConstEquate(..)
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
-                ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"),
-                ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
-                ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
-                ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
-                ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {predicate:#?}"),
-                ty::PredicateKind::Ambiguous => panic!("ambiguous predicate on function: {predicate:#?}"),
-            }
-        }
-        match predicates.parent {
-            Some(parent) => current = parent,
-            None => break,
-        }
-    }
 
     for local in &body.local_decls {
         check_ty(tcx, local.ty, local.source_info.span)?;
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index a87d58110b0..b38b9553558 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -147,6 +147,7 @@ impl<'a> Sugg<'a> {
             | hir::ExprKind::Path(..)
             | hir::ExprKind::Repeat(..)
             | hir::ExprKind::Ret(..)
+            | hir::ExprKind::Become(..)
             | hir::ExprKind::Struct(..)
             | hir::ExprKind::Tup(..)
             | hir::ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 2b185943c59..8d3aecd4785 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -17,7 +17,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
     self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv,
-    Predicate, PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
     TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
@@ -563,7 +563,7 @@ fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
 }
 
 /// Gets an iterator over all predicates which apply to the given item.
-pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(Predicate<'_>, Span)> {
+pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(ty::Clause<'_>, Span)> {
     let mut next_id = Some(id);
     iter::from_fn(move || {
         next_id.take().map(|id| {
@@ -665,7 +665,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
             cx,
             ty,
-            cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs).map(|c| c.as_predicate()),
+            cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs),
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
@@ -698,7 +698,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
 fn sig_from_bounds<'tcx>(
     cx: &LateContext<'tcx>,
     ty: Ty<'tcx>,
-    predicates: impl IntoIterator<Item = Predicate<'tcx>>,
+    predicates: impl IntoIterator<Item = ty::Clause<'tcx>>,
     predicates_id: Option<DefId>,
 ) -> Option<ExprFnSig<'tcx>> {
     let mut inputs = None;
@@ -707,7 +707,7 @@ fn sig_from_bounds<'tcx>(
 
     for pred in predicates {
         match pred.kind().skip_binder() {
-            PredicateKind::Clause(ty::ClauseKind::Trait(p))
+            ty::ClauseKind::Trait(p)
                 if (lang_items.fn_trait() == Some(p.def_id())
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id()))
@@ -720,7 +720,7 @@ fn sig_from_bounds<'tcx>(
                 }
                 inputs = Some(i);
             },
-            PredicateKind::Clause(ty::ClauseKind::Projection(p))
+            ty::ClauseKind::Projection(p)
                 if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty =>
             {
                 if output.is_some() {
@@ -937,7 +937,7 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
 }
 
 /// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
-pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool {
+pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [ty::Clause<'_>]) -> bool {
     let ty::Param(ty) = *ty.kind() else {
         return false;
     };
@@ -950,7 +950,7 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc
     predicates
         .iter()
         .try_fold(false, |found, p| {
-            if let PredicateKind::Clause(ty::ClauseKind::Trait(p)) = p.kind().skip_binder()
+            if let ty::ClauseKind::Trait(p) = p.kind().skip_binder()
             && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
             && ty.index == self_ty.index
         {
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 5dcd71cef12..8dafa723afa 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -651,6 +651,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
             // Either drops temporaries, jumps out of the current expression, or has no sub expression.
             ExprKind::DropTemps(_)
             | ExprKind::Ret(_)
+            | ExprKind::Become(_)
             | ExprKind::Break(..)
             | ExprKind::Yield(..)
             | ExprKind::Block(..)
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 3c5b6e12b96..f3cc94aeff0 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -16,6 +16,8 @@ extern crate rustc_session;
 extern crate rustc_span;
 
 use rustc_interface::interface;
+use rustc_session::EarlyErrorHandler;
+use rustc_session::config::ErrorOutputType;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Symbol;
 
@@ -187,7 +189,9 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne
 
 #[allow(clippy::too_many_lines)]
 pub fn main() {
-    rustc_driver::init_rustc_env_logger();
+    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
+    rustc_driver::init_rustc_env_logger(&handler);
 
     rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
         // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
index 4506d1550bd..db34e6bfa7b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
@@ -12,11 +12,6 @@ LL |     for reference in vec![1, 2, 3] {
 ...
 LL |         Some(reference) = cache.data.get(key) {
    |              ^^^^^^^^^ expected integer, found `&i32`
-   |
-help: consider dereferencing the borrow
-   |
-LL |         Some(*reference) = cache.data.get(key) {
-   |              +
 
 error[E0308]: mismatched types
   --> $DIR/ice-6250.rs:12:9
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 1b46c42fa4c..85a8fbcffbe 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -453,7 +453,7 @@ impl TargetCfgs {
         let mut all_families = HashSet::new();
         let mut all_pointer_widths = HashSet::new();
 
-        for (target, cfg) in targets.into_iter() {
+        for (target, cfg) in targets.iter() {
             all_archs.insert(cfg.arch.clone());
             all_oses.insert(cfg.os.clone());
             all_oses_and_envs.insert(cfg.os_and_env());
@@ -464,11 +464,11 @@ impl TargetCfgs {
             }
             all_pointer_widths.insert(format!("{}bit", cfg.pointer_width));
 
-            all_targets.insert(target.into());
+            all_targets.insert(target.clone());
         }
 
         Self {
-            current: Self::get_current_target_config(config),
+            current: Self::get_current_target_config(config, &targets),
             all_targets,
             all_archs,
             all_oses,
@@ -480,16 +480,20 @@ impl TargetCfgs {
         }
     }
 
-    fn get_current_target_config(config: &Config) -> TargetCfg {
-        let mut arch = None;
-        let mut os = None;
-        let mut env = None;
-        let mut abi = None;
-        let mut families = Vec::new();
-        let mut pointer_width = None;
-        let mut endian = None;
-        let mut panic = None;
-
+    fn get_current_target_config(
+        config: &Config,
+        targets: &HashMap<String, TargetCfg>,
+    ) -> TargetCfg {
+        let mut cfg = targets[&config.target].clone();
+
+        // To get the target information for the current target, we take the target spec obtained
+        // from `--print=all-target-specs-json`, and then we enrich it with the information
+        // gathered from `--print=cfg --target=$target`.
+        //
+        // This is done because some parts of the target spec can be overridden with `-C` flags,
+        // which are respected for `--print=cfg` but not for `--print=all-target-specs-json`. The
+        // code below extracts them from `--print=cfg`: make sure to only override fields that can
+        // actually be changed with `-C` flags.
         for config in
             rustc_output(config, &["--print=cfg", "--target", &config.target]).trim().lines()
         {
@@ -507,60 +511,16 @@ impl TargetCfgs {
                 })
                 .unwrap_or_else(|| (config, None));
 
-            match name {
-                "target_arch" => {
-                    arch = Some(value.expect("target_arch should be a key-value pair").to_string());
-                }
-                "target_os" => {
-                    os = Some(value.expect("target_os sould be a key-value pair").to_string());
-                }
-                "target_env" => {
-                    env = Some(value.expect("target_env should be a key-value pair").to_string());
-                }
-                "target_abi" => {
-                    abi = Some(value.expect("target_abi should be a key-value pair").to_string());
-                }
-                "target_family" => {
-                    families
-                        .push(value.expect("target_family should be a key-value pair").to_string());
-                }
-                "target_pointer_width" => {
-                    pointer_width = Some(
-                        value
-                            .expect("target_pointer_width should be a key-value pair")
-                            .parse::<u32>()
-                            .expect("target_pointer_width should be a valid u32"),
-                    );
-                }
-                "target_endian" => {
-                    endian = Some(match value.expect("target_endian should be a key-value pair") {
-                        "big" => Endian::Big,
-                        "little" => Endian::Little,
-                        _ => panic!("target_endian should be either 'big' or 'little'"),
-                    });
-                }
-                "panic" => {
-                    panic = Some(match value.expect("panic should be a key-value pair") {
-                        "abort" => PanicStrategy::Abort,
-                        "unwind" => PanicStrategy::Unwind,
-                        _ => panic!("panic should be either 'abort' or 'unwind'"),
-                    });
-                }
-                _ => (),
+            match (name, value) {
+                // Can be overridden with `-C panic=$strategy`.
+                ("panic", Some("abort")) => cfg.panic = PanicStrategy::Abort,
+                ("panic", Some("unwind")) => cfg.panic = PanicStrategy::Unwind,
+                ("panic", other) => panic!("unexpected value for panic cfg: {other:?}"),
+                _ => {}
             }
         }
 
-        TargetCfg {
-            arch: arch.expect("target configuration should specify target_arch"),
-            os: os.expect("target configuration should specify target_os"),
-            env: env.expect("target configuration should specify target_env"),
-            abi: abi.expect("target configuration should specify target_abi"),
-            families,
-            pointer_width: pointer_width
-                .expect("target configuration should specify target_pointer_width"),
-            endian: endian.expect("target configuration should specify target_endian"),
-            panic: panic.expect("target configuration should specify panic"),
-        }
+        cfg
     }
 }
 
@@ -582,6 +542,8 @@ pub struct TargetCfg {
     endian: Endian,
     #[serde(rename = "panic-strategy", default)]
     pub(crate) panic: PanicStrategy,
+    #[serde(default)]
+    pub(crate) dynamic_linking: bool,
 }
 
 impl TargetCfg {
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 18b3b913a68..0e306696a90 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -130,6 +130,11 @@ pub(super) fn handle_needs(
             condition: config.git_hash,
             ignore_reason: "ignored when git hashes have been omitted for building",
         },
+        Need {
+            name: "needs-dynamic-linking",
+            condition: config.target_cfg().dynamic_linking,
+            ignore_reason: "ignored on targets without dynamic linking",
+        },
     ];
 
     let (name, comment) = match ln.split_once([':', ' ']) {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 25b16e38e53..5c8ee7895d3 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1810,8 +1810,8 @@ impl<'test> TestCx<'test> {
             || self.config.target.contains("wasm32")
             || self.config.target.contains("nvptx")
             || self.is_vxworks_pure_static()
-            || self.config.target.contains("sgx")
             || self.config.target.contains("bpf")
+            || !self.config.target_cfg().dynamic_linking
         {
             // We primarily compile all auxiliary libraries as dynamic libraries
             // to avoid code size bloat and large binaries as much as possible
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index f984275b164..62a58576da5 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -1,6 +1,7 @@
 #![feature(rustc_private)]
 
 extern crate rustc_driver;
+extern crate rustc_session;
 
 use std::env;
 use std::error::Error;
@@ -170,7 +171,9 @@ fn parse_args() -> (OutputFormat, PathBuf) {
 }
 
 fn main() {
-    rustc_driver::init_env_logger("RUST_LOG");
+    let handler =
+        rustc_session::EarlyErrorHandler::new(rustc_session::config::ErrorOutputType::default());
+    rustc_driver::init_env_logger(&handler, "RUST_LOG");
     let (format, dst) = parse_args();
     let result = main_with_result(format, &dst);
     if let Err(e) = result {
diff --git a/src/tools/generate-windows-sys/src/arm_shim.rs b/src/tools/generate-windows-sys/src/arm_shim.rs
deleted file mode 100644
index 17c2ccb223c..00000000000
--- a/src/tools/generate-windows-sys/src/arm_shim.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Begin of ARM32 shim
-// The raw content of this file should be processed by `generate-windows-sys`
-// to be merged with the generated binding. It is not supposed to be used as
-// a normal Rust module.
-cfg_if::cfg_if! {
-if #[cfg(target_arch = "arm")] {
-#[repr(C)]
-pub struct WSADATA {
-    pub wVersion: u16,
-    pub wHighVersion: u16,
-    pub szDescription: [u8; 257],
-    pub szSystemStatus: [u8; 129],
-    pub iMaxSockets: u16,
-    pub iMaxUdpDg: u16,
-    pub lpVendorInfo: PSTR,
-}
-pub enum CONTEXT {}
-}
-}
-// End of ARM32 shim
diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs
index 65e480715ee..91d981462e8 100644
--- a/src/tools/generate-windows-sys/src/main.rs
+++ b/src/tools/generate-windows-sys/src/main.rs
@@ -11,9 +11,6 @@ const PRELUDE: &str = r#"// This file is autogenerated.
 // ignore-tidy-filelength
 "#;
 
-/// This is a shim for the ARM (32-bit) architecture, which is no longer supported by windows-rs.
-const ARM_SHIM: &str = include_str!("arm_shim.rs");
-
 fn main() -> io::Result<()> {
     let mut path: PathBuf =
         std::env::args_os().nth(1).expect("a path to the rust repository is required").into();
@@ -35,7 +32,6 @@ fn main() -> io::Result<()> {
     let mut f = std::fs::File::create(&path)?;
     f.write_all(PRELUDE.as_bytes())?;
     f.write_all(bindings.as_bytes())?;
-    f.write_all(ARM_SHIM.as_bytes())?;
 
     Ok(())
 }
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 0ac1e277eb7..3e024086a6b 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-0928a1f7574f5ca019b5443b3a90008588d18c8c
+08fd6f719ee764cf62659ddf481e22dbfe4b8894
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 083dd4800d9..cc14cfecea4 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -31,9 +31,9 @@ use rustc_middle::{
     query::{ExternProviders, LocalCrate},
     ty::TyCtxt,
 };
-use rustc_session::config::OptLevel;
-
-use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace};
+use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
+use rustc_session::search_paths::PathKind;
+use rustc_session::{CtfeBacktrace, EarlyErrorHandler};
 
 use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields};
 
@@ -59,6 +59,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
 
     fn after_analysis<'tcx>(
         &mut self,
+        handler: &EarlyErrorHandler,
         _: &rustc_interface::interface::Compiler,
         queries: &'tcx rustc_interface::Queries<'tcx>,
     ) -> Compilation {
@@ -66,8 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             if tcx.sess.compile_status().is_err() {
                 tcx.sess.fatal("miri cannot be run on programs that fail compilation");
             }
-
-            init_late_loggers(tcx);
+;
+            init_late_loggers(handler, tcx);
             if !tcx.sess.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
             }
@@ -181,7 +182,7 @@ macro_rules! show_error {
     ($($tt:tt)*) => { show_error(&format_args!($($tt)*)) };
 }
 
-fn init_early_loggers() {
+fn init_early_loggers(handler: &EarlyErrorHandler) {
     // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
     // initialize them both, and we always initialize `miri`'s first.
     let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
@@ -195,11 +196,11 @@ fn init_early_loggers() {
     // later with our custom settings, and *not* log anything for what happens before
     // `miri` gets started.
     if env::var_os("RUSTC_LOG").is_some() {
-        rustc_driver::init_rustc_env_logger();
+        rustc_driver::init_rustc_env_logger(handler);
     }
 }
 
-fn init_late_loggers(tcx: TyCtxt<'_>) {
+fn init_late_loggers(handler: &EarlyErrorHandler, tcx: TyCtxt<'_>) {
     // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
     // env var if it is not set, control it based on `MIRI_LOG`.
     // (FIXME: use `var_os`, but then we need to manually concatenate instead of `format!`.)
@@ -218,7 +219,7 @@ fn init_late_loggers(tcx: TyCtxt<'_>) {
             } else {
                 env::set_var("RUSTC_LOG", &var);
             }
-            rustc_driver::init_rustc_env_logger();
+            rustc_driver::init_rustc_env_logger(handler);
         }
     }
 
@@ -284,6 +285,8 @@ fn parse_comma_list<T: FromStr>(input: &str) -> Result<Vec<T>, T::Err> {
 }
 
 fn main() {
+    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     // Snapshot a copy of the environment before `rustc` starts messing with it.
     // (`install_ice_hook` might change `RUST_BACKTRACE`.)
     let env_snapshot = env::vars_os().collect::<Vec<_>>();
@@ -292,7 +295,7 @@ fn main() {
     if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
         // Earliest rustc setup.
         rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
-        rustc_driver::init_rustc_env_logger();
+        rustc_driver::init_rustc_env_logger(&handler);
 
         let target_crate = if crate_kind == "target" {
             true
@@ -314,7 +317,7 @@ fn main() {
     rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
 
     // Init loggers the Miri way.
-    init_early_loggers();
+    init_early_loggers(&handler);
 
     // Parse our arguments and split them across `rustc` and `miri`.
     let mut miri_config = miri::MiriConfig::default();
diff --git a/src/tools/rust-installer/Cargo.toml b/src/tools/rust-installer/Cargo.toml
index 85e979f07bf..471f2b5ac73 100644
--- a/src/tools/rust-installer/Cargo.toml
+++ b/src/tools/rust-installer/Cargo.toml
@@ -2,7 +2,7 @@
 authors = ["The Rust Project Developers"]
 name = "installer"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [[bin]]
 doc = false
@@ -20,4 +20,4 @@ num_cpus = "1"
 
 [dependencies.clap]
 features = ["derive"]
-version = "3.1"
+version = "4.2"
diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs
index abcf59cfe36..19466f63fed 100644
--- a/src/tools/rust-installer/src/combiner.rs
+++ b/src/tools/rust-installer/src/combiner.rs
@@ -13,47 +13,47 @@ actor! {
     #[derive(Debug)]
     pub struct Combiner {
         /// The name of the product, for display.
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         product_name: String = "Product",
 
         /// The name of the package  tarball.
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         package_name: String = "package",
 
         /// The directory under lib/ where the manifest lives.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         rel_manifest_dir: String = "packagelib",
 
         /// The string to print after successful installation.
-        #[clap(value_name = "MESSAGE")]
+        #[arg(value_name = "MESSAGE")]
         success_message: String = "Installed.",
 
         /// Places to look for legacy manifests to uninstall.
-        #[clap(value_name = "DIRS")]
+        #[arg(value_name = "DIRS")]
         legacy_manifest_dirs: String = "",
 
         /// Installers to combine.
-        #[clap(value_name = "FILE,FILE")]
+        #[arg(value_name = "FILE,FILE")]
         input_tarballs: String = "",
 
         /// Directory containing files that should not be installed.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         non_installed_overlay: String = "",
 
         /// The directory to do temporary work.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         work_dir: String = "./workdir",
 
         /// The location to put the final image and tarball.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         output_dir: String = "./dist",
 
         /// The profile used to compress the tarball.
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_profile: CompressionProfile,
 
         /// The formats used to compress the tarball
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
     }
 }
@@ -94,7 +94,7 @@ impl Combiner {
             let pkg_name =
                 input_tarball.trim_end_matches(&format!(".tar.{}", compression.extension()));
             let pkg_name = Path::new(pkg_name).file_name().unwrap();
-            let pkg_dir = Path::new(&self.work_dir).join(&pkg_name);
+            let pkg_dir = Path::new(&self.work_dir).join(pkg_name);
 
             // Verify the version number.
             let mut version = String::new();
@@ -114,9 +114,9 @@ impl Combiner {
                 // All we need to do is copy the component directory. We could
                 // move it, but rustbuild wants to reuse the unpacked package
                 // dir for OS-specific installers on macOS and Windows.
-                let component_dir = package_dir.join(&component);
+                let component_dir = package_dir.join(component);
                 create_dir(&component_dir)?;
-                copy_recursive(&pkg_dir.join(&component), &component_dir)?;
+                copy_recursive(&pkg_dir.join(component), &component_dir)?;
 
                 // Merge the component name.
                 writeln!(&components, "{}", component).context("failed to write new components")?;
@@ -158,7 +158,7 @@ impl Combiner {
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
             .compression_profile(self.compression_profile)
-            .compression_formats(self.compression_formats.clone());
+            .compression_formats(self.compression_formats);
         tarballer.run()?;
 
         Ok(())
diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs
index 7c9c946e0b5..902b2ec6907 100644
--- a/src/tools/rust-installer/src/compression.rs
+++ b/src/tools/rust-installer/src/compression.rs
@@ -166,7 +166,7 @@ impl Default for CompressionFormats {
 
 impl CompressionFormats {
     pub(crate) fn iter(&self) -> impl Iterator<Item = CompressionFormat> + '_ {
-        self.0.iter().map(|i| *i)
+        self.0.iter().copied()
     }
 }
 
diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs
index ddd1052599d..45f8c49d03e 100644
--- a/src/tools/rust-installer/src/generator.rs
+++ b/src/tools/rust-installer/src/generator.rs
@@ -11,55 +11,55 @@ actor! {
     #[derive(Debug)]
     pub struct Generator {
         /// The name of the product, for display
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         product_name: String = "Product",
 
         /// The name of the component, distinct from other installed components
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         component_name: String = "component",
 
         /// The name of the package, tarball
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         package_name: String = "package",
 
         /// The directory under lib/ where the manifest lives
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         rel_manifest_dir: String = "packagelib",
 
         /// The string to print after successful installation
-        #[clap(value_name = "MESSAGE")]
+        #[arg(value_name = "MESSAGE")]
         success_message: String = "Installed.",
 
         /// Places to look for legacy manifests to uninstall
-        #[clap(value_name = "DIRS")]
+        #[arg(value_name = "DIRS")]
         legacy_manifest_dirs: String = "",
 
         /// Directory containing files that should not be installed
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         non_installed_overlay: String = "",
 
         /// Path prefixes of directories that should be installed/uninstalled in bulk
-        #[clap(value_name = "DIRS")]
+        #[arg(value_name = "DIRS")]
         bulk_dirs: String = "",
 
         /// The directory containing the installation medium
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         image_dir: String = "./install_image",
 
         /// The directory to do temporary work
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         work_dir: String = "./workdir",
 
         /// The location to put the final image and tarball
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         output_dir: String = "./dist",
 
         /// The profile used to compress the tarball.
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_profile: CompressionProfile,
 
         /// The formats used to compress the tarball
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
     }
 }
@@ -118,7 +118,7 @@ impl Generator {
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
             .compression_profile(self.compression_profile)
-            .compression_formats(self.compression_formats.clone());
+            .compression_formats(self.compression_formats);
         tarballer.run()?;
 
         Ok(())
diff --git a/src/tools/rust-installer/src/scripter.rs b/src/tools/rust-installer/src/scripter.rs
index 06affc029fd..8180f925cb0 100644
--- a/src/tools/rust-installer/src/scripter.rs
+++ b/src/tools/rust-installer/src/scripter.rs
@@ -2,29 +2,29 @@ use crate::util::*;
 use anyhow::{Context, Result};
 use std::io::Write;
 
-const TEMPLATE: &'static str = include_str!("../install-template.sh");
+const TEMPLATE: &str = include_str!("../install-template.sh");
 
 actor! {
     #[derive(Debug)]
     pub struct Scripter {
         /// The name of the product, for display
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         product_name: String = "Product",
 
         /// The directory under lib/ where the manifest lives
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         rel_manifest_dir: String = "manifestlib",
 
         /// The string to print after successful installation
-        #[clap(value_name = "MESSAGE")]
+        #[arg(value_name = "MESSAGE")]
         success_message: String = "Installed.",
 
         /// Places to look for legacy manifests to uninstall
-        #[clap(value_name = "DIRS")]
+        #[arg(value_name = "DIRS")]
         legacy_manifest_dirs: String = "",
 
         /// The name of the output script
-        #[clap(value_name = "FILE")]
+        #[arg(value_name = "FILE")]
         output_script: String = "install.sh",
     }
 }
diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs
index 7353a49fe03..c60d5f648ff 100644
--- a/src/tools/rust-installer/src/tarballer.rs
+++ b/src/tools/rust-installer/src/tarballer.rs
@@ -14,23 +14,23 @@ actor! {
     #[derive(Debug)]
     pub struct Tarballer {
         /// The input folder to be compressed.
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         input: String = "package",
 
         /// The prefix of the tarballs.
-        #[clap(value_name = "PATH")]
+        #[arg(value_name = "PATH")]
         output: String = "./dist",
 
         /// The folder in which the input is to be found.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         work_dir: String = "./workdir",
 
         /// The profile used to compress the tarball.
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_profile: CompressionProfile,
 
         /// The formats used to compress the tarball.
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
     }
 }
@@ -98,7 +98,7 @@ fn append_path<W: Write>(builder: &mut Builder<W>, src: &Path, path: &String) ->
         if cfg!(windows) {
             // Windows doesn't really have a mode, so `tar` never marks files executable.
             // Use an extension whitelist to update files that usually should be so.
-            const EXECUTABLES: [&'static str; 4] = ["exe", "dll", "py", "sh"];
+            const EXECUTABLES: [&str; 4] = ["exe", "dll", "py", "sh"];
             if let Some(ext) = src.extension().and_then(|s| s.to_str()) {
                 if EXECUTABLES.contains(&ext) {
                     let mode = header.mode()?;
@@ -134,7 +134,7 @@ where
     for entry in WalkDir::new(root.join(name)) {
         let entry = entry?;
         let path = entry.path().strip_prefix(root)?;
-        let path = path_to_str(&path)?;
+        let path = path_to_str(path)?;
 
         if entry.file_type().is_dir() {
             dirs.push(path.to_owned());
diff --git a/src/tools/rust-installer/src/util.rs b/src/tools/rust-installer/src/util.rs
index 6cac314b68d..4eb2e75fd7e 100644
--- a/src/tools/rust-installer/src/util.rs
+++ b/src/tools/rust-installer/src/util.rs
@@ -117,7 +117,7 @@ where
         } else {
             copy(entry.path(), dst)?;
         }
-        callback(&path, file_type)?;
+        callback(path, file_type)?;
     }
     Ok(())
 }
@@ -135,7 +135,7 @@ macro_rules! actor {
         $( #[ $attr ] )+
         #[derive(clap::Args)]
         pub struct $name {
-            $( $( #[ $field_attr ] )+ #[clap(long, $(default_value = $default)*)] $field : $type, )*
+            $( $( #[ $field_attr ] )+ #[arg(long, $(default_value = $default)*)] $field : $type, )*
         }
 
         impl Default for $name {
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 2fd4c797b43..7ad8f5c5c05 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -160,10 +160,10 @@ pub fn check(
     for &(name, _) in gate_untested.iter() {
         println!("Expected a gate test for the feature '{name}'.");
         println!(
-            "Hint: create a failing test file named 'feature-gate-{}.rs'\
-                \n      in the 'ui' test suite, with its failures due to\
-                \n      missing usage of `#![feature({})]`.",
-            name, name
+            "Hint: create a failing test file named 'tests/ui/feature-gates/feature-gate-{}.rs',\
+                \n      with its failures due to missing usage of `#![feature({})]`.",
+            name.replace("_", "-"),
+            name
         );
         println!(
             "Hint: If you already have such a test and don't want to rename it,\
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 55bf38110a6..3ed587caadc 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 const ISSUES_ENTRY_LIMIT: usize = 1896;
-const ROOT_ENTRY_LIMIT: usize = 870;
+const ROOT_ENTRY_LIMIT: usize = 871;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files