about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/dependencies.yml7
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs31
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs29
-rw-r--r--compiler/rustc_infer/src/infer/context.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs10
-rw-r--r--compiler/rustc_lint/src/builtin.rs10
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs7
-rw-r--r--compiler/rustc_lint/src/internal.rs152
-rw-r--r--compiler/rustc_middle/src/middle/resolve_bound_vars.rs8
-rw-r--r--compiler/rustc_middle/src/ty/context.rs18
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs5
-rw-r--r--compiler/rustc_span/src/hygiene.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs50
-rw-r--r--library/core/src/ascii/ascii_char.rs10
-rw-r--r--library/core/src/cell/once.rs3
-rw-r--r--library/core/src/fmt/builders.rs224
-rw-r--r--library/core/src/ub_checks.rs2
-rw-r--r--library/core/tests/fmt/builders.rs386
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/src/fs.rs2
-rw-r--r--library/std/src/os/wasi/fs.rs1
-rw-r--r--library/std/src/os/wasi/mod.rs2
-rw-r--r--library/std/src/os/wasip2/mod.rs1
-rw-r--r--library/std/src/sys/pal/solid/fs.rs23
-rw-r--r--library/std/src/sys/pal/unix/fs.rs49
-rw-r--r--library/std/src/sys/pal/wasi/args.rs2
-rw-r--r--library/std/src/sys/pal/wasi/env.rs2
-rw-r--r--library/std/src/sys/pal/wasi/fd.rs2
-rw-r--r--library/std/src/sys/pal/wasi/fs.rs22
-rw-r--r--library/std/src/sys/pal/wasi/helpers.rs2
-rw-r--r--library/std/src/sys/pal/wasi/io.rs2
-rw-r--r--library/std/src/sys/pal/wasi/net.rs2
-rw-r--r--library/std/src/sys/pal/wasi/os.rs2
-rw-r--r--library/std/src/sys/pal/wasi/stdio.rs2
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs18
-rw-r--r--library/std/src/sys/pal/wasi/time.rs2
-rw-r--r--library/std/src/sys/pal/windows/fs.rs4
-rw-r--r--library/std/src/sys_common/fs.rs21
-rw-r--r--library/std/src/sys_common/mod.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs37
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs2
-rw-r--r--src/bootstrap/src/core/config/config.rs147
-rw-r--r--src/bootstrap/src/core/download.rs2
-rw-r--r--src/bootstrap/src/lib.rs117
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css13
m---------src/tools/cargo0
-rw-r--r--src/tools/miri/Cargo.toml2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs104
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs15
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs16
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs6
-rw-r--r--src/tools/miri/src/shims/x86/sha.rs221
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock4
-rw-r--r--src/tools/miri/tests/fail/alloc/global_system_mixup.rs4
-rw-r--r--src/tools/miri/tests/fail/alloc/global_system_mixup.stderr2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs19
-rw-r--r--src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr15
-rw-r--r--src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr36
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-epoll.rs28
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs270
-rw-r--r--src/tools/run-make-support/src/env.rs8
-rw-r--r--src/tools/run-make-support/src/lib.rs2
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs10
-rw-r--r--tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs21
-rw-r--r--tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs21
-rw-r--r--tests/incremental/decl_macro.rs34
-rw-r--r--tests/run-make/debugger-visualizer-dep-info/foo.py1
-rw-r--r--tests/run-make/debugger-visualizer-dep-info/main.rs2
-rw-r--r--tests/run-make/debugger-visualizer-dep-info/my_gdb_script.py6
-rw-r--r--tests/run-make/debugger-visualizer-dep-info/rmake.rs2
-rwxr-xr-xtests/run-make/libtest-junit/validate_junit.py10
-rw-r--r--tests/run-make/msvc-wholearchive/c.c1
-rw-r--r--tests/run-make/msvc-wholearchive/dll.def4
-rw-r--r--tests/run-make/msvc-wholearchive/rmake.rs52
-rw-r--r--tests/run-make/msvc-wholearchive/static.rs9
-rw-r--r--tests/run-make/remove-dir-all-race/rmake.rs62
-rw-r--r--tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile23
-rw-r--r--tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs96
-rw-r--r--tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh69
-rw-r--r--tests/rustdoc-gui/target.goml2
-rw-r--r--tests/ui-fulldeps/internal-lints/diagnostics.rs7
-rw-r--r--tests/ui-fulldeps/internal-lints/diagnostics.stderr42
-rw-r--r--tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr9
-rw-r--r--tests/ui/consts/static-default-lifetime/elided-lifetime.stderr6
-rw-r--r--tests/ui/consts/static-default-lifetime/static-trait-impl.stderr6
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path.base.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-76535.base.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-79422.base.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-79422.extended.stderr2
-rw-r--r--tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr4
-rw-r--r--tests/ui/issues/issue-20831-debruijn.stderr4
-rw-r--r--tests/ui/issues/issue-37884.stderr5
-rw-r--r--tests/ui/regions/explicit-static-bound-on-trait.rs13
-rw-r--r--tests/ui/regions/explicit-static-bound-on-trait.stderr32
-rw-r--r--tests/ui/traits/object/pretty.rs7
-rw-r--r--tests/ui/traits/object/pretty.stderr50
108 files changed, 2246 insertions, 638 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index 5e54ceea3d7..83b92b7fa09 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -64,6 +64,10 @@ jobs:
       - name: cargo update
         # Remove first line that always just says "Updating crates.io index"
         run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+      - name: cargo update library
+        run: |
+          echo -e "\nlibrary dependencies:" >> cargo_update.log
+          cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
       - name: cargo update rustbook
         run: |
           echo -e "\nrustbook dependencies:" >> cargo_update.log
@@ -74,6 +78,7 @@ jobs:
           name: Cargo-lock
           path: |
             Cargo.lock
+            library/Cargo.lock
             src/tools/rustbook/Cargo.lock
           retention-days: 1
       - name: upload cargo-update log artifact for use in PR
@@ -119,7 +124,7 @@ jobs:
           git config user.name github-actions
           git config user.email github-actions@github.com
           git switch --force-create cargo_update
-          git add ./Cargo.lock ./src/tools/rustbook/Cargo.lock
+          git add ./Cargo.lock ./library/Cargo.lock ./src/tools/rustbook/Cargo.lock
           git commit --no-verify --file=commit.txt
 
       - name: push
diff --git a/Cargo.lock b/Cargo.lock
index a18219b5683..87a68270e3e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -195,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "ar_archive_writer"
-version = "0.4.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de11a9d32db3327f981143bdf699ade4d637c6887b13b97e6e91a9154666963c"
+checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4"
 dependencies = [
  "object 0.36.3",
 ]
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 8862f139aff..fe71b2e669e 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -11,6 +11,7 @@ use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
+use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry;
 use rustc_middle::mir::mono::CodegenUnit;
 use rustc_middle::ty::layout::{
     FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
@@ -226,6 +227,20 @@ pub unsafe fn create_module<'ll>(
         }
     }
 
+    // If we're normalizing integers with CFI, ensure LLVM generated functions do the same.
+    // See https://github.com/llvm/llvm-project/pull/104826
+    if sess.is_sanitizer_cfi_normalize_integers_enabled() {
+        let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr().cast();
+        unsafe {
+            llvm::LLVMRustAddModuleFlagU32(
+                llmod,
+                llvm::LLVMModFlagBehavior::Override,
+                cfi_normalize_integers,
+                1,
+            );
+        }
+    }
+
     // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
     if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
         let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr();
@@ -245,6 +260,22 @@ pub unsafe fn create_module<'ll>(
         unsafe {
             llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
         }
+
+        // Add "kcfi-offset" module flag with -Z patchable-function-entry (See
+        // https://reviews.llvm.org/D141172).
+        let pfe =
+            PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry);
+        if pfe.prefix() > 0 {
+            let kcfi_offset = c"kcfi-offset".as_ptr().cast();
+            unsafe {
+                llvm::LLVMRustAddModuleFlagU32(
+                    llmod,
+                    llvm::LLVMModFlagBehavior::Override,
+                    kcfi_offset,
+                    pfe.prefix().into(),
+                );
+            }
+        }
     }
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index e3033b332ca..56b75f9b329 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-ar_archive_writer = "0.4.0"
+ar_archive_writer = "0.4.2"
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
 cc = "1.0.90"
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 38a440a707a..c8c1bd3e8f9 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -108,7 +108,11 @@ pub trait ArchiveBuilderBuilder {
                 &exports,
                 machine,
                 !sess.target.is_like_msvc,
-                /*comdat=*/ false,
+                // Enable compatibility with MSVC's `/WHOLEARCHIVE` flag.
+                // Without this flag a duplicate symbol error would be emitted
+                // when linking a rust staticlib using `/WHOLEARCHIVE`.
+                // See #129020
+                true,
             ) {
                 sess.dcx()
                     .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() });
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 16eeb57b2b9..14c5f8d9f16 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -529,7 +529,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
 
         match tcx.named_bound_var(hir_id) {
             Some(ResolvedArg::EarlyBound(def_id)) => {
-                expected_captures.insert(def_id);
+                expected_captures.insert(def_id.to_def_id());
 
                 // Make sure we allow capturing these lifetimes through `Self` and
                 // `T::Assoc` projection syntax, too. These will occur when we only
@@ -538,7 +538,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
                 // feature -- see <https://github.com/rust-lang/rust/pull/115659>.
                 if let DefKind::LifetimeParam = tcx.def_kind(def_id)
                     && let Some(def_id) = tcx
-                        .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
+                        .map_opaque_lifetime_to_parent_lifetime(def_id)
                         .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))
                 {
                     shadowed_captures.insert(def_id);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index d4b2c3f8a87..fb9bcc113c6 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -747,7 +747,7 @@ fn region_known_to_outlive<'tcx>(
     region_b: ty::Region<'tcx>,
 ) -> bool {
     test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
-        infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP), region_b, region_a);
+        infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a);
     })
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index ae0c70d2326..0cf9e128bce 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -13,7 +13,6 @@ use rustc_ast::visit::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node};
 use rustc_macros::extension;
@@ -22,7 +21,7 @@ use rustc_middle::middle::resolve_bound_vars::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_middle::{bug, span_bug};
-use rustc_span::def_id::DefId;
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
@@ -32,7 +31,7 @@ use crate::errors;
 impl ResolvedArg {
     fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
         debug!("ResolvedArg::early: def_id={:?}", param.def_id);
-        (param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id()))
+        (param.def_id, ResolvedArg::EarlyBound(param.def_id))
     }
 
     fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
@@ -41,10 +40,10 @@ impl ResolvedArg {
             "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
             idx, param, depth, param.def_id,
         );
-        (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id.to_def_id()))
+        (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id))
     }
 
-    fn id(&self) -> Option<DefId> {
+    fn id(&self) -> Option<LocalDefId> {
         match *self {
             ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None,
 
@@ -288,13 +287,14 @@ fn late_arg_as_bound_arg<'tcx>(
 ) -> ty::BoundVariableKind {
     match arg {
         ResolvedArg::LateBound(_, _, def_id) => {
-            let name = tcx.hir().name(tcx.local_def_id_to_hir_id(def_id.expect_local()));
+            let def_id = def_id.to_def_id();
+            let name = tcx.item_name(def_id);
             match param.kind {
                 GenericParamKind::Lifetime { .. } => {
-                    ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name))
+                    ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
                 }
                 GenericParamKind::Type { .. } => {
-                    ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(*def_id, name))
+                    ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name))
                 }
                 GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
             }
@@ -717,7 +717,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     // In the future, this should be fixed and this error should be removed.
                     let def = self.map.defs.get(&lifetime.hir_id).copied();
                     let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
-                    let Some(lifetime_def_id) = lifetime_def_id.as_local() else { continue };
                     let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
 
                     let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id))
@@ -1150,7 +1149,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                             .param_def_id_to_index(self.tcx, region_def_id.to_def_id())
                             .is_some()
                     {
-                        break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
+                        break Some(ResolvedArg::EarlyBound(region_def_id));
                     }
                     break None;
                 }
@@ -1259,7 +1258,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     kind => span_bug!(
                         use_span,
                         "did not expect to resolve lifetime to {}",
-                        kind.descr(param_def_id)
+                        kind.descr(param_def_id.to_def_id())
                     ),
                 };
                 def = ResolvedArg::Error(guar);
@@ -1277,10 +1276,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         kind: hir::ImplItemKind::Fn(..),
                         ..
                     }) => {
-                        def = ResolvedArg::Free(owner_id.to_def_id(), def.id().unwrap());
+                        def = ResolvedArg::Free(owner_id.def_id, def.id().unwrap());
                     }
                     Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => {
-                        def = ResolvedArg::Free(closure.def_id.to_def_id(), def.id().unwrap());
+                        def = ResolvedArg::Free(closure.def_id, def.id().unwrap());
                     }
                     _ => {}
                 }
@@ -1351,7 +1350,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                             .param_def_id_to_index(self.tcx, param_def_id.to_def_id())
                             .is_some()
                     {
-                        break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id()));
+                        break Some(ResolvedArg::EarlyBound(param_def_id));
                     }
                     break None;
                 }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 2fb1bcf2dbf..5c8ecf254a5 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -296,25 +296,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static,
 
             Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
-                let name = lifetime_name(def_id.expect_local());
+                let name = lifetime_name(def_id);
                 let br = ty::BoundRegion {
                     var: ty::BoundVar::from_u32(index),
-                    kind: ty::BrNamed(def_id, name),
+                    kind: ty::BrNamed(def_id.to_def_id(), name),
                 };
                 ty::Region::new_bound(tcx, debruijn, br)
             }
 
             Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
-                let name = tcx.hir().ty_param_name(def_id.expect_local());
-                let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
+                let name = tcx.hir().ty_param_name(def_id);
+                let item_def_id = tcx.hir().ty_param_owner(def_id);
                 let generics = tcx.generics_of(item_def_id);
-                let index = generics.param_def_id_to_index[&def_id];
+                let index = generics.param_def_id_to_index[&def_id.to_def_id()];
                 ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name })
             }
 
             Some(rbv::ResolvedArg::Free(scope, id)) => {
-                let name = lifetime_name(id.expect_local());
-                ty::Region::new_late_param(tcx, scope, ty::BrNamed(id, name))
+                let name = lifetime_name(id);
+                ty::Region::new_late_param(
+                    tcx,
+                    scope.to_def_id(),
+                    ty::BrNamed(id.to_def_id(), name),
+                )
 
                 // (*) -- not late-bound, won't change
             }
@@ -1953,15 +1957,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let tcx = self.tcx();
         match tcx.named_bound_var(hir_id) {
             Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
-                let name = tcx.item_name(def_id);
+                let name = tcx.item_name(def_id.to_def_id());
                 let br = ty::BoundTy {
                     var: ty::BoundVar::from_u32(index),
-                    kind: ty::BoundTyKind::Param(def_id, name),
+                    kind: ty::BoundTyKind::Param(def_id.to_def_id(), name),
                 };
                 Ty::new_bound(tcx, debruijn, br)
             }
             Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
-                let def_id = def_id.expect_local();
                 let item_def_id = tcx.hir().ty_param_owner(def_id);
                 let generics = tcx.generics_of(item_def_id);
                 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
@@ -1982,10 +1985,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
                 // Find the name and index of the const parameter by indexing the generics of
                 // the parent item and construct a `ParamConst`.
-                let item_def_id = tcx.parent(def_id);
+                let item_def_id = tcx.local_parent(def_id);
                 let generics = tcx.generics_of(item_def_id);
-                let index = generics.param_def_id_to_index[&def_id];
-                let name = tcx.item_name(def_id);
+                let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+                let name = tcx.item_name(def_id.to_def_id());
                 ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
             }
             Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index f35a8162d96..95888beb6b1 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -167,7 +167,7 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
     }
 
     fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
-        self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
+        self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), sub, sup)
     }
 
     fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index f2fc25a2d2e..5aa7f259685 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -390,7 +390,7 @@ pub enum SubregionOrigin<'tcx> {
 
     /// The given region parameter was instantiated with a region
     /// that must outlive some other region.
-    RelateRegionParamBound(Span),
+    RelateRegionParamBound(Span, Option<Ty<'tcx>>),
 
     /// Creating a pointer `b` to contents of another reference.
     Reborrow(Span),
@@ -859,7 +859,7 @@ impl<'tcx> InferCtxt<'tcx> {
     ) {
         self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| {
             let origin = SubregionOrigin::from_obligation_cause(cause, || {
-                RelateRegionParamBound(cause.span)
+                RelateRegionParamBound(cause.span, None)
             });
             self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
         })
@@ -1685,7 +1685,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
             Subtype(ref a) => a.span(),
             RelateObjectBound(a) => a,
             RelateParamBound(a, ..) => a,
-            RelateRegionParamBound(a) => a,
+            RelateRegionParamBound(a, _) => a,
             Reborrow(a) => a,
             ReferenceOutlivesReferent(_, a) => a,
             CompareImplItemObligation { span, .. } => span,
@@ -1726,6 +1726,10 @@ impl<'tcx> SubregionOrigin<'tcx> {
                 SubregionOrigin::AscribeUserTypeProvePredicate(span)
             }
 
+            traits::ObligationCauseCode::ObjectTypeBound(ty, _reg) => {
+                SubregionOrigin::RelateRegionParamBound(cause.span, Some(ty))
+            }
+
             _ => default(),
         }
     }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 85132dd4f98..d8482567bbe 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1925,8 +1925,8 @@ impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
         tcx: TyCtxt<'tcx>,
         inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
-        item: DefId,
-        lifetime: DefId,
+        item: LocalDefId,
+        lifetime: LocalDefId,
     ) -> Vec<ty::Region<'tcx>> {
         let item_generics = tcx.generics_of(item);
 
@@ -1934,7 +1934,7 @@ impl ExplicitOutlivesRequirements {
             .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
                     ty::ReEarlyParam(ebr)
-                        if item_generics.region_param(ebr, tcx).def_id == lifetime =>
+                        if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() =>
                     {
                         Some(b)
                     }
@@ -1982,7 +1982,7 @@ impl ExplicitOutlivesRequirements {
                 let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
                     Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
                         .iter()
-                        .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id })),
+                        .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })),
                     _ => false,
                 };
 
@@ -2097,7 +2097,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                         inferred_outlives
                                             .iter()
                                             .filter(|(_, span)| !predicate.span.contains(*span)),
-                                        item.owner_id.to_def_id(),
+                                        item.owner_id.def_id,
                                         region_def_id,
                                     ),
                                     &predicate.bounds,
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index 990fb2d16f9..2e0da69e920 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -300,16 +300,17 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
                         Some(
                             ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id),
                         ) => {
-                            if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy {
+                            if self.tcx.def_kind(self.tcx.local_parent(def_id)) == DefKind::OpaqueTy
+                            {
                                 let def_id = self
                                     .tcx
-                                    .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
+                                    .map_opaque_lifetime_to_parent_lifetime(def_id)
                                     .opt_param_def_id(self.tcx, self.parent_def_id.to_def_id())
                                     .expect("variable should have been duplicated from parent");
 
                                 explicitly_captured.insert(def_id);
                             } else {
-                                explicitly_captured.insert(def_id);
+                                explicitly_captured.insert(def_id.to_def_id());
                             }
                         }
                         _ => {
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 044c9413f0b..65571815019 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -8,7 +8,7 @@ use rustc_hir::{
     BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat, PatKind,
     Path, PathSegment, QPath, Ty, TyKind,
 };
-use rustc_middle::ty::{self, Ty as MiddleTy};
+use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -415,14 +415,17 @@ declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE
 
 impl LateLintPass<'_> for Diagnostics {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        let collect_args_tys_and_spans = |args: &[Expr<'_>], reserve_one_extra: bool| {
+            let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra));
+            result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span)));
+            result
+        };
         // Only check function calls and method calls.
-        let (span, def_id, fn_gen_args, call_tys) = match expr.kind {
+        let (span, def_id, fn_gen_args, arg_tys_and_spans) = match expr.kind {
             ExprKind::Call(callee, args) => {
                 match cx.typeck_results().node_type(callee.hir_id).kind() {
                     &ty::FnDef(def_id, fn_gen_args) => {
-                        let call_tys: Vec<_> =
-                            args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
-                        (callee.span, def_id, fn_gen_args, call_tys)
+                        (callee.span, def_id, fn_gen_args, collect_args_tys_and_spans(args, false))
                     }
                     _ => return, // occurs for fns passed as args
                 }
@@ -432,38 +435,40 @@ impl LateLintPass<'_> for Diagnostics {
                 else {
                     return;
                 };
-                let mut call_tys: Vec<_> =
-                    args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
-                call_tys.insert(0, cx.tcx.types.self_param); // dummy inserted for `self`
-                (span, def_id, fn_gen_args, call_tys)
+                let mut args = collect_args_tys_and_spans(args, true);
+                args.insert(0, (cx.tcx.types.self_param, _recv.span)); // dummy inserted for `self`
+                (span, def_id, fn_gen_args, args)
             }
             _ => return,
         };
 
-        // Is the callee marked with `#[rustc_lint_diagnostics]`?
-        let has_attr = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args)
-            .ok()
-            .flatten()
-            .is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
-
-        // Closure: is the type `{D,Subd}iagMessage`?
-        let is_diag_message = |ty: MiddleTy<'_>| {
-            if let Some(adt_def) = ty.ty_adt_def()
-                && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
-                && matches!(name, sym::DiagMessage | sym::SubdiagMessage)
-            {
-                true
-            } else {
-                false
-            }
-        };
+        Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args);
+        Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans);
+    }
+}
 
-        // Does the callee have one or more `impl Into<{D,Subd}iagMessage>` parameters?
-        let mut impl_into_diagnostic_message_params = vec![];
+impl Diagnostics {
+    // Is the type `{D,Subd}iagMessage`?
+    fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: MiddleTy<'cx>) -> bool {
+        if let Some(adt_def) = ty.ty_adt_def()
+            && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
+            && matches!(name, sym::DiagMessage | sym::SubdiagMessage)
+        {
+            true
+        } else {
+            false
+        }
+    }
+
+    fn untranslatable_diagnostic<'cx>(
+        cx: &LateContext<'cx>,
+        def_id: DefId,
+        arg_tys_and_spans: &[(MiddleTy<'cx>, Span)],
+    ) {
         let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
         let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates;
         for (i, &param_ty) in fn_sig.inputs().iter().enumerate() {
-            if let ty::Param(p) = param_ty.kind() {
+            if let ty::Param(sig_param) = param_ty.kind() {
                 // It is a type parameter. Check if it is `impl Into<{D,Subd}iagMessage>`.
                 for pred in predicates.iter() {
                     if let Some(trait_pred) = pred.as_trait_clause()
@@ -471,27 +476,53 @@ impl LateLintPass<'_> for Diagnostics {
                         && trait_ref.self_ty() == param_ty // correct predicate for the param?
                         && cx.tcx.is_diagnostic_item(sym::Into, trait_ref.def_id)
                         && let ty1 = trait_ref.args.type_at(1)
-                        && is_diag_message(ty1)
+                        && Self::is_diag_message(cx, ty1)
                     {
-                        impl_into_diagnostic_message_params.push((i, p.name));
+                        // Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg
+                        // with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an
+                        // `UNTRANSLATABLE_DIAGNOSTIC` lint.
+                        let (arg_ty, arg_span) = arg_tys_and_spans[i];
+
+                        // Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`?
+                        let is_translatable = Self::is_diag_message(cx, arg_ty)
+                            || matches!(arg_ty.kind(), ty::Param(arg_param) if arg_param.name == sig_param.name);
+                        if !is_translatable {
+                            cx.emit_span_lint(
+                                UNTRANSLATABLE_DIAGNOSTIC,
+                                arg_span,
+                                UntranslatableDiag,
+                            );
+                        }
                     }
                 }
             }
         }
+    }
 
-        // Is the callee interesting?
-        if !has_attr && impl_into_diagnostic_message_params.is_empty() {
+    fn diagnostic_outside_of_impl<'cx>(
+        cx: &LateContext<'cx>,
+        span: Span,
+        current_id: HirId,
+        def_id: DefId,
+        fn_gen_args: GenericArgsRef<'cx>,
+    ) {
+        // Is the callee marked with `#[rustc_lint_diagnostics]`?
+        let Some(inst) =
+            ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args).ok().flatten()
+        else {
             return;
-        }
+        };
+        let has_attr = cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics);
+        if !has_attr {
+            return;
+        };
 
-        // Is the parent method marked with `#[rustc_lint_diagnostics]`?
-        let mut parent_has_attr = false;
-        for (hir_id, _parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
+        for (hir_id, _parent) in cx.tcx.hir().parent_iter(current_id) {
             if let Some(owner_did) = hir_id.as_owner()
                 && cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics)
             {
-                parent_has_attr = true;
-                break;
+                // The parent method is marked with `#[rustc_lint_diagnostics]`
+                return;
             }
         }
 
@@ -500,37 +531,22 @@ impl LateLintPass<'_> for Diagnostics {
         // - inside a parent function that is itself marked with `#[rustc_lint_diagnostics]`.
         //
         // Otherwise, emit a `DIAGNOSTIC_OUTSIDE_OF_IMPL` lint.
-        if has_attr && !parent_has_attr {
-            let mut is_inside_appropriate_impl = false;
-            for (_hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
-                debug!(?parent);
-                if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
-                    && let Impl { of_trait: Some(of_trait), .. } = impl_
-                    && let Some(def_id) = of_trait.trait_def_id()
-                    && let Some(name) = cx.tcx.get_diagnostic_name(def_id)
-                    && matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
-                {
-                    is_inside_appropriate_impl = true;
-                    break;
-                }
-            }
-            debug!(?is_inside_appropriate_impl);
-            if !is_inside_appropriate_impl {
-                cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
+        let mut is_inside_appropriate_impl = false;
+        for (_hir_id, parent) in cx.tcx.hir().parent_iter(current_id) {
+            debug!(?parent);
+            if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
+                && let Impl { of_trait: Some(of_trait), .. } = impl_
+                && let Some(def_id) = of_trait.trait_def_id()
+                && let Some(name) = cx.tcx.get_diagnostic_name(def_id)
+                && matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
+            {
+                is_inside_appropriate_impl = true;
+                break;
             }
         }
-
-        // Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg
-        // with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an
-        // `UNTRANSLATABLE_DIAGNOSTIC` lint.
-        for (param_i, param_i_p_name) in impl_into_diagnostic_message_params {
-            // Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`?
-            let arg_ty = call_tys[param_i];
-            let is_translatable = is_diag_message(arg_ty)
-                || matches!(arg_ty.kind(), ty::Param(p) if p.name == param_i_p_name);
-            if !is_translatable {
-                cx.emit_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag);
-            }
+        debug!(?is_inside_appropriate_impl);
+        if !is_inside_appropriate_impl {
+            cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
         }
     }
 }
diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
index a4f6d7afe4d..32e2f3b4b16 100644
--- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
+++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
@@ -2,7 +2,7 @@
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{ItemLocalId, OwnerId};
 use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable};
 
@@ -11,9 +11,9 @@ use crate::ty;
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum ResolvedArg {
     StaticLifetime,
-    EarlyBound(/* decl */ DefId),
-    LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId),
-    Free(DefId, /* lifetime decl */ DefId),
+    EarlyBound(/* decl */ LocalDefId),
+    LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ LocalDefId),
+    Free(LocalDefId, /* lifetime decl */ LocalDefId),
     Error(ErrorGuaranteed),
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 9b39b849704..cad3515f068 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -3035,13 +3035,13 @@ impl<'tcx> TyCtxt<'tcx> {
 
             match self.named_bound_var(lifetime.hir_id) {
                 Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => {
-                    let new_parent = self.parent(ebv);
+                    let new_parent = self.local_parent(ebv);
 
                     // If we map to another opaque, then it should be a parent
                     // of the opaque we mapped from. Continue mapping.
                     if matches!(self.def_kind(new_parent), DefKind::OpaqueTy) {
-                        debug_assert_eq!(self.parent(parent.to_def_id()), new_parent);
-                        opaque_lifetime_param_def_id = ebv.expect_local();
+                        debug_assert_eq!(self.local_parent(parent), new_parent);
+                        opaque_lifetime_param_def_id = ebv;
                         continue;
                     }
 
@@ -3050,20 +3050,20 @@ impl<'tcx> TyCtxt<'tcx> {
                         self,
                         ty::EarlyParamRegion {
                             index: generics
-                                .param_def_id_to_index(self, ebv)
+                                .param_def_id_to_index(self, ebv.to_def_id())
                                 .expect("early-bound var should be present in fn generics"),
-                            name: self.hir().name(self.local_def_id_to_hir_id(ebv.expect_local())),
+                            name: self.item_name(ebv.to_def_id()),
                         },
                     );
                 }
                 Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => {
-                    let new_parent = self.parent(lbv);
+                    let new_parent = self.local_parent(lbv);
                     return ty::Region::new_late_param(
                         self,
-                        new_parent,
+                        new_parent.to_def_id(),
                         ty::BoundRegionKind::BrNamed(
-                            lbv,
-                            self.hir().name(self.local_def_id_to_hir_id(lbv.expect_local())),
+                            lbv.to_def_id(),
+                            self.item_name(lbv.to_def_id()),
                         ),
                     );
                 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 319fb7ef03b..f1ff90831b0 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3119,7 +3119,10 @@ define_print! {
 
     ty::ExistentialProjection<'tcx> {
         let name = cx.tcx().associated_item(self.def_id).name;
-        p!(write("{} = ", name), print(self.term))
+        // The args don't contain the self ty (as it has been erased) but the corresp.
+        // generics do as the trait always has a self ty param. We need to offset.
+        let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..];
+        p!(path_generic_args(|cx| write!(cx, "{name}"), args), " = ", print(self.term))
     }
 
     ty::ProjectionPredicate<'tcx> {
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 434df35a515..5e1b1b44bc2 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1415,6 +1415,14 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
 
     // Overwrite the dummy data with our decoded SyntaxContextData
     HygieneData::with(|hygiene_data| {
+        if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize)
+            && old.outer_expn == ctxt_data.outer_expn
+            && old.outer_transparency == ctxt_data.outer_transparency
+            && old.parent == ctxt_data.parent
+        {
+            ctxt_data = old.clone();
+        }
+
         let dummy = std::mem::replace(
             &mut hygiene_data.syntax_context_data[ctxt.as_u32() as usize],
             ctxt_data,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
index 3f35391be13..cd61747917a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
@@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
                     // region at the right depth with the same index
                     (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
                         debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
-                        if id == def_id {
+                        if id.to_def_id() == def_id {
                             return ControlFlow::Break(arg);
                         }
                     }
@@ -118,7 +118,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
                             debruijn_index
                         );
                         debug!("LateBound id={:?} def_id={:?}", id, def_id);
-                        if debruijn_index == self.current_index && id == def_id {
+                        if debruijn_index == self.current_index && id.to_def_id() == def_id {
                             return ControlFlow::Break(arg);
                         }
                     }
@@ -192,7 +192,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
             // the lifetime of the TyPath!
             (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
                 debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
-                if id == def_id {
+                if id.to_def_id() == def_id {
                     return ControlFlow::Break(());
                 }
             }
@@ -201,7 +201,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
                 debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,);
                 debug!("id={:?}", id);
                 debug!("def_id={:?}", def_id);
-                if debruijn_index == self.current_index && id == def_id {
+                if debruijn_index == self.current_index && id.to_def_id() == def_id {
                     return ControlFlow::Break(());
                 }
             }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
index 9c772f42cca..f2a7da707b8 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs
@@ -11,7 +11,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
     pub(super) fn try_report_placeholder_relation(&self) -> Option<Diag<'tcx>> {
         match &self.error {
             Some(RegionResolutionError::ConcreteFailure(
-                SubregionOrigin::RelateRegionParamBound(span),
+                SubregionOrigin::RelateRegionParamBound(span, _),
                 Region(Interned(
                     RePlaceholder(ty::Placeholder {
                         bound: ty::BoundRegion { kind: sub_name, .. },
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
index 04e1be22a4d..600da730845 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
@@ -52,7 +52,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         .add_to_diag(err);
                 }
             }
-            infer::RelateRegionParamBound(span) => {
+            infer::RelateRegionParamBound(span, _) => {
                 RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
                     .add_to_diag(err);
             }
@@ -199,7 +199,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     note,
                 })
             }
-            infer::RelateRegionParamBound(span) => {
+            infer::RelateRegionParamBound(span, _) => {
                 let param_instantiated = note_and_explain::RegionExplanation::new(
                     self.tcx,
                     generic_param_scope,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 877a8a23d7f..ada44b632d4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -257,7 +257,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     .add_to_diag(err);
                 }
             }
-            infer::RelateRegionParamBound(span) => {
+            infer::RelateRegionParamBound(span, _) => {
                 RegionOriginNote::Plain {
                     span,
                     msg: fluent::trait_selection_relate_region_param_bound,
@@ -410,7 +410,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     note,
                 })
             }
-            infer::RelateRegionParamBound(span) => {
+            infer::RelateRegionParamBound(span, ty) => {
                 let param_instantiated = note_and_explain::RegionExplanation::new(
                     self.tcx,
                     generic_param_scope,
@@ -419,11 +419,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     note_and_explain::PrefixKind::LfParamInstantiatedWith,
                     note_and_explain::SuffixKind::Empty,
                 );
+                let mut alt_span = None;
+                if let Some(ty) = ty
+                    && sub.is_static()
+                    && let ty::Dynamic(preds, _, ty::DynKind::Dyn) = ty.kind()
+                    && let Some(def_id) = preds.principal_def_id()
+                {
+                    for (clause, span) in
+                        self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
+                    {
+                        if let ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) =
+                            clause.kind().skip_binder()
+                            && let ty::Param(param) = a.kind()
+                            && param.name == kw::SelfUpper
+                            && b.is_static()
+                        {
+                            // Point at explicit `'static` bound on the trait (`trait T: 'static`).
+                            alt_span = Some(span);
+                        }
+                    }
+                }
                 let param_must_outlive = note_and_explain::RegionExplanation::new(
                     self.tcx,
                     generic_param_scope,
                     sub,
-                    None,
+                    alt_span,
                     note_and_explain::PrefixKind::LfParamMustOutlive,
                     note_and_explain::SuffixKind::Empty,
                 );
@@ -1079,16 +1099,8 @@ fn msg_span_from_named_region<'tcx>(
 ) -> (String, Option<Span>) {
     match *region {
         ty::ReEarlyParam(br) => {
-            let scope = tcx
-                .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
-                .expect_local();
-            let span = if let Some(param) =
-                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
-            {
-                param.span
-            } else {
-                tcx.def_span(scope)
-            };
+            let param_def_id = tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id;
+            let span = tcx.def_span(param_def_id);
             let text = if br.has_name() {
                 format!("the lifetime `{}` as defined here", br.name)
             } else {
@@ -1104,16 +1116,8 @@ fn msg_span_from_named_region<'tcx>(
                 ("the anonymous lifetime defined here".to_string(), Some(ty.span))
             } else {
                 match fr.bound_region {
-                    ty::BoundRegionKind::BrNamed(_, name) => {
-                        let span = if let Some(param) = tcx
-                            .hir()
-                            .get_generics(generic_param_scope)
-                            .and_then(|generics| generics.get_named(name))
-                        {
-                            param.span
-                        } else {
-                            tcx.def_span(generic_param_scope)
-                        };
+                    ty::BoundRegionKind::BrNamed(param_def_id, name) => {
+                        let span = tcx.def_span(param_def_id);
                         let text = if name == kw::UnderscoreLifetime {
                             "the anonymous lifetime as defined here".to_string()
                         } else {
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 375358dddf5..ce09a0b444d 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -3,8 +3,8 @@
 //! suggestions from rustc if you get anything slightly wrong in here, and overall
 //! helps with clarity as we're also referring to `char` intentionally in here.
 
-use crate::fmt;
 use crate::mem::transmute;
+use crate::{assert_unsafe_precondition, fmt};
 
 /// One of the 128 Unicode characters from U+0000 through U+007F,
 /// often known as the [ASCII] subset.
@@ -497,14 +497,18 @@ impl AsciiChar {
     /// Notably, it should not be expected to return hex digits, or any other
     /// reasonable extension of the decimal digits.
     ///
-    /// (This lose safety condition is intended to simplify soundness proofs
+    /// (This loose safety condition is intended to simplify soundness proofs
     /// when writing code using this method, since the implementation doesn't
     /// need something really specific, not to make those other arguments do
     /// something useful. It might be tightened before stabilization.)
     #[unstable(feature = "ascii_char", issue = "110998")]
     #[inline]
     pub const unsafe fn digit_unchecked(d: u8) -> Self {
-        debug_assert!(d < 10);
+        assert_unsafe_precondition!(
+            check_language_ub,
+            "`AsciiChar::digit_unchecked` input cannot exceed 9.",
+            (d: u8 = d) => d < 10
+        );
 
         // SAFETY: `'0'` through `'9'` are U+00030 through U+0039,
         // so because `d` must be 64 or less the addition can return at most
diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs
index 097fa86c938..87df8a4e272 100644
--- a/library/core/src/cell/once.rs
+++ b/library/core/src/cell/once.rs
@@ -309,7 +309,8 @@ impl<T> OnceCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
-    pub fn into_inner(self) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    pub const fn into_inner(self) -> Option<T> {
         // Because `into_inner` takes `self` by value, the compiler statically verifies
         // that it is not currently borrowed. So it is safe to move out `Option<T>`.
         self.inner.into_inner()
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index 467fa17a6f3..c7c462a4df1 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -78,7 +78,7 @@ impl fmt::Write for PadAdapter<'_, '_> {
 ///
 /// assert_eq!(
 ///     format!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }),
-///     "Foo { bar: 10, baz: \"Hello World\" }",
+///     r#"Foo { bar: 10, baz: "Hello World" }"#,
 /// );
 /// ```
 #[must_use = "must eventually call `finish()` on Debug builders"]
@@ -125,7 +125,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Bar { bar: 10, another: "Hello World".to_string() }),
-    ///     "Bar { bar: 10, another: \"Hello World\", nonexistent_field: 1 }",
+    ///     r#"Bar { bar: 10, another: "Hello World", nonexistent_field: 1 }"#,
     /// );
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -237,7 +237,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Bar { bar: 10, baz: "Hello World".to_string() }),
-    ///     "Bar { bar: 10, baz: \"Hello World\" }",
+    ///     r#"Bar { bar: 10, baz: "Hello World" }"#,
     /// );
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -280,7 +280,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
 ///
 /// assert_eq!(
 ///     format!("{:?}", Foo(10, "Hello World".to_string())),
-///     "Foo(10, \"Hello World\")",
+///     r#"Foo(10, "Hello World")"#,
 /// );
 /// ```
 #[must_use = "must eventually call `finish()` on Debug builders"]
@@ -322,7 +322,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Foo(10, "Hello World".to_string())),
-    ///     "Foo(10, \"Hello World\")",
+    ///     r#"Foo(10, "Hello World")"#,
     /// );
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -360,6 +360,51 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
         self
     }
 
+    /// Marks the tuple struct as non-exhaustive, indicating to the reader that there are some
+    /// other fields that are not shown in the debug representation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(debug_more_non_exhaustive)]
+    ///
+    /// use std::fmt;
+    ///
+    /// struct Foo(i32, String);
+    ///
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         fmt.debug_tuple("Foo")
+    ///            .field(&self.0)
+    ///            .finish_non_exhaustive() // Show that some other field(s) exist.
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(
+    ///     format!("{:?}", Foo(10, "secret!".to_owned())),
+    ///     "Foo(10, ..)",
+    /// );
+    /// ```
+    #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")]
+    pub fn finish_non_exhaustive(&mut self) -> fmt::Result {
+        self.result = self.result.and_then(|_| {
+            if self.fields > 0 {
+                if self.is_pretty() {
+                    let mut slot = None;
+                    let mut state = Default::default();
+                    let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
+                    writer.write_str("..\n")?;
+                    self.fmt.write_str(")")
+                } else {
+                    self.fmt.write_str(", ..)")
+                }
+            } else {
+                self.fmt.write_str("(..)")
+            }
+        });
+        self.result
+    }
+
     /// Finishes output and returns any error encountered.
     ///
     /// # Examples
@@ -381,7 +426,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Foo(10, "Hello World".to_string())),
-    ///     "Foo(10, \"Hello World\")",
+    ///     r#"Foo(10, "Hello World")"#,
     /// );
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -555,6 +600,56 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
         self
     }
 
+    /// Marks the set as non-exhaustive, indicating to the reader that there are some other
+    /// elements that are not shown in the debug representation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(debug_more_non_exhaustive)]
+    ///
+    /// use std::fmt;
+    ///
+    /// struct Foo(Vec<i32>);
+    ///
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         // Print at most two elements, abbreviate the rest
+    ///         let mut f = fmt.debug_set();
+    ///         let mut f = f.entries(self.0.iter().take(2));
+    ///         if self.0.len() > 2 {
+    ///             f.finish_non_exhaustive()
+    ///         } else {
+    ///             f.finish()
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(
+    ///     format!("{:?}", Foo(vec![1, 2, 3, 4])),
+    ///     "{1, 2, ..}",
+    /// );
+    /// ```
+    #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")]
+    pub fn finish_non_exhaustive(&mut self) -> fmt::Result {
+        self.inner.result = self.inner.result.and_then(|_| {
+            if self.inner.has_fields {
+                if self.inner.is_pretty() {
+                    let mut slot = None;
+                    let mut state = Default::default();
+                    let mut writer = PadAdapter::wrap(self.inner.fmt, &mut slot, &mut state);
+                    writer.write_str("..\n")?;
+                    self.inner.fmt.write_str("}")
+                } else {
+                    self.inner.fmt.write_str(", ..}")
+                }
+            } else {
+                self.inner.fmt.write_str("..}")
+            }
+        });
+        self.inner.result
+    }
+
     /// Finishes output and returns any error encountered.
     ///
     /// # Examples
@@ -699,6 +794,55 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
         self
     }
 
+    /// Marks the list as non-exhaustive, indicating to the reader that there are some other
+    /// elements that are not shown in the debug representation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(debug_more_non_exhaustive)]
+    ///
+    /// use std::fmt;
+    ///
+    /// struct Foo(Vec<i32>);
+    ///
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         // Print at most two elements, abbreviate the rest
+    ///         let mut f = fmt.debug_list();
+    ///         let mut f = f.entries(self.0.iter().take(2));
+    ///         if self.0.len() > 2 {
+    ///             f.finish_non_exhaustive()
+    ///         } else {
+    ///             f.finish()
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(
+    ///     format!("{:?}", Foo(vec![1, 2, 3, 4])),
+    ///     "[1, 2, ..]",
+    /// );
+    /// ```
+    #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")]
+    pub fn finish_non_exhaustive(&mut self) -> fmt::Result {
+        self.inner.result.and_then(|_| {
+            if self.inner.has_fields {
+                if self.inner.is_pretty() {
+                    let mut slot = None;
+                    let mut state = Default::default();
+                    let mut writer = PadAdapter::wrap(self.inner.fmt, &mut slot, &mut state);
+                    writer.write_str("..\n")?;
+                    self.inner.fmt.write_str("]")
+                } else {
+                    self.inner.fmt.write_str(", ..]")
+                }
+            } else {
+                self.inner.fmt.write_str("..]")
+            }
+        })
+    }
+
     /// Finishes output and returns any error encountered.
     ///
     /// # Examples
@@ -750,7 +894,7 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
 ///
 /// assert_eq!(
 ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
-///     "{\"A\": 10, \"B\": 11}",
+///     r#"{"A": 10, "B": 11}"#,
 /// );
 /// ```
 #[must_use = "must eventually call `finish()` on Debug builders"]
@@ -790,7 +934,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
-    ///     "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
+    ///     r#"{"whole": [("A", 10), ("B", 11)]}"#,
     /// );
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -826,7 +970,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
-    ///     "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
+    ///     r#"{"whole": [("A", 10), ("B", 11)]}"#,
     /// );
     /// ```
     #[stable(feature = "debug_map_key_value", since = "1.42.0")]
@@ -902,7 +1046,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
-    ///     "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
+    ///     r#"{"whole": [("A", 10), ("B", 11)]}"#,
     /// );
     /// ```
     #[stable(feature = "debug_map_key_value", since = "1.42.0")]
@@ -960,7 +1104,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
-    ///     "{\"A\": 10, \"B\": 11}",
+    ///     r#"{"A": 10, "B": 11}"#,
     /// );
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
@@ -976,6 +1120,62 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
         self
     }
 
+    /// Marks the map as non-exhaustive, indicating to the reader that there are some other
+    /// entries that are not shown in the debug representation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(debug_more_non_exhaustive)]
+    ///
+    /// use std::fmt;
+    ///
+    /// struct Foo(Vec<(String, i32)>);
+    ///
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         // Print at most two elements, abbreviate the rest
+    ///         let mut f = fmt.debug_map();
+    ///         let mut f = f.entries(self.0.iter().take(2).map(|&(ref k, ref v)| (k, v)));
+    ///         if self.0.len() > 2 {
+    ///             f.finish_non_exhaustive()
+    ///         } else {
+    ///             f.finish()
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(
+    ///     format!("{:?}", Foo(vec![
+    ///         ("A".to_string(), 10),
+    ///         ("B".to_string(), 11),
+    ///         ("C".to_string(), 12),
+    ///     ])),
+    ///     r#"{"A": 10, "B": 11, ..}"#,
+    /// );
+    /// ```
+    #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")]
+    pub fn finish_non_exhaustive(&mut self) -> fmt::Result {
+        self.result = self.result.and_then(|_| {
+            assert!(!self.has_key, "attempted to finish a map with a partial entry");
+
+            if self.has_fields {
+                if self.is_pretty() {
+                    let mut slot = None;
+                    let mut state = Default::default();
+                    let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
+                    writer.write_str("..\n")?;
+                    self.fmt.write_str("}")
+                } else {
+                    self.fmt.write_str(", ..}")
+                }
+            } else {
+                self.fmt.write_str("..}")
+            }
+        });
+        self.result
+    }
+
     /// Finishes output and returns any error encountered.
     ///
     /// # Panics
@@ -1000,7 +1200,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     ///
     /// assert_eq!(
     ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
-    ///     "{\"A\": 10, \"B\": 11}",
+    ///     r#"{"A": 10, "B": 11}"#,
     /// );
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index b65b48c162d..c1a8c34539e 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -10,7 +10,7 @@ use crate::intrinsics::{self, const_eval_select};
 /// macro for language UB are always ignored.
 ///
 /// This macro should be called as
-/// `assert_unsafe_precondition!(check_{library,lang}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)`
+/// `assert_unsafe_precondition!(check_{library,language}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)`
 /// where each `expr` will be evaluated and passed in as function argument `ident: type`. Then all
 /// those arguments are passed to a function with the body `check_expr`.
 /// Pick `check_language_ub` when this is guarding a violation of language UB, i.e., immediate UB
diff --git a/library/core/tests/fmt/builders.rs b/library/core/tests/fmt/builders.rs
index 2bdc334b7c0..ba4801f5912 100644
--- a/library/core/tests/fmt/builders.rs
+++ b/library/core/tests/fmt/builders.rs
@@ -79,23 +79,23 @@ mod debug_struct {
         }
 
         assert_eq!(
-            "Bar { foo: Foo { bar: true, baz: 10/20 }, hello: \"world\" }",
+            r#"Bar { foo: Foo { bar: true, baz: 10/20 }, hello: "world" }"#,
             format!("{Bar:?}")
         );
         assert_eq!(
-            "Bar {
+            r#"Bar {
     foo: Foo {
         bar: true,
         baz: 10/20,
     },
-    hello: \"world\",
-}",
+    hello: "world",
+}"#,
             format!("{Bar:#?}")
         );
     }
 
     #[test]
-    fn test_only_non_exhaustive() {
+    fn test_empty_non_exhaustive() {
         struct Foo;
 
         impl fmt::Debug for Foo {
@@ -157,19 +157,19 @@ mod debug_struct {
         }
 
         assert_eq!(
-            "Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }",
+            r#"Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: "world", .. }"#,
             format!("{Bar:?}")
         );
         assert_eq!(
-            "Bar {
+            r#"Bar {
     foo: Foo {
         bar: true,
         baz: 10/20,
         ..
     },
-    hello: \"world\",
+    hello: "world",
     ..
-}",
+}"#,
             format!("{Bar:#?}")
         );
     }
@@ -249,15 +249,89 @@ mod debug_tuple {
             }
         }
 
-        assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{Bar:?}"));
+        assert_eq!(r#"Bar(Foo(true, 10/20), "world")"#, format!("{Bar:?}"));
         assert_eq!(
-            "Bar(
+            r#"Bar(
     Foo(
         true,
         10/20,
     ),
-    \"world\",
+    "world",
+)"#,
+            format!("{Bar:#?}")
+        );
+    }
+
+    #[test]
+    fn test_empty_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_tuple("Foo").finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!("Foo(..)", format!("{Foo:?}"));
+        assert_eq!("Foo(..)", format!("{Foo:#?}"));
+    }
+
+    #[test]
+    fn test_multiple_and_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_tuple("Foo")
+                    .field(&true)
+                    .field(&format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!("Foo(true, 10/20, ..)", format!("{Foo:?}"));
+        assert_eq!(
+            "Foo(
+    true,
+    10/20,
+    ..
 )",
+            format!("{Foo:#?}")
+        );
+    }
+
+    #[test]
+    fn test_nested_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_tuple("Foo")
+                    .field(&true)
+                    .field(&format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        struct Bar;
+
+        impl fmt::Debug for Bar {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_tuple("Bar").field(&Foo).field(&"world").finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!(r#"Bar(Foo(true, 10/20, ..), "world", ..)"#, format!("{Bar:?}"));
+        assert_eq!(
+            r#"Bar(
+    Foo(
+        true,
+        10/20,
+        ..
+    ),
+    "world",
+    ..
+)"#,
             format!("{Bar:#?}")
         );
     }
@@ -301,11 +375,11 @@ mod debug_map {
         assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
         assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
 
-        assert_eq!("{\"bar\": true}", format!("{Entry:?}"));
+        assert_eq!(r#"{"bar": true}"#, format!("{Entry:?}"));
         assert_eq!(
-            "{
-    \"bar\": true,
-}",
+            r#"{
+    "bar": true,
+}"#,
             format!("{Entry:#?}")
         );
     }
@@ -339,12 +413,12 @@ mod debug_map {
         assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
         assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
 
-        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{Entry:?}"));
+        assert_eq!(r#"{"bar": true, 10: 10/20}"#, format!("{Entry:?}"));
         assert_eq!(
-            "{
-    \"bar\": true,
+            r#"{
+    "bar": true,
     10: 10/20,
-}",
+}"#,
             format!("{Entry:#?}")
         );
     }
@@ -371,21 +445,20 @@ mod debug_map {
         }
 
         assert_eq!(
-            "{\"foo\": {\"bar\": true, 10: 10/20}, \
-                    {\"bar\": true, 10: 10/20}: \"world\"}",
+            r#"{"foo": {"bar": true, 10: 10/20}, {"bar": true, 10: 10/20}: "world"}"#,
             format!("{Bar:?}")
         );
         assert_eq!(
-            "{
-    \"foo\": {
-        \"bar\": true,
+            r#"{
+    "foo": {
+        "bar": true,
         10: 10/20,
     },
     {
-        \"bar\": true,
+        "bar": true,
         10: 10/20,
-    }: \"world\",
-}",
+    }: "world",
+}"#,
             format!("{Bar:#?}")
         );
     }
@@ -471,6 +544,103 @@ mod debug_map {
 
         let _ = format!("{Foo:?}");
     }
+
+    #[test]
+    fn test_empty_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map().finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!("{..}", format!("{Foo:?}"));
+        assert_eq!("{..}", format!("{Foo:#?}"));
+    }
+
+    #[test]
+    fn test_multiple_and_non_exhaustive() {
+        struct Entry;
+
+        impl fmt::Debug for Entry {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .entry(&"bar", &true)
+                    .entry(&10, &format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        struct KeyValue;
+
+        impl fmt::Debug for KeyValue {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar")
+                    .value(&true)
+                    .key(&10)
+                    .value(&format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+        assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
+
+        assert_eq!(r#"{"bar": true, 10: 10/20, ..}"#, format!("{Entry:?}"));
+        assert_eq!(
+            r#"{
+    "bar": true,
+    10: 10/20,
+    ..
+}"#,
+            format!("{Entry:#?}")
+        );
+    }
+
+    #[test]
+    fn test_nested_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .entry(&"bar", &true)
+                    .entry(&10, &format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        struct Bar;
+
+        impl fmt::Debug for Bar {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map().entry(&"foo", &Foo).entry(&Foo, &"world").finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!(
+            r#"{"foo": {"bar": true, 10: 10/20, ..}, {"bar": true, 10: 10/20, ..}: "world", ..}"#,
+            format!("{Bar:?}")
+        );
+        assert_eq!(
+            r#"{
+    "foo": {
+        "bar": true,
+        10: 10/20,
+        ..
+    },
+    {
+        "bar": true,
+        10: 10/20,
+        ..
+    }: "world",
+    ..
+}"#,
+            format!("{Bar:#?}")
+        );
+    }
 }
 
 mod debug_set {
@@ -547,15 +717,89 @@ mod debug_set {
             }
         }
 
-        assert_eq!("{{true, 10/20}, \"world\"}", format!("{Bar:?}"));
+        assert_eq!(r#"{{true, 10/20}, "world"}"#, format!("{Bar:?}"));
         assert_eq!(
-            "{
+            r#"{
     {
         true,
         10/20,
     },
-    \"world\",
+    "world",
+}"#,
+            format!("{Bar:#?}")
+        );
+    }
+
+    #[test]
+    fn test_empty_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_set().finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!("{..}", format!("{Foo:?}"));
+        assert_eq!("{..}", format!("{Foo:#?}"));
+    }
+
+    #[test]
+    fn test_multiple_and_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_set()
+                    .entry(&true)
+                    .entry(&format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!("{true, 10/20, ..}", format!("{Foo:?}"));
+        assert_eq!(
+            "{
+    true,
+    10/20,
+    ..
 }",
+            format!("{Foo:#?}")
+        );
+    }
+
+    #[test]
+    fn test_nested_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_set()
+                    .entry(&true)
+                    .entry(&format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        struct Bar;
+
+        impl fmt::Debug for Bar {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_set().entry(&Foo).entry(&"world").finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!(r#"{{true, 10/20, ..}, "world", ..}"#, format!("{Bar:?}"));
+        assert_eq!(
+            r#"{
+    {
+        true,
+        10/20,
+        ..
+    },
+    "world",
+    ..
+}"#,
             format!("{Bar:#?}")
         );
     }
@@ -635,15 +879,89 @@ mod debug_list {
             }
         }
 
-        assert_eq!("[[true, 10/20], \"world\"]", format!("{Bar:?}"));
+        assert_eq!(r#"[[true, 10/20], "world"]"#, format!("{Bar:?}"));
         assert_eq!(
-            "[
+            r#"[
     [
         true,
         10/20,
     ],
-    \"world\",
+    "world",
+]"#,
+            format!("{Bar:#?}")
+        );
+    }
+
+    #[test]
+    fn test_empty_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_list().finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!("[..]", format!("{Foo:?}"));
+        assert_eq!("[..]", format!("{Foo:#?}"));
+    }
+
+    #[test]
+    fn test_multiple_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_list()
+                    .entry(&true)
+                    .entry(&format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!("[true, 10/20, ..]", format!("{Foo:?}"));
+        assert_eq!(
+            "[
+    true,
+    10/20,
+    ..
 ]",
+            format!("{Foo:#?}")
+        );
+    }
+
+    #[test]
+    fn test_nested_non_exhaustive() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_list()
+                    .entry(&true)
+                    .entry(&format_args!("{}/{}", 10, 20))
+                    .finish_non_exhaustive()
+            }
+        }
+
+        struct Bar;
+
+        impl fmt::Debug for Bar {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_list().entry(&Foo).entry(&"world").finish_non_exhaustive()
+            }
+        }
+
+        assert_eq!(r#"[[true, 10/20, ..], "world", ..]"#, format!("{Bar:?}"));
+        assert_eq!(
+            r#"[
+    [
+        true,
+        10/20,
+        ..
+    ],
+    "world",
+    ..
+]"#,
             format!("{Bar:#?}")
         );
     }
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 2f0d03abed3..073429c7628 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -43,6 +43,7 @@
 #![feature(core_io_borrowed_buf)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
+#![feature(debug_more_non_exhaustive)]
 #![feature(dec2flt)]
 #![feature(duration_constants)]
 #![feature(duration_constructors)]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index c5edb03bb08..6a0d9f47960 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2491,6 +2491,8 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///
 /// Consider ignoring the error if validating the removal is not required for your use case.
 ///
+/// [`io::ErrorKind::NotFound`] is only returned if no removal occurs.
+///
 /// [`fs::remove_file`]: remove_file
 /// [`fs::remove_dir`]: remove_dir
 ///
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index a58ca543d67..9ec3e387e2b 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -2,7 +2,6 @@
 //!
 //! [`std::fs`]: crate::fs
 
-#![deny(unsafe_op_in_unsafe_fn)]
 #![unstable(feature = "wasi_ext", issue = "71213")]
 
 // Used for `File::read` on intra-doc links
diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs
index e36b93e60ea..33b50c9e53b 100644
--- a/library/std/src/os/wasi/mod.rs
+++ b/library/std/src/os/wasi/mod.rs
@@ -30,7 +30,7 @@
 
 #![cfg_attr(not(target_env = "p2"), stable(feature = "rust1", since = "1.0.0"))]
 #![cfg_attr(target_env = "p2", unstable(feature = "wasip2", issue = "none"))]
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 #![doc(cfg(target_os = "wasi"))]
 
 pub mod ffi;
diff --git a/library/std/src/os/wasip2/mod.rs b/library/std/src/os/wasip2/mod.rs
index 1d44dd72814..809a288f20d 100644
--- a/library/std/src/os/wasip2/mod.rs
+++ b/library/std/src/os/wasip2/mod.rs
@@ -2,4 +2,5 @@
 //!
 //! This module is currently empty, but will be filled over time as wasi-libc support for WASI Preview 2 is stabilized.
 
+#![forbid(unsafe_op_in_unsafe_fn)]
 #![stable(feature = "raw_ext", since = "1.1.0")]
diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs
index 8179ec8821a..591be66fcb4 100644
--- a/library/std/src/sys/pal/solid/fs.rs
+++ b/library/std/src/sys/pal/solid/fs.rs
@@ -10,6 +10,7 @@ use crate::sync::Arc;
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
 pub use crate::sys_common::fs::exists;
+use crate::sys_common::ignore_notfound;
 
 /// A file descriptor.
 #[derive(Clone, Copy)]
@@ -527,15 +528,23 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
 
 pub fn remove_dir_all(path: &Path) -> io::Result<()> {
     for child in readdir(path)? {
-        let child = child?;
-        let child_type = child.file_type()?;
-        if child_type.is_dir() {
-            remove_dir_all(&child.path())?;
-        } else {
-            unlink(&child.path())?;
+        let result: io::Result<()> = try {
+            let child = child?;
+            let child_type = child.file_type()?;
+            if child_type.is_dir() {
+                remove_dir_all(&child.path())?;
+            } else {
+                unlink(&child.path())?;
+            }
+        };
+        // ignore internal NotFound errors
+        if let Err(err) = result
+            && err.kind() != io::ErrorKind::NotFound
+        {
+            return result;
         }
     }
-    rmdir(path)
+    ignore_notfound(rmdir(path))
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index be13e1ae9b3..fc9d7e98883 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -2002,6 +2002,7 @@ mod remove_dir_impl {
     use crate::path::{Path, PathBuf};
     use crate::sys::common::small_c_string::run_path_with_cstr;
     use crate::sys::{cvt, cvt_r};
+    use crate::sys_common::ignore_notfound;
 
     pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
         let fd = cvt_r(|| unsafe {
@@ -2055,6 +2056,16 @@ mod remove_dir_impl {
         }
     }
 
+    fn is_enoent(result: &io::Result<()>) -> bool {
+        if let Err(err) = result
+            && matches!(err.raw_os_error(), Some(libc::ENOENT))
+        {
+            true
+        } else {
+            false
+        }
+    }
+
     fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
         // try opening as directory
         let fd = match openat_nofollow_dironly(parent_fd, &path) {
@@ -2078,27 +2089,35 @@ mod remove_dir_impl {
         for child in dir {
             let child = child?;
             let child_name = child.name_cstr();
-            match is_dir(&child) {
-                Some(true) => {
-                    remove_dir_all_recursive(Some(fd), child_name)?;
-                }
-                Some(false) => {
-                    cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?;
-                }
-                None => {
-                    // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
-                    // if the process has the appropriate privileges. This however can causing orphaned
-                    // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
-                    // into it first instead of trying to unlink() it.
-                    remove_dir_all_recursive(Some(fd), child_name)?;
+            // we need an inner try block, because if one of these
+            // directories has already been deleted, then we need to
+            // continue the loop, not return ok.
+            let result: io::Result<()> = try {
+                match is_dir(&child) {
+                    Some(true) => {
+                        remove_dir_all_recursive(Some(fd), child_name)?;
+                    }
+                    Some(false) => {
+                        cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?;
+                    }
+                    None => {
+                        // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
+                        // if the process has the appropriate privileges. This however can causing orphaned
+                        // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
+                        // into it first instead of trying to unlink() it.
+                        remove_dir_all_recursive(Some(fd), child_name)?;
+                    }
                 }
+            };
+            if result.is_err() && !is_enoent(&result) {
+                return result;
             }
         }
 
         // unlink the directory after removing its contents
-        cvt(unsafe {
+        ignore_notfound(cvt(unsafe {
             unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), path.as_ptr(), libc::AT_REMOVEDIR)
-        })?;
+        }))?;
         Ok(())
     }
 
diff --git a/library/std/src/sys/pal/wasi/args.rs b/library/std/src/sys/pal/wasi/args.rs
index 6b6d1b8ff4e..52cfa202af8 100644
--- a/library/std/src/sys/pal/wasi/args.rs
+++ b/library/std/src/sys/pal/wasi/args.rs
@@ -1,4 +1,4 @@
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use crate::ffi::{CStr, OsStr, OsString};
 use crate::os::wasi::ffi::OsStrExt;
diff --git a/library/std/src/sys/pal/wasi/env.rs b/library/std/src/sys/pal/wasi/env.rs
index 730e356d7fe..8d444982673 100644
--- a/library/std/src/sys/pal/wasi/env.rs
+++ b/library/std/src/sys/pal/wasi/env.rs
@@ -1,3 +1,5 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+
 pub mod os {
     pub const FAMILY: &str = "";
     pub const OS: &str = "";
diff --git a/library/std/src/sys/pal/wasi/fd.rs b/library/std/src/sys/pal/wasi/fd.rs
index 8966e4b80ad..19b60157e2e 100644
--- a/library/std/src/sys/pal/wasi/fd.rs
+++ b/library/std/src/sys/pal/wasi/fd.rs
@@ -1,4 +1,4 @@
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 #![allow(dead_code)]
 
 use super::err2io;
diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs
index 11900886f0b..88b1e543ec7 100644
--- a/library/std/src/sys/pal/wasi/fs.rs
+++ b/library/std/src/sys/pal/wasi/fs.rs
@@ -1,4 +1,4 @@
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use super::fd::WasiFd;
 use crate::ffi::{CStr, OsStr, OsString};
@@ -13,7 +13,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr;
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
 pub use crate::sys_common::fs::exists;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner};
 use crate::{fmt, iter, ptr};
 
 pub struct File {
@@ -794,14 +794,22 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> {
             io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found")
         })?;
 
-        if entry.file_type()?.is_dir() {
-            remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?;
-        } else {
-            entry.inner.dir.fd.unlink_file(path)?;
+        let result: io::Result<()> = try {
+            if entry.file_type()?.is_dir() {
+                remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?;
+            } else {
+                entry.inner.dir.fd.unlink_file(path)?;
+            }
+        };
+        // ignore internal NotFound errors
+        if let Err(err) = &result
+            && err.kind() != io::ErrorKind::NotFound
+        {
+            return result;
         }
     }
 
     // Once all this directory's contents are deleted it should be safe to
     // delete the directory tiself.
-    parent.remove_directory(osstr2str(path.as_ref())?)
+    ignore_notfound(parent.remove_directory(osstr2str(path.as_ref())?))
 }
diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs
index 4b770ee23bc..d047bf2fce8 100644
--- a/library/std/src/sys/pal/wasi/helpers.rs
+++ b/library/std/src/sys/pal/wasi/helpers.rs
@@ -1,3 +1,5 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+
 use crate::{io as std_io, mem};
 
 #[inline]
diff --git a/library/std/src/sys/pal/wasi/io.rs b/library/std/src/sys/pal/wasi/io.rs
index 2cd45df88fa..b7c2f03daa0 100644
--- a/library/std/src/sys/pal/wasi/io.rs
+++ b/library/std/src/sys/pal/wasi/io.rs
@@ -1,4 +1,4 @@
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use crate::marker::PhantomData;
 use crate::os::fd::{AsFd, AsRawFd};
diff --git a/library/std/src/sys/pal/wasi/net.rs b/library/std/src/sys/pal/wasi/net.rs
index b4cf94c8781..a6486799828 100644
--- a/library/std/src/sys/pal/wasi/net.rs
+++ b/library/std/src/sys/pal/wasi/net.rs
@@ -1,4 +1,4 @@
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use super::err2io;
 use super::fd::WasiFd;
diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs
index f5b17d9df94..f7701360f5a 100644
--- a/library/std/src/sys/pal/wasi/os.rs
+++ b/library/std/src/sys/pal/wasi/os.rs
@@ -1,4 +1,4 @@
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use core::slice::memchr;
 
diff --git a/library/std/src/sys/pal/wasi/stdio.rs b/library/std/src/sys/pal/wasi/stdio.rs
index 4cc0e4ed5a4..ca49f871e19 100644
--- a/library/std/src/sys/pal/wasi/stdio.rs
+++ b/library/std/src/sys/pal/wasi/stdio.rs
@@ -1,4 +1,4 @@
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use super::fd::WasiFd;
 use crate::io::{self, IoSlice, IoSliceMut};
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index c37acd8dfee..31c9cbd4699 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -1,3 +1,5 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+
 use crate::ffi::CStr;
 use crate::num::NonZero;
 use crate::sys::unsupported;
@@ -73,13 +75,13 @@ impl Thread {
         if #[cfg(target_feature = "atomics")] {
             pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
                 let p = Box::into_raw(Box::new(p));
-                let mut native: libc::pthread_t = mem::zeroed();
-                let mut attr: libc::pthread_attr_t = mem::zeroed();
-                assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+                let mut native: libc::pthread_t = unsafe { mem::zeroed() };
+                let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
+                assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
 
                 let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
 
-                match libc::pthread_attr_setstacksize(&mut attr, stack_size) {
+                match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } {
                     0 => {}
                     n => {
                         assert_eq!(n, libc::EINVAL);
@@ -90,20 +92,20 @@ impl Thread {
                         let page_size = os::page_size();
                         let stack_size =
                             (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
-                        assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
+                        assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0);
                     }
                 };
 
-                let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
+                let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
                 // Note: if the thread creation fails and this assert fails, then p will
                 // be leaked. However, an alternative design could cause double-free
                 // which is clearly worse.
-                assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+                assert_eq!(unsafe {libc::pthread_attr_destroy(&mut attr) }, 0);
 
                 return if ret != 0 {
                     // The thread failed to start and as a result p was not consumed. Therefore, it is
                     // safe to reconstruct the box so that it gets deallocated.
-                    drop(Box::from_raw(p));
+                    unsafe { drop(Box::from_raw(p)); }
                     Err(io::Error::from_raw_os_error(ret))
                 } else {
                     Ok(Thread { id: native })
diff --git a/library/std/src/sys/pal/wasi/time.rs b/library/std/src/sys/pal/wasi/time.rs
index 016b06efbdc..0d8d0b59ac1 100644
--- a/library/std/src/sys/pal/wasi/time.rs
+++ b/library/std/src/sys/pal/wasi/time.rs
@@ -1,4 +1,4 @@
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use crate::time::Duration;
 
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index d99d4931de4..2134152ea93 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -14,7 +14,7 @@ use crate::sys::handle::Handle;
 use crate::sys::path::maybe_verbatim;
 use crate::sys::time::SystemTime;
 use crate::sys::{c, cvt, Align8};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner};
 use crate::{fmt, ptr, slice, thread};
 
 pub struct File {
@@ -1160,7 +1160,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> {
         return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _));
     }
 
-    match remove_dir_all_iterative(&file, File::posix_delete) {
+    match ignore_notfound(remove_dir_all_iterative(&file, File::posix_delete)) {
         Err(e) => {
             if let Some(code) = e.raw_os_error() {
                 match code as u32 {
diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs
index acb6713cf1b..a25a7244660 100644
--- a/library/std/src/sys_common/fs.rs
+++ b/library/std/src/sys_common/fs.rs
@@ -3,6 +3,7 @@
 use crate::fs;
 use crate::io::{self, Error, ErrorKind};
 use crate::path::Path;
+use crate::sys_common::ignore_notfound;
 
 pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!(
     ErrorKind::InvalidInput,
@@ -32,14 +33,22 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> {
 
 fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
     for child in fs::read_dir(path)? {
-        let child = child?;
-        if child.file_type()?.is_dir() {
-            remove_dir_all_recursive(&child.path())?;
-        } else {
-            fs::remove_file(&child.path())?;
+        let result: io::Result<()> = try {
+            let child = child?;
+            if child.file_type()?.is_dir() {
+                remove_dir_all_recursive(&child.path())?;
+            } else {
+                fs::remove_file(&child.path())?;
+            }
+        };
+        // ignore internal NotFound errors to prevent race conditions
+        if let Err(err) = &result
+            && err.kind() != io::ErrorKind::NotFound
+        {
+            return result;
         }
     }
-    fs::remove_dir(path)
+    ignore_notfound(fs::remove_dir(path))
 }
 
 pub fn exists(path: &Path) -> io::Result<bool> {
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 60ee405ecaa..1c884f107be 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -80,3 +80,11 @@ pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
     // r < denom, so (denom*numer) is the upper bound of (r*numer)
     q * numer + r * numer / denom
 }
+
+pub fn ignore_notfound<T>(result: crate::io::Result<T>) -> crate::io::Result<()> {
+    match result {
+        Err(err) if err.kind() == crate::io::ErrorKind::NotFound => Ok(()),
+        Ok(_) => Ok(()),
+        Err(err) => Err(err),
+    }
+}
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 8d20b956213..4957de2e1b7 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -269,34 +269,45 @@ fn make_win_dist(
     let target_libs = find_files(&target_libs, &lib_path);
 
     // Copy runtime dlls next to rustc.exe
-    let dist_bin_dir = rust_root.join("bin/");
-    fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
-    for src in rustc_dlls {
-        builder.copy_link_to_folder(&src, &dist_bin_dir);
+    let rust_bin_dir = rust_root.join("bin/");
+    fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed");
+    for src in &rustc_dlls {
+        builder.copy_link_to_folder(src, &rust_bin_dir);
+    }
+
+    if builder.config.lld_enabled {
+        // rust-lld.exe also needs runtime dlls
+        let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin");
+        fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed");
+        for src in &rustc_dlls {
+            builder.copy_link_to_folder(src, &rust_target_bin_dir);
+        }
     }
 
     //Copy platform tools to platform-specific bin directory
-    let target_bin_dir =
-        plat_root.join("lib").join("rustlib").join(target).join("bin").join("self-contained");
-    fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
+    let plat_target_bin_self_contained_dir =
+        plat_root.join("lib/rustlib").join(target).join("bin/self-contained");
+    fs::create_dir_all(&plat_target_bin_self_contained_dir)
+        .expect("creating plat_target_bin_self_contained_dir failed");
     for src in target_tools {
-        builder.copy_link_to_folder(&src, &target_bin_dir);
+        builder.copy_link_to_folder(&src, &plat_target_bin_self_contained_dir);
     }
 
     // Warn windows-gnu users that the bundled GCC cannot compile C files
     builder.create(
-        &target_bin_dir.join("GCC-WARNING.txt"),
+        &plat_target_bin_self_contained_dir.join("GCC-WARNING.txt"),
         "gcc.exe contained in this folder cannot be used for compiling C files - it is only \
          used as a linker. In order to be able to compile projects containing C code use \
          the GCC provided by MinGW or Cygwin.",
     );
 
     //Copy platform libs to platform-specific lib directory
-    let target_lib_dir =
-        plat_root.join("lib").join("rustlib").join(target).join("lib").join("self-contained");
-    fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
+    let plat_target_lib_self_contained_dir =
+        plat_root.join("lib/rustlib").join(target).join("lib/self-contained");
+    fs::create_dir_all(&plat_target_lib_self_contained_dir)
+        .expect("creating plat_target_lib_self_contained_dir failed");
     for src in target_libs {
-        builder.copy_link_to_folder(&src, &target_lib_dir);
+        builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir);
     }
 }
 
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index c5a1ab78801..e1eea31b3bb 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -110,7 +110,7 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
 
     // Initialize the llvm submodule if not initialized already.
     // If submodules are disabled, this does nothing.
-    builder.update_submodule("src/llvm-project");
+    builder.config.update_submodule("src/llvm-project");
 
     let root = "src/llvm-project/llvm";
     let out_dir = builder.llvm_out(target);
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index bdd9fd755aa..ce23b7735f8 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -14,7 +14,7 @@ use std::sync::OnceLock;
 use std::{cmp, env, fs};
 
 use build_helper::exit;
-use build_helper::git::GitConfig;
+use build_helper::git::{output_result, GitConfig};
 use serde::{Deserialize, Deserializer};
 use serde_derive::Deserialize;
 
@@ -2509,6 +2509,123 @@ impl Config {
         }
     }
 
+    /// Given a path to the directory of a submodule, update it.
+    ///
+    /// `relative_path` should be relative to the root of the git repository, not an absolute path.
+    ///
+    /// This *does not* update the submodule if `config.toml` explicitly says
+    /// not to, or if we're not in a git repository (like a plain source
+    /// tarball). Typically [`crate::Build::require_submodule`] should be
+    /// used instead to provide a nice error to the user if the submodule is
+    /// missing.
+    pub(crate) fn update_submodule(&self, relative_path: &str) {
+        if !self.submodules() {
+            return;
+        }
+
+        let absolute_path = self.src.join(relative_path);
+
+        // NOTE: The check for the empty directory is here because when running x.py the first time,
+        // the submodule won't be checked out. Check it out now so we can build it.
+        if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
+            && !helpers::dir_is_empty(&absolute_path)
+        {
+            return;
+        }
+
+        // Submodule updating actually happens during in the dry run mode. We need to make sure that
+        // all the git commands below are actually executed, because some follow-up code
+        // in bootstrap might depend on the submodules being checked out. Furthermore, not all
+        // the command executions below work with an empty output (produced during dry run).
+        // Therefore, all commands below are marked with `run_always()`, so that they also run in
+        // dry run mode.
+        let submodule_git = || {
+            let mut cmd = helpers::git(Some(&absolute_path));
+            cmd.run_always();
+            cmd
+        };
+
+        // Determine commit checked out in submodule.
+        let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]).as_command_mut());
+        let checked_out_hash = checked_out_hash.trim_end();
+        // Determine commit that the submodule *should* have.
+        let recorded = output(
+            helpers::git(Some(&self.src))
+                .run_always()
+                .args(["ls-tree", "HEAD"])
+                .arg(relative_path)
+                .as_command_mut(),
+        );
+
+        let actual_hash = recorded
+            .split_whitespace()
+            .nth(2)
+            .unwrap_or_else(|| panic!("unexpected output `{}`", recorded));
+
+        if actual_hash == checked_out_hash {
+            // already checked out
+            return;
+        }
+
+        println!("Updating submodule {relative_path}");
+        self.check_run(
+            helpers::git(Some(&self.src))
+                .run_always()
+                .args(["submodule", "-q", "sync"])
+                .arg(relative_path),
+        );
+
+        // Try passing `--progress` to start, then run git again without if that fails.
+        let update = |progress: bool| {
+            // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
+            // even though that has no relation to the upstream for the submodule.
+            let current_branch = output_result(
+                helpers::git(Some(&self.src))
+                    .allow_failure()
+                    .run_always()
+                    .args(["symbolic-ref", "--short", "HEAD"])
+                    .as_command_mut(),
+            )
+            .map(|b| b.trim().to_owned());
+
+            let mut git = helpers::git(Some(&self.src)).allow_failure();
+            git.run_always();
+            if let Ok(branch) = current_branch {
+                // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
+                // This syntax isn't accepted by `branch.{branch}`. Strip it.
+                let branch = branch.strip_prefix("heads/").unwrap_or(&branch);
+                git.arg("-c").arg(format!("branch.{branch}.remote=origin"));
+            }
+            git.args(["submodule", "update", "--init", "--recursive", "--depth=1"]);
+            if progress {
+                git.arg("--progress");
+            }
+            git.arg(relative_path);
+            git
+        };
+        if !self.check_run(&mut update(true)) {
+            self.check_run(&mut update(false));
+        }
+
+        // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
+        // diff-index reports the modifications through the exit status
+        let has_local_modifications = !self.check_run(submodule_git().allow_failure().args([
+            "diff-index",
+            "--quiet",
+            "HEAD",
+        ]));
+        if has_local_modifications {
+            self.check_run(submodule_git().args(["stash", "push"]));
+        }
+
+        self.check_run(submodule_git().args(["reset", "-q", "--hard"]));
+        self.check_run(submodule_git().args(["clean", "-qdfx"]));
+
+        if has_local_modifications {
+            self.check_run(submodule_git().args(["stash", "pop"]));
+        }
+    }
+
     #[cfg(feature = "bootstrap-self-test")]
     pub fn check_stage0_version(&self, _program_path: &Path, _component_name: &'static str) {}
 
@@ -2613,19 +2730,23 @@ impl Config {
         asserts: bool,
     ) -> bool {
         let if_unchanged = || {
-            // Git is needed to track modifications here, but tarball source is not available.
-            // If not modified here or built through tarball source, we maintain consistency
-            // with '"if available"'.
-            if !self.rust_info.is_from_tarball()
-                && self
-                    .last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true)
-                    .is_none()
-            {
-                // there are some untracked changes in the given paths.
-                false
-            } else {
-                llvm::is_ci_llvm_available(self, asserts)
+            if self.rust_info.is_from_tarball() {
+                // Git is needed for running "if-unchanged" logic.
+                println!(
+                    "WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`."
+                );
+                return false;
             }
+
+            self.update_submodule("src/llvm-project");
+
+            // Check for untracked changes in `src/llvm-project`.
+            let has_changes = self
+                .last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true)
+                .is_none();
+
+            // Return false if there are untracked changes, otherwise check if CI LLVM is available.
+            if has_changes { false } else { llvm::is_ci_llvm_available(self, asserts) }
         };
 
         match download_ci_llvm {
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index dd0309733ae..c225cc30146 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -56,7 +56,7 @@ impl Config {
     /// Returns false if do not execute at all, otherwise returns its
     /// `status.success()`.
     pub(crate) fn check_run(&self, cmd: &mut BootstrapCommand) -> bool {
-        if self.dry_run() {
+        if self.dry_run() && !cmd.run_always {
             return true;
         }
         self.verbose(|| println!("running: {cmd:?}"));
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 784519a20a2..268392c5fb1 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -473,117 +473,6 @@ impl Build {
         build
     }
 
-    /// Given a path to the directory of a submodule, update it.
-    ///
-    /// `relative_path` should be relative to the root of the git repository, not an absolute path.
-    ///
-    /// This *does not* update the submodule if `config.toml` explicitly says
-    /// not to, or if we're not in a git repository (like a plain source
-    /// tarball). Typically [`Build::require_submodule`] should be
-    /// used instead to provide a nice error to the user if the submodule is
-    /// missing.
-    fn update_submodule(&self, relative_path: &str) {
-        if !self.config.submodules() {
-            return;
-        }
-
-        let absolute_path = self.config.src.join(relative_path);
-
-        // NOTE: The check for the empty directory is here because when running x.py the first time,
-        // the submodule won't be checked out. Check it out now so we can build it.
-        if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
-            && !dir_is_empty(&absolute_path)
-        {
-            return;
-        }
-
-        // Submodule updating actually happens during in the dry run mode. We need to make sure that
-        // all the git commands below are actually executed, because some follow-up code
-        // in bootstrap might depend on the submodules being checked out. Furthermore, not all
-        // the command executions below work with an empty output (produced during dry run).
-        // Therefore, all commands below are marked with `run_always()`, so that they also run in
-        // dry run mode.
-        let submodule_git = || {
-            let mut cmd = helpers::git(Some(&absolute_path));
-            cmd.run_always();
-            cmd
-        };
-
-        // Determine commit checked out in submodule.
-        let checked_out_hash =
-            submodule_git().args(["rev-parse", "HEAD"]).run_capture_stdout(self).stdout();
-        let checked_out_hash = checked_out_hash.trim_end();
-        // Determine commit that the submodule *should* have.
-        let recorded = helpers::git(Some(&self.src))
-            .run_always()
-            .args(["ls-tree", "HEAD"])
-            .arg(relative_path)
-            .run_capture_stdout(self)
-            .stdout();
-        let actual_hash = recorded
-            .split_whitespace()
-            .nth(2)
-            .unwrap_or_else(|| panic!("unexpected output `{}`", recorded));
-
-        if actual_hash == checked_out_hash {
-            // already checked out
-            return;
-        }
-
-        println!("Updating submodule {relative_path}");
-        helpers::git(Some(&self.src))
-            .run_always()
-            .args(["submodule", "-q", "sync"])
-            .arg(relative_path)
-            .run(self);
-
-        // Try passing `--progress` to start, then run git again without if that fails.
-        let update = |progress: bool| {
-            // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
-            // even though that has no relation to the upstream for the submodule.
-            let current_branch = helpers::git(Some(&self.src))
-                .allow_failure()
-                .run_always()
-                .args(["symbolic-ref", "--short", "HEAD"])
-                .run_capture_stdout(self)
-                .stdout_if_ok()
-                .map(|s| s.trim().to_owned());
-
-            let mut git = helpers::git(Some(&self.src)).allow_failure();
-            git.run_always();
-            if let Some(branch) = current_branch {
-                // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
-                // This syntax isn't accepted by `branch.{branch}`. Strip it.
-                let branch = branch.strip_prefix("heads/").unwrap_or(&branch);
-                git.arg("-c").arg(format!("branch.{branch}.remote=origin"));
-            }
-            git.args(["submodule", "update", "--init", "--recursive", "--depth=1"]);
-            if progress {
-                git.arg("--progress");
-            }
-            git.arg(relative_path);
-            git
-        };
-        if !update(true).run(self) {
-            update(false).run(self);
-        }
-
-        // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
-        // diff-index reports the modifications through the exit status
-        let has_local_modifications =
-            !submodule_git().allow_failure().args(["diff-index", "--quiet", "HEAD"]).run(self);
-        if has_local_modifications {
-            submodule_git().args(["stash", "push"]).run(self);
-        }
-
-        submodule_git().args(["reset", "-q", "--hard"]).run(self);
-        submodule_git().args(["clean", "-qdfx"]).run(self);
-
-        if has_local_modifications {
-            submodule_git().args(["stash", "pop"]).run(self);
-        }
-    }
-
     /// Updates a submodule, and exits with a failure if submodule management
     /// is disabled and the submodule does not exist.
     ///
@@ -598,7 +487,7 @@ impl Build {
         if cfg!(test) && !self.config.submodules() {
             return;
         }
-        self.update_submodule(submodule);
+        self.config.update_submodule(submodule);
         let absolute_path = self.config.src.join(submodule);
         if dir_is_empty(&absolute_path) {
             let maybe_enable = if !self.config.submodules()
@@ -646,7 +535,7 @@ impl Build {
             let path = Path::new(submodule);
             // Don't update the submodule unless it's already been cloned.
             if GitInfo::new(false, path).is_managed_git_subrepository() {
-                self.update_submodule(submodule);
+                self.config.update_submodule(submodule);
             }
         }
     }
@@ -659,7 +548,7 @@ impl Build {
         }
 
         if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() {
-            self.update_submodule(submodule);
+            self.config.update_submodule(submodule);
         }
     }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index db81b4c4282..5260e363dd6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -272,7 +272,7 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) ->
         | rbv::ResolvedArg::LateBound(_, _, did)
         | rbv::ResolvedArg::Free(_, did),
     ) = cx.tcx.named_bound_var(lifetime.hir_id)
-        && let Some(lt) = cx.args.get(&did).and_then(|arg| arg.as_lt())
+        && let Some(lt) = cx.args.get(&did.to_def_id()).and_then(|arg| arg.as_lt())
     {
         return lt.clone();
     }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index eb5a5d935e2..28df8d3f011 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1547,10 +1547,23 @@ instead, we check that it's not a "finger" cursor.
 	margin-left: 24px;
 }
 
+@keyframes targetfadein {
+	from {
+		background-color: var(--main-background-color);
+	}
+	10% {
+		background-color: var(--target-border-color);
+	}
+	to {
+		background-color: var(--target-background-color);
+	}
+}
+
 :target {
 	padding-right: 3px;
 	background-color: var(--target-background-color);
 	border-right: 3px solid var(--target-border-color);
+	animation: 0.65s cubic-bezier(0, 0, 0.1, 1.0) 0.1s targetfadein;
 }
 
 .code-header a.tooltip {
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject ba8b39413c74d08494f94a7542fe79aa636e166
+Subproject 8f40fc59fb0c8df91c97405785197f3c630304e
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index e12f3f9012f..4b7f3483ff7 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -20,7 +20,7 @@ doctest = false # and no doc tests
 [dependencies]
 getrandom = { version = "0.2", features = ["std"] }
 rand = "0.8"
-smallvec = "1.7"
+smallvec = { version = "1.7", features = ["drain_filter"] }
 aes = { version = "0.8.3", features = ["hazmat"] }
 measureme = "11"
 ctrlc = "3.2.5"
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index c3f4f4b5d82..1eca86baeaa 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-f24a6ba06f4190d8ec4f22d1baa800e64b1900cb
+fdf61d499c8a8421ecf98e7924bb87caf43a9938
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
index 90bd1103218..56643c6cbe8 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -10,7 +10,7 @@
 //!   and the relative position of the access;
 //! - idempotency properties asserted in `perms.rs` (for optimizations)
 
-use std::fmt;
+use std::{fmt, mem};
 
 use smallvec::SmallVec;
 
@@ -699,8 +699,7 @@ impl<'tcx> Tree {
 /// Integration with the BorTag garbage collector
 impl Tree {
     pub fn remove_unreachable_tags(&mut self, live_tags: &FxHashSet<BorTag>) {
-        let root_is_needed = self.keep_only_needed(self.root, live_tags); // root can't be removed
-        assert!(root_is_needed);
+        self.remove_useless_children(self.root, live_tags);
         // Right after the GC runs is a good moment to check if we can
         // merge some adjacent ranges that were made equal by the removal of some
         // tags (this does not necessarily mean that they have identical internal representations,
@@ -708,9 +707,16 @@ impl Tree {
         self.rperms.merge_adjacent_thorough();
     }
 
+    /// Checks if a node is useless and should be GC'ed.
+    /// A node is useless if it has no children and also the tag is no longer live.
+    fn is_useless(&self, idx: UniIndex, live: &FxHashSet<BorTag>) -> bool {
+        let node = self.nodes.get(idx).unwrap();
+        node.children.is_empty() && !live.contains(&node.tag)
+    }
+
     /// Traverses the entire tree looking for useless tags.
-    /// Returns true iff the tag it was called on is still live or has live children,
-    /// and removes from the tree all tags that have no live children.
+    /// Removes from the tree all useless child nodes of root.
+    /// It will not delete the root itself.
     ///
     /// NOTE: This leaves in the middle of the tree tags that are unreachable but have
     /// reachable children. There is a potential for compacting the tree by reassigning
@@ -721,42 +727,60 @@ impl Tree {
     /// `child: Reserved`. This tree can exist. If we blindly delete `parent` and reassign
     /// `child` to be a direct child of `root` then Writes to `child` are now permitted
     /// whereas they were not when `parent` was still there.
-    fn keep_only_needed(&mut self, idx: UniIndex, live: &FxHashSet<BorTag>) -> bool {
-        let node = self.nodes.get(idx).unwrap();
-        // FIXME: this function does a lot of cloning, a 2-pass approach is possibly
-        // more efficient. It could consist of
-        // 1. traverse the Tree, collect all useless tags in a Vec
-        // 2. traverse the Vec, remove all tags previously selected
-        // Bench it.
-        let children: SmallVec<_> = node
-            .children
-            .clone()
-            .into_iter()
-            .filter(|child| self.keep_only_needed(*child, live))
-            .collect();
-        let no_children = children.is_empty();
-        let node = self.nodes.get_mut(idx).unwrap();
-        node.children = children;
-        if !live.contains(&node.tag) && no_children {
-            // All of the children and this node are unreachable, delete this tag
-            // from the tree (the children have already been deleted by recursive
-            // calls).
-            // Due to the API of UniMap we must absolutely call
-            // `UniValMap::remove` for the key of this tag on *all* maps that used it
-            // (which are `self.nodes` and every range of `self.rperms`)
-            // before we can safely apply `UniValMap::forget` to truly remove
-            // the tag from the mapping.
-            let tag = node.tag;
-            self.nodes.remove(idx);
-            for (_perms_range, perms) in self.rperms.iter_mut_all() {
-                perms.remove(idx);
+    fn remove_useless_children(&mut self, root: UniIndex, live: &FxHashSet<BorTag>) {
+        // To avoid stack overflows, we roll our own stack.
+        // Each element in the stack consists of the current tag, and the number of the
+        // next child to be processed.
+
+        // The other functions are written using the `TreeVisitorStack`, but that does not work here
+        // since we need to 1) do a post-traversal and 2) remove nodes from the tree.
+        // Since we do a post-traversal (by deleting nodes only after handling all children),
+        // we also need to be a bit smarter than "pop node, push all children."
+        let mut stack = vec![(root, 0)];
+        while let Some((tag, nth_child)) = stack.last_mut() {
+            let node = self.nodes.get(*tag).unwrap();
+            if *nth_child < node.children.len() {
+                // Visit the child by pushing it to the stack.
+                // Also increase `nth_child` so that when we come back to the `tag` node, we
+                // look at the next child.
+                let next_child = node.children[*nth_child];
+                *nth_child += 1;
+                stack.push((next_child, 0));
+                continue;
+            } else {
+                // We have processed all children of `node`, so now it is time to process `node` itself.
+                // First, get the current children of `node`. To appease the borrow checker,
+                // we have to temporarily move the list out of the node, and then put the
+                // list of remaining children back in.
+                let mut children_of_node =
+                    mem::take(&mut self.nodes.get_mut(*tag).unwrap().children);
+                // Remove all useless children, and save them for later.
+                // The closure needs `&self` and the loop below needs `&mut self`, so we need to `collect`
+                // in to a temporary list.
+                let to_remove: Vec<_> =
+                    children_of_node.drain_filter(|x| self.is_useless(*x, live)).collect();
+                // Put back the now-filtered vector.
+                self.nodes.get_mut(*tag).unwrap().children = children_of_node;
+                // Now, all that is left is unregistering the children saved in `to_remove`.
+                for idx in to_remove {
+                    // Note: In the rest of this comment, "this node" refers to `idx`.
+                    // This node has no more children (if there were any, they have already been removed).
+                    // It is also unreachable as determined by the GC, so we can remove it everywhere.
+                    // Due to the API of UniMap we must make sure to call
+                    // `UniValMap::remove` for the key of this node on *all* maps that used it
+                    // (which are `self.nodes` and every range of `self.rperms`)
+                    // before we can safely apply `UniKeyMap::remove` to truly remove
+                    // this tag from the `tag_mapping`.
+                    let node = self.nodes.remove(idx).unwrap();
+                    for (_perms_range, perms) in self.rperms.iter_mut_all() {
+                        perms.remove(idx);
+                    }
+                    self.tag_mapping.remove(&node.tag);
+                }
+                // We are done, the parent can continue.
+                stack.pop();
+                continue;
             }
-            self.tag_mapping.remove(&tag);
-            // The tag has been deleted, inform the caller
-            false
-        } else {
-            // The tag is still live or has live children, it must be kept
-            true
         }
     }
 }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
index f45b2d9e00a..92bae6203b3 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
@@ -12,7 +12,7 @@
 
 #![allow(dead_code)]
 
-use std::hash::Hash;
+use std::{hash::Hash, mem};
 
 use rustc_data_structures::fx::FxHashMap;
 
@@ -187,13 +187,16 @@ impl<V> UniValMap<V> {
         self.data.get_mut(idx.idx as usize).and_then(Option::as_mut)
     }
 
-    /// Delete any value associated with this index. Ok even if the index
-    /// has no associated value.
-    pub fn remove(&mut self, idx: UniIndex) {
+    /// Delete any value associated with this index.
+    /// Returns None if the value was not present, otherwise
+    /// returns the previously stored value.
+    pub fn remove(&mut self, idx: UniIndex) -> Option<V> {
         if idx.idx as usize >= self.data.len() {
-            return;
+            return None;
         }
-        self.data[idx.idx as usize] = None;
+        let mut res = None;
+        mem::swap(&mut res, &mut self.data[idx.idx as usize]);
+        res
     }
 }
 
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 80f4b89bf34..e00758bb98d 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -1204,14 +1204,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         )?;
                     }
                     "freebsd" => {
-                        this.write_int(ino, &this.project_field_named(&entry_place, "d_fileno")?)?;
-                        // `d_off` only exists on FreeBSD 12+, but we support v11 as well.
-                        // `libc` uses a build script to determine which version of the API to use,
-                        // and cross-builds always end up using v11.
-                        // To support both v11 and v12+, we dynamically check whether the field exists.
-                        if this.projectable_has_field(&entry_place, "d_off") {
-                            this.write_int(0, &this.project_field_named(&entry_place, "d_off")?)?;
-                        }
+                        #[rustfmt::skip]
+                        this.write_int_fields_named(
+                            &[
+                                ("d_fileno", ino.into()),
+                                ("d_off", 0),
+                            ],
+                            &entry_place,
+                        )?;
                     }
                     _ => unreachable!(),
                 }
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index c1117e4d811..305e59fa0cd 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -15,6 +15,7 @@ mod aesni;
 mod avx;
 mod avx2;
 mod bmi;
+mod sha;
 mod sse;
 mod sse2;
 mod sse3;
@@ -105,6 +106,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this, link_name, abi, args, dest,
                 );
             }
+            name if name.starts_with("sha") => {
+                return sha::EvalContextExt::emulate_x86_sha_intrinsic(
+                    this, link_name, abi, args, dest,
+                );
+            }
             name if name.starts_with("sse.") => {
                 return sse::EvalContextExt::emulate_x86_sse_intrinsic(
                     this, link_name, abi, args, dest,
diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs
new file mode 100644
index 00000000000..e9cc28be34c
--- /dev/null
+++ b/src/tools/miri/src/shims/x86/sha.rs
@@ -0,0 +1,221 @@
+//! Implements sha256 SIMD instructions of x86 targets
+//!
+//! The functions that actually compute SHA256 were copied from [RustCrypto's sha256 module].
+//!
+//! [RustCrypto's sha256 module]: https://github.com/RustCrypto/hashes/blob/6be8466247e936c415d8aafb848697f39894a386/sha2/src/sha256/soft.rs
+
+use rustc_span::Symbol;
+use rustc_target::spec::abi::Abi;
+
+use crate::*;
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    fn emulate_x86_sha_intrinsic(
+        &mut self,
+        link_name: Symbol,
+        abi: Abi,
+        args: &[OpTy<'tcx>],
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx, EmulateItemResult> {
+        let this = self.eval_context_mut();
+        this.expect_target_feature_for_intrinsic(link_name, "sha")?;
+        // Prefix should have already been checked.
+        let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sha").unwrap();
+
+        fn read<'c>(this: &mut MiriInterpCx<'c>, reg: &MPlaceTy<'c>) -> InterpResult<'c, [u32; 4]> {
+            let mut res = [0; 4];
+            // We reverse the order because x86 is little endian but the copied implementation uses
+            // big endian.
+            for (i, dst) in res.iter_mut().rev().enumerate() {
+                let projected = &this.project_index(reg, i.try_into().unwrap())?;
+                *dst = this.read_scalar(projected)?.to_u32()?
+            }
+            Ok(res)
+        }
+
+        fn write<'c>(
+            this: &mut MiriInterpCx<'c>,
+            dest: &MPlaceTy<'c>,
+            val: [u32; 4],
+        ) -> InterpResult<'c, ()> {
+            // We reverse the order because x86 is little endian but the copied implementation uses
+            // big endian.
+            for (i, part) in val.into_iter().rev().enumerate() {
+                let projected = &this.project_index(dest, i.try_into().unwrap())?;
+                this.write_scalar(Scalar::from_u32(part), projected)?;
+            }
+            Ok(())
+        }
+
+        match unprefixed_name {
+            // Used to implement the _mm_sha256rnds2_epu32 function.
+            "256rnds2" => {
+                let [a, b, k] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (a_reg, a_len) = this.operand_to_simd(a)?;
+                let (b_reg, b_len) = this.operand_to_simd(b)?;
+                let (k_reg, k_len) = this.operand_to_simd(k)?;
+                let (dest, dest_len) = this.mplace_to_simd(dest)?;
+
+                assert_eq!(a_len, 4);
+                assert_eq!(b_len, 4);
+                assert_eq!(k_len, 4);
+                assert_eq!(dest_len, 4);
+
+                let a = read(this, &a_reg)?;
+                let b = read(this, &b_reg)?;
+                let k = read(this, &k_reg)?;
+
+                let result = sha256_digest_round_x2(a, b, k);
+                write(this, &dest, result)?;
+            }
+            // Used to implement the _mm_sha256msg1_epu32 function.
+            "256msg1" => {
+                let [a, b] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (a_reg, a_len) = this.operand_to_simd(a)?;
+                let (b_reg, b_len) = this.operand_to_simd(b)?;
+                let (dest, dest_len) = this.mplace_to_simd(dest)?;
+
+                assert_eq!(a_len, 4);
+                assert_eq!(b_len, 4);
+                assert_eq!(dest_len, 4);
+
+                let a = read(this, &a_reg)?;
+                let b = read(this, &b_reg)?;
+
+                let result = sha256msg1(a, b);
+                write(this, &dest, result)?;
+            }
+            // Used to implement the _mm_sha256msg2_epu32 function.
+            "256msg2" => {
+                let [a, b] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (a_reg, a_len) = this.operand_to_simd(a)?;
+                let (b_reg, b_len) = this.operand_to_simd(b)?;
+                let (dest, dest_len) = this.mplace_to_simd(dest)?;
+
+                assert_eq!(a_len, 4);
+                assert_eq!(b_len, 4);
+                assert_eq!(dest_len, 4);
+
+                let a = read(this, &a_reg)?;
+                let b = read(this, &b_reg)?;
+
+                let result = sha256msg2(a, b);
+                write(this, &dest, result)?;
+            }
+            _ => return Ok(EmulateItemResult::NotSupported),
+        }
+        Ok(EmulateItemResult::NeedsReturn)
+    }
+}
+
+#[inline(always)]
+fn shr(v: [u32; 4], o: u32) -> [u32; 4] {
+    [v[0] >> o, v[1] >> o, v[2] >> o, v[3] >> o]
+}
+
+#[inline(always)]
+fn shl(v: [u32; 4], o: u32) -> [u32; 4] {
+    [v[0] << o, v[1] << o, v[2] << o, v[3] << o]
+}
+
+#[inline(always)]
+fn or(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
+    [a[0] | b[0], a[1] | b[1], a[2] | b[2], a[3] | b[3]]
+}
+
+#[inline(always)]
+fn xor(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
+    [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]]
+}
+
+#[inline(always)]
+fn add(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
+    [
+        a[0].wrapping_add(b[0]),
+        a[1].wrapping_add(b[1]),
+        a[2].wrapping_add(b[2]),
+        a[3].wrapping_add(b[3]),
+    ]
+}
+
+fn sha256load(v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
+    [v3[3], v2[0], v2[1], v2[2]]
+}
+
+fn sha256_digest_round_x2(cdgh: [u32; 4], abef: [u32; 4], wk: [u32; 4]) -> [u32; 4] {
+    macro_rules! big_sigma0 {
+        ($a:expr) => {
+            ($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22))
+        };
+    }
+    macro_rules! big_sigma1 {
+        ($a:expr) => {
+            ($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25))
+        };
+    }
+    macro_rules! bool3ary_202 {
+        ($a:expr, $b:expr, $c:expr) => {
+            $c ^ ($a & ($b ^ $c))
+        };
+    } // Choose, MD5F, SHA1C
+    macro_rules! bool3ary_232 {
+        ($a:expr, $b:expr, $c:expr) => {
+            ($a & $b) ^ ($a & $c) ^ ($b & $c)
+        };
+    } // Majority, SHA1M
+
+    let [_, _, wk1, wk0] = wk;
+    let [a0, b0, e0, f0] = abef;
+    let [c0, d0, g0, h0] = cdgh;
+
+    // a round
+    let x0 =
+        big_sigma1!(e0).wrapping_add(bool3ary_202!(e0, f0, g0)).wrapping_add(wk0).wrapping_add(h0);
+    let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
+    let (a1, b1, c1, d1, e1, f1, g1, h1) =
+        (x0.wrapping_add(y0), a0, b0, c0, x0.wrapping_add(d0), e0, f0, g0);
+
+    // a round
+    let x1 =
+        big_sigma1!(e1).wrapping_add(bool3ary_202!(e1, f1, g1)).wrapping_add(wk1).wrapping_add(h1);
+    let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1));
+    let (a2, b2, _, _, e2, f2, _, _) =
+        (x1.wrapping_add(y1), a1, b1, c1, x1.wrapping_add(d1), e1, f1, g1);
+
+    [a2, b2, e2, f2]
+}
+
+fn sha256msg1(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] {
+    // sigma 0 on vectors
+    #[inline]
+    fn sigma0x4(x: [u32; 4]) -> [u32; 4] {
+        let t1 = or(shr(x, 7), shl(x, 25));
+        let t2 = or(shr(x, 18), shl(x, 14));
+        let t3 = shr(x, 3);
+        xor(xor(t1, t2), t3)
+    }
+
+    add(v0, sigma0x4(sha256load(v0, v1)))
+}
+
+fn sha256msg2(v4: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
+    macro_rules! sigma1 {
+        ($a:expr) => {
+            $a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10)
+        };
+    }
+
+    let [x3, x2, x1, x0] = v4;
+    let [w15, w14, _, _] = v3;
+
+    let w16 = x0.wrapping_add(sigma1!(w14));
+    let w17 = x1.wrapping_add(sigma1!(w15));
+    let w18 = x2.wrapping_add(sigma1!(w16));
+    let w19 = x3.wrapping_add(sigma1!(w17));
+
+    [w19, w18, w17, w16]
+}
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index e94bef52952..bbead878223 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -119,9 +119,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.155"
+version = "0.2.158"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
 
 [[package]]
 name = "linux-raw-sys"
diff --git a/src/tools/miri/tests/fail/alloc/global_system_mixup.rs b/src/tools/miri/tests/fail/alloc/global_system_mixup.rs
index 19c62913b4c..804aa13660b 100644
--- a/src/tools/miri/tests/fail/alloc/global_system_mixup.rs
+++ b/src/tools/miri/tests/fail/alloc/global_system_mixup.rs
@@ -13,7 +13,5 @@ use std::alloc::{Allocator, Global, Layout, System};
 fn main() {
     let l = Layout::from_size_align(1, 1).unwrap();
     let ptr = Global.allocate(l).unwrap().as_non_null_ptr();
-    unsafe {
-        System.deallocate(ptr, l);
-    }
+    unsafe { System.deallocate(ptr, l) };
 }
diff --git a/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr b/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr
index 7006b96ee1e..77909564149 100644
--- a/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr
+++ b/src/tools/miri/tests/fail/alloc/global_system_mixup.stderr
@@ -12,7 +12,7 @@ LL |         FREE();
 note: inside `main`
   --> $DIR/global_system_mixup.rs:LL:CC
    |
-LL |         System.deallocate(ptr, l);
+LL |     unsafe { System.deallocate(ptr, l) };
    | ^
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs
new file mode 100644
index 00000000000..aed5cb11258
--- /dev/null
+++ b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.rs
@@ -0,0 +1,19 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+//@[tree]error-in-other-file: /deallocation .* is forbidden/
+use std::alloc::{alloc, dealloc, Layout};
+
+// `x` is strongly protected but covers zero bytes.
+// Let's see if deallocating the allocation x points to is UB:
+// in TB, it is UB, but in SB it is not.
+fn test(_x: &mut (), ptr: *mut u8, l: Layout) {
+    unsafe { dealloc(ptr, l) };
+}
+
+fn main() {
+    let l = Layout::from_size_align(1, 1).unwrap();
+    let ptr = unsafe { alloc(l) };
+    unsafe { test(&mut *ptr.cast::<()>(), ptr, l) };
+    // In SB the test would pass if it weren't for this line.
+    unsafe { std::hint::unreachable_unchecked() }; //~[stack] ERROR: unreachable
+}
diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr
new file mode 100644
index 00000000000..672682ff294
--- /dev/null
+++ b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.stack.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: entering unreachable code
+  --> $DIR/zero-sized-protected.rs:LL:CC
+   |
+LL |     unsafe { std::hint::unreachable_unchecked() };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/zero-sized-protected.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr
new file mode 100644
index 00000000000..ef981038e55
--- /dev/null
+++ b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr
@@ -0,0 +1,36 @@
+error: Undefined Behavior: deallocation through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden
+  --> RUSTLIB/alloc/src/alloc.rs:LL:CC
+   |
+LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocation through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = help: the allocation of the accessed tag <TAG> (root of the allocation) also contains the strongly protected tag <TAG>
+   = help: the strongly protected tag <TAG> disallows deallocations
+help: the accessed tag <TAG> was created here
+  --> $DIR/zero-sized-protected.rs:LL:CC
+   |
+LL |     let ptr = unsafe { alloc(l) };
+   |                        ^^^^^^^^
+help: the strongly protected tag <TAG> was created here, in the initial state Reserved
+  --> $DIR/zero-sized-protected.rs:LL:CC
+   |
+LL | fn test(_x: &mut (), ptr: *mut u8, l: Layout) {
+   |         ^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
+note: inside `test`
+  --> $DIR/zero-sized-protected.rs:LL:CC
+   |
+LL |     unsafe { dealloc(ptr, l) };
+   |              ^^^^^^^^^^^^^^^
+note: inside `main`
+  --> $DIR/zero-sized-protected.rs:LL:CC
+   |
+LL |     unsafe { test(&mut *ptr.cast::<()>(), ptr, l) };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll.rs
index e28cafd3c28..052ce73de23 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll.rs
@@ -1,8 +1,7 @@
 //@only-target-linux
 
-#![feature(exposed_provenance)] // Needed for fn test_pointer()
+#![feature(strict_provenance)]
 use std::convert::TryInto;
-use std::mem::MaybeUninit;
 
 fn main() {
     test_epoll_socketpair();
@@ -17,7 +16,6 @@ fn main() {
     test_no_notification_for_unregister_flag();
     test_epoll_ctl_mod();
     test_epoll_ctl_del();
-    test_pointer();
     test_two_same_fd_in_same_epoll_instance();
     test_epoll_wait_maxevent_zero();
     test_socketpair_epollerr();
@@ -261,24 +259,6 @@ fn test_epoll_eventfd() {
     check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)]);
 }
 
-fn test_pointer() {
-    // Create an epoll instance.
-    let epfd = unsafe { libc::epoll_create1(0) };
-    assert_ne!(epfd, -1);
-
-    // Create a socketpair instance.
-    let mut fds = [-1, -1];
-    let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
-    assert_eq!(res, 0);
-
-    // Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET
-    let data = MaybeUninit::<u64>::uninit().as_ptr();
-    let mut ev =
-        libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: data.expose_provenance() as u64 };
-    let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
-    assert_eq!(res, 0);
-}
-
 // When read/write happened on one side of the socketpair, only the other side will be notified.
 fn test_epoll_socketpair_both_sides() {
     // Create an epoll instance.
@@ -543,9 +523,9 @@ fn test_epoll_wait_maxevent_zero() {
     // Create an epoll instance.
     let epfd = unsafe { libc::epoll_create1(0) };
     assert_ne!(epfd, -1);
-    // It is ok to use uninitialised pointer here because it will error out before the
-    // pointer actually get accessed.
-    let array_ptr = MaybeUninit::<libc::epoll_event>::uninit().as_mut_ptr();
+    // It is ok to use a dangling pointer here because it will error out before the
+    // pointer actually gets accessed.
+    let array_ptr = std::ptr::without_provenance_mut::<libc::epoll_event>(0x100);
     let res = unsafe { libc::epoll_wait(epfd, array_ptr, 0, 0) };
     let e = std::io::Error::last_os_error();
     assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs
new file mode 100644
index 00000000000..e65fdc3fbed
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs
@@ -0,0 +1,270 @@
+// Ignore everything except x86 and x86_64
+// Any new targets that are added to CI should be ignored here.
+// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+//@compile-flags: -C target-feature=+sha,+sse2,+ssse3,+sse4.1
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+
+macro_rules! rounds4 {
+    ($abef:ident, $cdgh:ident, $rest:expr, $i:expr) => {{
+        let k = K32X4[$i];
+        let kv = _mm_set_epi32(k[0] as i32, k[1] as i32, k[2] as i32, k[3] as i32);
+        let t1 = _mm_add_epi32($rest, kv);
+        $cdgh = _mm_sha256rnds2_epu32($cdgh, $abef, t1);
+        let t2 = _mm_shuffle_epi32(t1, 0x0E);
+        $abef = _mm_sha256rnds2_epu32($abef, $cdgh, t2);
+    }};
+}
+
+macro_rules! schedule_rounds4 {
+    (
+        $abef:ident, $cdgh:ident,
+        $w0:expr, $w1:expr, $w2:expr, $w3:expr, $w4:expr,
+        $i: expr
+    ) => {{
+        $w4 = schedule($w0, $w1, $w2, $w3);
+        rounds4!($abef, $cdgh, $w4, $i);
+    }};
+}
+
+fn main() {
+    assert!(is_x86_feature_detected!("sha"));
+    assert!(is_x86_feature_detected!("sse2"));
+    assert!(is_x86_feature_detected!("ssse3"));
+    assert!(is_x86_feature_detected!("sse4.1"));
+
+    unsafe {
+        test_sha256rnds2();
+        test_sha256msg1();
+        test_sha256msg2();
+        test_sha256();
+    }
+}
+
+#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
+unsafe fn test_sha256rnds2() {
+    let test_vectors = [
+        (
+            [0x3c6ef372, 0xa54ff53a, 0x1f83d9ab, 0x5be0cd19],
+            [0x6a09e667, 0xbb67ae85, 0x510e527f, 0x9b05688c],
+            [0x592340c6, 0x17386142, 0x91a0b7b1, 0x94ffa30c],
+            [0xeef39c6c, 0x4e7dfbc1, 0x467a98f3, 0xeb3d5616],
+        ),
+        (
+            [0x6a09e667, 0xbb67ae85, 0x510e527f, 0x9b05688c],
+            [0xeef39c6c, 0x4e7dfbc1, 0x467a98f3, 0xeb3d5616],
+            [0x91a0b7b1, 0x94ffa30c, 0x592340c6, 0x17386142],
+            [0x7e7f3c9d, 0x78db9a20, 0xd82fe6ed, 0xaf1f2704],
+        ),
+        (
+            [0xeef39c6c, 0x4e7dfbc1, 0x467a98f3, 0xeb3d5616],
+            [0x7e7f3c9d, 0x78db9a20, 0xd82fe6ed, 0xaf1f2704],
+            [0x1a89c3f6, 0xf3b6e817, 0x7a5a8511, 0x8bcc35cf],
+            [0xc9292f7e, 0x49137bd9, 0x7e5f9e08, 0xd10f9247],
+        ),
+    ];
+    for (cdgh, abef, wk, expected) in test_vectors {
+        let output_reg = _mm_sha256rnds2_epu32(set_arr(cdgh), set_arr(abef), set_arr(wk));
+        let mut output = [0u32; 4];
+        _mm_storeu_si128(output.as_mut_ptr().cast(), output_reg);
+        // The values are stored as little endian, so we need to reverse them
+        output.reverse();
+        assert_eq!(output, expected);
+    }
+}
+
+#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
+unsafe fn test_sha256msg1() {
+    let test_vectors = [
+        (
+            [0x6f6d6521, 0x61776573, 0x20697320, 0x52757374],
+            [0x6f6d6521, 0x61776573, 0x20697320, 0x52757374],
+            [0x2da4b536, 0x77f29328, 0x541a4d59, 0x6afb680c],
+        ),
+        (
+            [0x6f6d6521, 0x61776573, 0x20697320, 0x52757374],
+            [0x6f6d6521, 0x61776573, 0x20697320, 0x52757374],
+            [0x2da4b536, 0x77f29328, 0x541a4d59, 0x6afb680c],
+        ),
+        (
+            [0x6f6d6521, 0x61776573, 0x20697320, 0x52757374],
+            [0x6f6d6521, 0x61776573, 0x20697320, 0x52757374],
+            [0x2da4b536, 0x77f29328, 0x541a4d59, 0x6afb680c],
+        ),
+    ];
+    for (v0, v1, expected) in test_vectors {
+        let output_reg = _mm_sha256msg1_epu32(set_arr(v0), set_arr(v1));
+        let mut output = [0u32; 4];
+        _mm_storeu_si128(output.as_mut_ptr().cast(), output_reg);
+        // The values are stored as little endian, so we need to reverse them
+        output.reverse();
+        assert_eq!(output, expected);
+    }
+}
+
+#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
+unsafe fn test_sha256msg2() {
+    let test_vectors = [
+        (
+            [0x801a28aa, 0xe75ff849, 0xb591b2cc, 0x8b64db2c],
+            [0x6f6d6521, 0x61776573, 0x20697320, 0x52757374],
+            [0xe7c46c4e, 0x8ce92ccc, 0xd3c0f3ce, 0xe9745c78],
+        ),
+        (
+            [0x171911ae, 0xe75ff849, 0xb591b2cc, 0x8b64db2c],
+            [0xe7c46c4e, 0x8ce92ccc, 0xd3c0f3ce, 0xe9745c78],
+            [0xc17c6ea3, 0xc4d10083, 0x712910cd, 0x3f41c8ce],
+        ),
+        (
+            [0x6ce67e04, 0x5fb6ff76, 0xe1037a25, 0x3ebc5bda],
+            [0xc17c6ea3, 0xc4d10083, 0x712910cd, 0x3f41c8ce],
+            [0xf5ab4eff, 0x83d732a5, 0x9bb941af, 0xdf1d0a8c],
+        ),
+    ];
+    for (v4, v3, expected) in test_vectors {
+        let output_reg = _mm_sha256msg2_epu32(set_arr(v4), set_arr(v3));
+        let mut output = [0u32; 4];
+        _mm_storeu_si128(output.as_mut_ptr().cast(), output_reg);
+        // The values are stored as little endian, so we need to reverse them
+        output.reverse();
+        assert_eq!(output, expected);
+    }
+}
+
+#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
+unsafe fn set_arr(x: [u32; 4]) -> __m128i {
+    _mm_set_epi32(x[0] as i32, x[1] as i32, x[2] as i32, x[3] as i32)
+}
+
+#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
+unsafe fn test_sha256() {
+    use std::fmt::Write;
+
+    /// The initial state of the hash engine.
+    const INITIAL_STATE: [u32; 8] = [
+        0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
+        0x5be0cd19,
+    ];
+
+    // We don't want to bother with hash finalization algorithm so we just feed constant data.
+    // This is the content that's being hashed - you can feed it to sha256sum and it'll output
+    // the same hash (beware of newlines though).
+    let first_block = *b"Rust is awesome!Rust is awesome!Rust is awesome!Rust is awesome!";
+    // sha256 is fianlized by appending 0x80, then zeros and finally the data lenght at the
+    // end.
+    let mut final_block = [0; 64];
+    final_block[0] = 0x80;
+    final_block[(64 - 8)..].copy_from_slice(&(8u64 * 64).to_be_bytes());
+
+    let mut state = INITIAL_STATE;
+    digest_blocks(&mut state, &[first_block, final_block]);
+
+    // We compare strings because it's easier to check the hex and the output of panic.
+    let mut hash = String::new();
+    for chunk in &state {
+        write!(hash, "{:08x}", chunk).expect("writing to String doesn't fail");
+    }
+    assert_eq!(hash, "1b2293d21b17a0cb0c18737307c37333dea775eded18cefed45e50389f9f8184");
+}
+
+// Almost full SHA256 implementation copied from RustCrypto's sha2 crate
+// https://github.com/RustCrypto/hashes/blob/6be8466247e936c415d8aafb848697f39894a386/sha2/src/sha256/x86.rs
+
+#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
+unsafe fn schedule(v0: __m128i, v1: __m128i, v2: __m128i, v3: __m128i) -> __m128i {
+    let t1 = _mm_sha256msg1_epu32(v0, v1);
+    let t2 = _mm_alignr_epi8(v3, v2, 4);
+    let t3 = _mm_add_epi32(t1, t2);
+    _mm_sha256msg2_epu32(t3, v3)
+}
+
+// we use unaligned loads with `__m128i` pointers
+#[allow(clippy::cast_ptr_alignment)]
+#[target_feature(enable = "sha,sse2,ssse3,sse4.1")]
+unsafe fn digest_blocks(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
+    #[allow(non_snake_case)]
+    let MASK: __m128i =
+        _mm_set_epi64x(0x0C0D_0E0F_0809_0A0Bu64 as i64, 0x0405_0607_0001_0203u64 as i64);
+
+    let state_ptr: *const __m128i = state.as_ptr().cast();
+    let dcba = _mm_loadu_si128(state_ptr.add(0));
+    let efgh = _mm_loadu_si128(state_ptr.add(1));
+
+    let cdab = _mm_shuffle_epi32(dcba, 0xB1);
+    let efgh = _mm_shuffle_epi32(efgh, 0x1B);
+    let mut abef = _mm_alignr_epi8(cdab, efgh, 8);
+    let mut cdgh = _mm_blend_epi16(efgh, cdab, 0xF0);
+
+    for block in blocks {
+        let abef_save = abef;
+        let cdgh_save = cdgh;
+
+        let block_ptr: *const __m128i = block.as_ptr().cast();
+        let mut w0 = _mm_shuffle_epi8(_mm_loadu_si128(block_ptr.add(0)), MASK);
+        let mut w1 = _mm_shuffle_epi8(_mm_loadu_si128(block_ptr.add(1)), MASK);
+        let mut w2 = _mm_shuffle_epi8(_mm_loadu_si128(block_ptr.add(2)), MASK);
+        let mut w3 = _mm_shuffle_epi8(_mm_loadu_si128(block_ptr.add(3)), MASK);
+        let mut w4;
+
+        rounds4!(abef, cdgh, w0, 0);
+        rounds4!(abef, cdgh, w1, 1);
+        rounds4!(abef, cdgh, w2, 2);
+        rounds4!(abef, cdgh, w3, 3);
+        schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 4);
+        schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 5);
+        schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 6);
+        schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 7);
+        schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 8);
+        schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 9);
+        schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 10);
+        schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 11);
+        schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 12);
+        schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 13);
+        schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 14);
+        schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 15);
+
+        abef = _mm_add_epi32(abef, abef_save);
+        cdgh = _mm_add_epi32(cdgh, cdgh_save);
+    }
+
+    let feba = _mm_shuffle_epi32(abef, 0x1B);
+    let dchg = _mm_shuffle_epi32(cdgh, 0xB1);
+    let dcba = _mm_blend_epi16(feba, dchg, 0xF0);
+    let hgef = _mm_alignr_epi8(dchg, feba, 8);
+
+    let state_ptr_mut: *mut __m128i = state.as_mut_ptr().cast();
+    _mm_storeu_si128(state_ptr_mut.add(0), dcba);
+    _mm_storeu_si128(state_ptr_mut.add(1), hgef);
+}
+
+/// Swapped round constants for SHA-256 family of digests
+pub static K32X4: [[u32; 4]; 16] = {
+    let mut res = [[0u32; 4]; 16];
+    let mut i = 0;
+    while i < 16 {
+        res[i] = [K32[4 * i + 3], K32[4 * i + 2], K32[4 * i + 1], K32[4 * i]];
+        i += 1;
+    }
+    res
+};
+
+/// Round constants for SHA-256 family of digests
+pub static K32: [u32; 64] = [
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
+];
diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs
index e6460fb93d3..9acbb16d73e 100644
--- a/src/tools/run-make-support/src/env.rs
+++ b/src/tools/run-make-support/src/env.rs
@@ -24,3 +24,11 @@ pub fn env_var_os(name: &str) -> OsString {
 pub fn no_debug_assertions() -> bool {
     std::env::var_os("NO_DEBUG_ASSERTIONS").is_some()
 }
+
+/// A wrapper around [`std::env::set_current_dir`] which includes the directory
+/// path in the panic message.
+#[track_caller]
+pub fn set_current_dir<P: AsRef<std::path::Path>>(dir: P) {
+    std::env::set_current_dir(dir.as_ref())
+        .expect(&format!("could not set current directory to \"{}\"", dir.as_ref().display()));
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index fc20fd3b2e8..956fa1404c7 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -64,7 +64,7 @@ pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
 pub use diff::{diff, Diff};
 
 /// Panic-on-fail [`std::env::var`] and [`std::env::var_os`] wrappers.
-pub use env::{env_var, env_var_os};
+pub use env::{env_var, env_var_os, set_current_dir};
 
 /// Convenience helpers for running binaries and other commands.
 pub use run::{cmd, run, run_fail, run_with_args};
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index f55abb513b8..05e8af5e1c5 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -11,4 +11,3 @@ run-make/macos-deployment-target/Makefile
 run-make/split-debuginfo/Makefile
 run-make/symbol-mangling-hashed/Makefile
 run-make/translation/Makefile
-run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
diff --git a/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs b/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
new file mode 100644
index 00000000000..a54a6d84a80
--- /dev/null
+++ b/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs
@@ -0,0 +1,10 @@
+// Verifies that "cfi-normalize-integers" module flag is added.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers
+
+#![crate_type = "lib"]
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1}
diff --git a/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs b/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs
new file mode 100644
index 00000000000..d48e4016a16
--- /dev/null
+++ b/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs
@@ -0,0 +1,21 @@
+// Verifies that "cfi-normalize-integers" module flag is added.
+//
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1}
diff --git a/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs b/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs
new file mode 100644
index 00000000000..b4924719f4c
--- /dev/null
+++ b/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs
@@ -0,0 +1,21 @@
+// Verifies that "kcfi-offset" module flag is added.
+//
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Z patchable-function-entry=4,3
+
+#![feature(no_core, lang_items, patchable_function_entry)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn foo() {}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-offset", i32 3}
diff --git a/tests/incremental/decl_macro.rs b/tests/incremental/decl_macro.rs
new file mode 100644
index 00000000000..74810ae4227
--- /dev/null
+++ b/tests/incremental/decl_macro.rs
@@ -0,0 +1,34 @@
+//@ revisions: rpass1 rpass2
+
+// issue#112680
+
+#![feature(decl_macro)]
+
+pub trait T {
+    type Key;
+    fn index_from_key(key: Self::Key) -> usize;
+}
+
+pub macro m($key_ty:ident, $val_ty:ident) {
+    struct $key_ty {
+        inner: usize,
+    }
+
+    impl T for $val_ty {
+        type Key = $key_ty;
+
+        fn index_from_key(key: Self::Key) -> usize {
+            key.inner
+        }
+    }
+}
+
+m!(TestId, Test);
+
+#[cfg(rpass1)]
+struct Test(u32);
+
+#[cfg(rpass2)]
+struct Test;
+
+fn main() {}
diff --git a/tests/run-make/debugger-visualizer-dep-info/foo.py b/tests/run-make/debugger-visualizer-dep-info/foo.py
deleted file mode 100644
index 1bb8bf6d7fd..00000000000
--- a/tests/run-make/debugger-visualizer-dep-info/foo.py
+++ /dev/null
@@ -1 +0,0 @@
-# empty
diff --git a/tests/run-make/debugger-visualizer-dep-info/main.rs b/tests/run-make/debugger-visualizer-dep-info/main.rs
index 3aede2215ea..3539b305be3 100644
--- a/tests/run-make/debugger-visualizer-dep-info/main.rs
+++ b/tests/run-make/debugger-visualizer-dep-info/main.rs
@@ -1,4 +1,4 @@
-#![debugger_visualizer(gdb_script_file = "foo.py")]
+#![debugger_visualizer(gdb_script_file = "my_gdb_script.py")]
 
 fn main() {
     const _UNUSED: u32 = {
diff --git a/tests/run-make/debugger-visualizer-dep-info/my_gdb_script.py b/tests/run-make/debugger-visualizer-dep-info/my_gdb_script.py
new file mode 100644
index 00000000000..d319792657e
--- /dev/null
+++ b/tests/run-make/debugger-visualizer-dep-info/my_gdb_script.py
@@ -0,0 +1,6 @@
+# This is a Python script, but we don't actually run it.
+# So if you're trying to remove Python scripts from the test suite,
+# be aware that there's no value in trying to get rid of this one.
+#
+# It just needs to exist so that the compiler can embed it via
+# `#![debugger_visualizer(gdb_script_file = "...")]`.
diff --git a/tests/run-make/debugger-visualizer-dep-info/rmake.rs b/tests/run-make/debugger-visualizer-dep-info/rmake.rs
index 65ffb2373e7..f5cf39157ac 100644
--- a/tests/run-make/debugger-visualizer-dep-info/rmake.rs
+++ b/tests/run-make/debugger-visualizer-dep-info/rmake.rs
@@ -6,6 +6,6 @@ use run_make_support::{invalid_utf8_contains, rustc};
 
 fn main() {
     rustc().emit("dep-info").input("main.rs").run();
-    invalid_utf8_contains("main.d", "foo.py");
+    invalid_utf8_contains("main.d", "my_gdb_script.py");
     invalid_utf8_contains("main.d", "my_visualizers/bar.natvis");
 }
diff --git a/tests/run-make/libtest-junit/validate_junit.py b/tests/run-make/libtest-junit/validate_junit.py
index 0d9b34a3cf7..f92473751b0 100755
--- a/tests/run-make/libtest-junit/validate_junit.py
+++ b/tests/run-make/libtest-junit/validate_junit.py
@@ -1,5 +1,15 @@
 #!/usr/bin/env python
 
+# Trivial Python script that reads lines from stdin, and checks that each line
+# is a well-formed XML document.
+#
+# This takes advantage of the fact that Python has a built-in XML parser,
+# whereas doing the same check in Rust would require us to pull in an XML
+# crate just for this relatively-minor test.
+#
+# If you're trying to remove Python scripts from the test suite, think twice
+# before removing this one. You could do so, but it's probably not worth it.
+
 import sys
 import xml.etree.ElementTree as ET
 
diff --git a/tests/run-make/msvc-wholearchive/c.c b/tests/run-make/msvc-wholearchive/c.c
new file mode 100644
index 00000000000..d6847845c68
--- /dev/null
+++ b/tests/run-make/msvc-wholearchive/c.c
@@ -0,0 +1 @@
+// This page is intentionally left blank
diff --git a/tests/run-make/msvc-wholearchive/dll.def b/tests/run-make/msvc-wholearchive/dll.def
new file mode 100644
index 00000000000..d55819e0d5e
--- /dev/null
+++ b/tests/run-make/msvc-wholearchive/dll.def
@@ -0,0 +1,4 @@
+LIBRARY dll
+EXPORTS
+        hello
+        number
diff --git a/tests/run-make/msvc-wholearchive/rmake.rs b/tests/run-make/msvc-wholearchive/rmake.rs
new file mode 100644
index 00000000000..98586fd8cc8
--- /dev/null
+++ b/tests/run-make/msvc-wholearchive/rmake.rs
@@ -0,0 +1,52 @@
+//! This is a regression test for #129020
+//! It ensures we can use `/WHOLEARCHIVE` to link a rust staticlib into DLL
+//! using the MSVC linker
+
+//@ only-msvc
+// Reason: this is testing the MSVC linker
+
+use std::path::PathBuf;
+
+use run_make_support::{cc, cmd, env_var, extra_c_flags, rustc};
+
+fn main() {
+    // Build the staticlib
+    rustc().crate_type("staticlib").input("static.rs").output("static.lib").run();
+    // Build an empty object to pass to the linker.
+    cc().input("c.c").output("c.obj").args(["-c"]).run();
+
+    // Find the C toolchain's linker.
+    let mut linker = PathBuf::from(env_var("CC"));
+    let linker_flavour = if linker.file_stem().is_some_and(|s| s == "cl") {
+        linker.set_file_name("link.exe");
+        "msvc"
+    } else if linker.file_stem().is_some_and(|s| s == "clang-cl") {
+        linker.set_file_name("lld-link.exe");
+        "llvm"
+    } else {
+        panic!("unknown C toolchain");
+    };
+
+    // As a sanity check, make sure this works without /WHOLEARCHIVE.
+    // Otherwise the actual test failure may be caused by something else.
+    cmd(&linker)
+        .args(["c.obj", "./static.lib", "-dll", "-def:dll.def", "-out:dll.dll"])
+        .args(extra_c_flags())
+        .run();
+
+    // FIXME(@ChrisDenton): this doesn't currently work with llvm's lld-link for other reasons.
+    // May need LLVM patches.
+    if linker_flavour == "msvc" {
+        // Link in the staticlib using `/WHOLEARCHIVE` and produce a DLL.
+        cmd(&linker)
+            .args([
+                "c.obj",
+                "-WHOLEARCHIVE:./static.lib",
+                "-dll",
+                "-def:dll.def",
+                "-out:dll_whole_archive.dll",
+            ])
+            .args(extra_c_flags())
+            .run();
+    }
+}
diff --git a/tests/run-make/msvc-wholearchive/static.rs b/tests/run-make/msvc-wholearchive/static.rs
new file mode 100644
index 00000000000..881c8856573
--- /dev/null
+++ b/tests/run-make/msvc-wholearchive/static.rs
@@ -0,0 +1,9 @@
+#[no_mangle]
+pub extern "C" fn hello() {
+    println!("Hello world!");
+}
+
+#[no_mangle]
+pub extern "C" fn number() -> u32 {
+    42
+}
diff --git a/tests/run-make/remove-dir-all-race/rmake.rs b/tests/run-make/remove-dir-all-race/rmake.rs
new file mode 100644
index 00000000000..03c94b76127
--- /dev/null
+++ b/tests/run-make/remove-dir-all-race/rmake.rs
@@ -0,0 +1,62 @@
+//@ ignore-windows
+
+// This test attempts to make sure that running `remove_dir_all`
+// doesn't result in a NotFound error one of the files it
+// is deleting is deleted concurrently.
+//
+// The windows implementation for `remove_dir_all` is significantly
+// more complicated, and has not yet been brought up to par with
+// the implementation on other platforms, so this test is marked as
+// `ignore-windows` until someone more expirenced with windows can
+// sort that out.
+
+use std::fs::remove_dir_all;
+use std::path::Path;
+use std::thread;
+use std::time::Duration;
+
+use run_make_support::rfs::{create_dir, write};
+use run_make_support::run_in_tmpdir;
+
+fn main() {
+    let mut race_happened = false;
+    run_in_tmpdir(|| {
+        for i in 0..150 {
+            create_dir("outer");
+            create_dir("outer/inner");
+            write("outer/inner.txt", b"sometext");
+
+            thread::scope(|scope| {
+                let t1 = scope.spawn(|| {
+                    thread::sleep(Duration::from_nanos(i));
+                    remove_dir_all("outer").unwrap();
+                });
+
+                let race_happened_ref = &race_happened;
+                let t2 = scope.spawn(|| {
+                    let r1 = remove_dir_all("outer/inner");
+                    let r2 = remove_dir_all("outer/inner.txt");
+                    if r1.is_ok() && r2.is_err() {
+                        race_happened = true;
+                    }
+                });
+            });
+
+            assert!(!Path::new("outer").exists());
+
+            // trying to remove a nonexistant top-level directory should
+            // still result in an error.
+            let Err(err) = remove_dir_all("outer") else {
+                panic!("removing nonexistant dir did not result in an error");
+            };
+            assert_eq!(err.kind(), std::io::ErrorKind::NotFound);
+        }
+    });
+    if !race_happened {
+        eprintln!(
+            "WARNING: multithreaded deletion never raced, \
+                   try increasing the number of attempts or \
+                   adjusting the sleep timing"
+        );
+    }
+}
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
deleted file mode 100644
index 3c88ec34f43..00000000000
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-include ../tools.mk
-
-#only-x86_64-fortanix-unknown-sgx
-
-# For cargo setting
-export RUSTC := $(RUSTC_ORIGINAL)
-export LD_LIBRARY_PATH := $(HOST_RPATH_DIR)
-# We need to be outside of 'src' dir in order to run cargo
-export WORK_DIR := $(TMPDIR)
-export TEST_DIR := $(shell pwd)
-
-## clean up unused env variables which might cause harm.
-unexport RUSTC_LINKER
-unexport RUSTC_BOOTSTRAP
-unexport RUST_BUILD_STAGE
-unexport RUST_TEST_THREADS
-unexport RUST_TEST_TMPDIR
-unexport AR
-unexport CC
-unexport CXX
-
-all:
-	bash script.sh
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs
new file mode 100644
index 00000000000..130781a4293
--- /dev/null
+++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs
@@ -0,0 +1,96 @@
+// ignore-tidy-linelength
+// Reason: intel.com link
+
+// This security test checks that the disassembled form of certain symbols
+// is "hardened" - that means, the assembly instructions match a pattern that
+// mitigate potential Load Value Injection vulnerabilities.
+// To do so, a test crate is compiled, and certain symbols are found, disassembled
+// and checked one by one.
+// See https://github.com/rust-lang/rust/pull/77008
+
+// On load value injection:
+// https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/load-value-injection.html
+
+//@ only-x86_64-fortanix-unknown-sgx
+
+use run_make_support::{cmd, cwd, llvm_filecheck, llvm_objdump, regex, set_current_dir, target};
+
+fn main() {
+    let main_dir = cwd();
+    set_current_dir("enclave");
+    // HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features.
+    // These come from the top-level Rust workspace, that this crate is not a
+    // member of, but Cargo tries to load the workspace `Cargo.toml` anyway.
+    cmd("cargo")
+        .env("RUSTC_BOOTSTRAP", "1")
+        .arg("-v")
+        .arg("run")
+        .arg("--target")
+        .arg(target())
+        .run();
+    set_current_dir(&main_dir);
+    // Rust has various ways of adding code to a binary:
+    // - Rust code
+    // - Inline assembly
+    // - Global assembly
+    // - C/C++ code compiled as part of Rust crates
+    // For those different kinds, we do have very small code examples that should be
+    // mitigated in some way. Mostly we check that ret instructions should no longer be present.
+    check("unw_getcontext", "unw_getcontext.checks");
+    check("__libunwind_Registers_x86_64_jumpto", "jumpto.checks");
+
+    check("std::io::stdio::_print::[[:alnum:]]+", "print.with_frame_pointers.checks");
+
+    check("rust_plus_one_global_asm", "rust_plus_one_global_asm.checks");
+
+    check("cc_plus_one_c", "cc_plus_one_c.checks");
+    check("cc_plus_one_c_asm", "cc_plus_one_c_asm.checks");
+    check("cc_plus_one_cxx", "cc_plus_one_cxx.checks");
+    check("cc_plus_one_cxx_asm", "cc_plus_one_cxx_asm.checks");
+    check("cc_plus_one_asm", "cc_plus_one_asm.checks");
+
+    check("cmake_plus_one_c", "cmake_plus_one_c.checks");
+    check("cmake_plus_one_c_asm", "cmake_plus_one_c_asm.checks");
+    check("cmake_plus_one_c_global_asm", "cmake_plus_one_c_global_asm.checks");
+    check("cmake_plus_one_cxx", "cmake_plus_one_cxx.checks");
+    check("cmake_plus_one_cxx_asm", "cmake_plus_one_cxx_asm.checks");
+    check("cmake_plus_one_cxx_global_asm", "cmake_plus_one_cxx_global_asm.checks");
+    check("cmake_plus_one_asm", "cmake_plus_one_asm.checks");
+}
+
+fn check(func_re: &str, mut checks: &str) {
+    let dump = llvm_objdump()
+        .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave")
+        .args(&["--syms", "--demangle"])
+        .run()
+        .stdout_utf8();
+    let re = regex::Regex::new(&format!("[[:blank:]]+{func_re}")).unwrap();
+    let func = re.find_iter(&dump).map(|m| m.as_str().trim()).collect::<Vec<&str>>().join(",");
+    assert!(!func.is_empty());
+    let dump = llvm_objdump()
+        .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave")
+        .args(&["--demangle", &format!("--disassemble-symbols={func}")])
+        .run()
+        .stdout_utf8();
+    let dump = dump.as_bytes();
+
+    // Unique case, must succeed at one of two possible tests.
+    // This is because frame pointers are optional, and them being enabled requires
+    // an additional `popq` in the pattern checking file.
+    if func_re == "std::io::stdio::_print::[[:alnum:]]+" {
+        let output = llvm_filecheck().stdin(&dump).patterns(checks).run_unchecked();
+        if !output.status().success() {
+            checks = "print.without_frame_pointers.checks";
+            llvm_filecheck().stdin(&dump).patterns(checks).run();
+        }
+    } else {
+        llvm_filecheck().stdin(&dump).patterns(checks).run();
+    }
+    if !["rust_plus_one_global_asm", "cmake_plus_one_c_global_asm", "cmake_plus_one_cxx_global_asm"]
+        .contains(&func_re)
+    {
+        // The assembler cannot avoid explicit `ret` instructions. Sequences
+        // of `shlq $0x0, (%rsp); lfence; retq` are used instead.
+        llvm_filecheck().args(&["--implicit-check-not", "ret"]).stdin(dump).patterns(checks).run();
+    }
+}
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh
deleted file mode 100644
index a7c4ae13ecb..00000000000
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/bash
-set -exuo pipefail
-
-function build {
-    CRATE=enclave
-
-    mkdir -p "${WORK_DIR}"
-    pushd "${WORK_DIR}"
-        rm -rf "${CRATE}"
-        cp -a "${TEST_DIR}"/enclave .
-        pushd $CRATE
-            echo "${WORK_DIR}"
-            # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features.
-            # These come from the top-level Rust workspace, that this crate is not a
-            # member of, but Cargo tries to load the workspace `Cargo.toml` anyway.
-            env RUSTC_BOOTSTRAP=1
-                cargo -v run --target "${TARGET}"
-        popd
-    popd
-}
-
-function check {
-    local func_re="$1"
-    local checks="${TEST_DIR}/$2"
-    local asm=""
-    local objdump="${LLVM_BIN_DIR}/llvm-objdump"
-    local filecheck="${LLVM_BIN_DIR}/FileCheck"
-    local enclave=${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave
-
-    asm=$(mktemp)
-    func="$(${objdump} --syms --demangle "${enclave}" | \
-            grep --only-matching -E "[[:blank:]]+${func_re}\$" | \
-            sed -e 's/^[[:space:]]*//' )"
-    ${objdump} --disassemble-symbols="${func}" --demangle \
-      "${enclave}" > "${asm}"
-    ${filecheck} --input-file "${asm}" "${checks}"
-
-    if [ "${func_re}" != "rust_plus_one_global_asm" ] &&
-         [ "${func_re}" != "cmake_plus_one_c_global_asm" ] &&
-         [ "${func_re}" != "cmake_plus_one_cxx_global_asm" ]; then
-        # The assembler cannot avoid explicit `ret` instructions. Sequences
-        # of `shlq $0x0, (%rsp); lfence; retq` are used instead.
-        # https://www.intel.com/content/www/us/en/developer/articles/technical/
-        #     software-security-guidance/technical-documentation/load-value-injection.html
-        ${filecheck} --implicit-check-not ret --input-file "${asm}" "${checks}"
-    fi
-}
-
-build
-
-check "unw_getcontext" unw_getcontext.checks
-check "__libunwind_Registers_x86_64_jumpto" jumpto.checks
-check 'std::io::stdio::_print::[[:alnum:]]+' print.with_frame_pointers.checks ||
-    check 'std::io::stdio::_print::[[:alnum:]]+' print.without_frame_pointers.checks
-check rust_plus_one_global_asm rust_plus_one_global_asm.checks
-
-check cc_plus_one_c cc_plus_one_c.checks
-check cc_plus_one_c_asm cc_plus_one_c_asm.checks
-check cc_plus_one_cxx cc_plus_one_cxx.checks
-check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks
-check cc_plus_one_asm cc_plus_one_asm.checks
-
-check cmake_plus_one_c cmake_plus_one_c.checks
-check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks
-check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks
-check cmake_plus_one_cxx cmake_plus_one_cxx.checks
-check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks
-check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks
-check cmake_plus_one_asm cmake_plus_one_asm.checks
diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml
index 82bd34ed274..92846f8e01d 100644
--- a/tests/rustdoc-gui/target.goml
+++ b/tests/rustdoc-gui/target.goml
@@ -11,7 +11,7 @@ define-function: (
     [theme, background, border],
     block {
         call-function: ("switch-theme", {"theme": |theme|})
-        assert-css: ("#method\.a_method:target", {
+        wait-for-css: ("#method\.a_method:target", {
             "background-color": |background|,
             "border-right": "3px solid " + |border|,
         })
diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs
index 5fcff74064a..442f9d72c3f 100644
--- a/tests/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs
@@ -117,4 +117,11 @@ pub fn skipped_because_of_annotation<'a>(dcx: DiagCtxtHandle<'a>) {
 fn f(_x: impl Into<DiagMessage>, _y: impl Into<SubdiagMessage>) {}
 fn g() {
     f(crate::fluent_generated::no_crate_example, crate::fluent_generated::no_crate_example);
+    f("untranslatable diagnostic", crate::fluent_generated::no_crate_example);
+    //~^ ERROR diagnostics should be created using translatable messages
+    f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic");
+    //~^ ERROR diagnostics should be created using translatable messages
+    f("untranslatable diagnostic", "untranslatable diagnostic");
+    //~^ ERROR diagnostics should be created using translatable messages
+    //~^^ ERROR diagnostics should be created using translatable messages
 }
diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr
index 669324ce5d4..36dd3cf4be7 100644
--- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr
@@ -1,8 +1,8 @@
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:43:9
+  --> $DIR/diagnostics.rs:43:31
    |
 LL |         Diag::new(dcx, level, "untranslatable diagnostic")
-   |         ^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/diagnostics.rs:7:9
@@ -11,16 +11,16 @@ LL | #![deny(rustc::untranslatable_diagnostic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:64:14
+  --> $DIR/diagnostics.rs:64:19
    |
 LL |         diag.note("untranslatable diagnostic");
-   |              ^^^^
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:85:14
+  --> $DIR/diagnostics.rs:85:19
    |
 LL |         diag.note("untranslatable diagnostic");
-   |              ^^^^
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
   --> $DIR/diagnostics.rs:99:21
@@ -41,10 +41,34 @@ LL |     let _diag = dcx.struct_err("untranslatable diagnostic");
    |                     ^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:102:21
+  --> $DIR/diagnostics.rs:102:32
    |
 LL |     let _diag = dcx.struct_err("untranslatable diagnostic");
-   |                     ^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: diagnostics should be created using translatable messages
+  --> $DIR/diagnostics.rs:120:7
+   |
+LL |     f("untranslatable diagnostic", crate::fluent_generated::no_crate_example);
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: diagnostics should be created using translatable messages
+  --> $DIR/diagnostics.rs:122:50
+   |
+LL |     f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic");
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: diagnostics should be created using translatable messages
+  --> $DIR/diagnostics.rs:124:7
+   |
+LL |     f("untranslatable diagnostic", "untranslatable diagnostic");
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: diagnostics should be created using translatable messages
+  --> $DIR/diagnostics.rs:124:36
+   |
+LL |     f("untranslatable diagnostic", "untranslatable diagnostic");
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
index 54d8f26f4ea..5f0347bdb4d 100644
--- a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
+++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
@@ -30,9 +30,9 @@ note: the lifetime `'c` as defined here...
 LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
    |                        ^^
 note: ...does not necessarily outlive the lifetime `'c` as defined here
-  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:12:24
    |
-LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+LL |     fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
    |                        ^^
 
 error[E0308]: method not compatible with trait
@@ -44,16 +44,15 @@ LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d
    = note: expected signature `fn(&'a _, Inv<'c>, Inv<'c>, Inv<'_>)`
               found signature `fn(&'a _, Inv<'_>, Inv<'c>, Inv<'_>)`
 note: the lifetime `'c` as defined here...
-  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:12:24
    |
-LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+LL |     fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
    |                        ^^
 note: ...does not necessarily outlive the lifetime `'c` as defined here
   --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
    |
 LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
    |                        ^^
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration
   --> $DIR/regions-bound-missing-bound-in-impl.rs:42:20
diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr
index d4fc1717538..ec01225c6bf 100644
--- a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr
+++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr
@@ -48,10 +48,10 @@ LL |     const STATIC: &str = "";
    = note: expected reference `&'static _`
               found reference `&_`
 note: the anonymous lifetime as defined here...
-  --> $DIR/elided-lifetime.rs:15:18
+  --> $DIR/elided-lifetime.rs:16:19
    |
-LL | impl Bar for Foo<'_> {
-   |                  ^^
+LL |     const STATIC: &str = "";
+   |                   ^
    = note: ...does not necessarily outlive the static lifetime
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr
index 8e4c27875ab..b8e2f412b49 100644
--- a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr
+++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr
@@ -30,10 +30,10 @@ LL |     const STATIC: &str = "";
    = note: expected reference `&_`
               found reference `&_`
 note: the anonymous lifetime as defined here...
-  --> $DIR/static-trait-impl.rs:8:10
+  --> $DIR/static-trait-impl.rs:9:19
    |
-LL | impl Bar<'_> for A {
-   |          ^^
+LL |     const STATIC: &str = "";
+   |                   ^
 note: ...does not necessarily outlive the anonymous lifetime as defined here
   --> $DIR/static-trait-impl.rs:8:10
    |
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
index d1decc0c3f1..37491ca12b0 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
+++ b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr
@@ -51,7 +51,7 @@ LL |     type A<'a> where Self: 'a;
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead:
              Fooy
              Fooer<T>
-   = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A = &'a ()> + 'static)>`
+   = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A<'a> = &'a ()> + 'static)>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/generic-associated-types/issue-76535.base.stderr b/tests/ui/generic-associated-types/issue-76535.base.stderr
index bb14e297174..88c08051da7 100644
--- a/tests/ui/generic-associated-types/issue-76535.base.stderr
+++ b/tests/ui/generic-associated-types/issue-76535.base.stderr
@@ -47,7 +47,7 @@ LL |     type SubType<'a>: SubTrait where Self: 'a;
    = help: consider moving `SubType` to another trait
    = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead
    = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type
-   = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType = SubStruct<'_>>>`
+   = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType<'_> = SubStruct<'_>>>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/generic-associated-types/issue-79422.base.stderr b/tests/ui/generic-associated-types/issue-79422.base.stderr
index bcc6382cf7c..551ad2a8fdf 100644
--- a/tests/ui/generic-associated-types/issue-79422.base.stderr
+++ b/tests/ui/generic-associated-types/issue-79422.base.stderr
@@ -49,7 +49,7 @@ LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
    = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead:
              std::collections::BTreeMap<K, V>
              Source
-   = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
+   = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont<'_> = (dyn RefCont<'_, u8> + 'static)>>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/generic-associated-types/issue-79422.extended.stderr b/tests/ui/generic-associated-types/issue-79422.extended.stderr
index ae1526296a7..031f8d8d851 100644
--- a/tests/ui/generic-associated-types/issue-79422.extended.stderr
+++ b/tests/ui/generic-associated-types/issue-79422.extended.stderr
@@ -28,7 +28,7 @@ LL |     type VRefCont<'a> = &'a V where Self: 'a;
    = note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
                  found reference `&u8`
    = help: `&u8` implements `RefCont` so you could box the found value and coerce it to the trait object `Box<dyn RefCont>`, you will have to change the expected type as well
-   = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
+   = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont<'_> = (dyn RefCont<'_, u8> + 'static)>>`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
index c8d1614a7f3..f498257e12f 100644
--- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
+++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
@@ -5,9 +5,9 @@ LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'s` as defined here...
-  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:12
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:8:12
    |
-LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
+LL |     fn get<'s>(s: &'s str, _: ()) -> &'static str;
    |            ^^
 note: ...so that the method type is compatible with trait
   --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5
diff --git a/tests/ui/issues/issue-20831-debruijn.stderr b/tests/ui/issues/issue-20831-debruijn.stderr
index 60721f001b7..fe310998f09 100644
--- a/tests/ui/issues/issue-20831-debruijn.stderr
+++ b/tests/ui/issues/issue-20831-debruijn.stderr
@@ -5,10 +5,10 @@ LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the anonymous lifetime as defined here...
-  --> $DIR/issue-20831-debruijn.rs:28:18
+  --> $DIR/issue-20831-debruijn.rs:28:67
    |
 LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-   |                  ^
+   |                                                                   ^^^^^^^^^
 note: ...but the lifetime must also be valid for the lifetime `'a` as defined here...
   --> $DIR/issue-20831-debruijn.rs:26:6
    |
diff --git a/tests/ui/issues/issue-37884.stderr b/tests/ui/issues/issue-37884.stderr
index b7c0095d682..17037d2180d 100644
--- a/tests/ui/issues/issue-37884.stderr
+++ b/tests/ui/issues/issue-37884.stderr
@@ -7,10 +7,7 @@ LL |     fn next(&'a mut self) -> Option<Self::Item>
    = note: expected signature `fn(&mut RepeatMut<'_, _>) -> Option<_>`
               found signature `fn(&'a mut RepeatMut<'_, _>) -> Option<_>`
 note: the anonymous lifetime as defined here...
-  --> $DIR/issue-37884.rs:6:5
-   |
-LL |     fn next(&'a mut self) -> Option<Self::Item>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 note: ...does not necessarily outlive the lifetime `'a` as defined here
   --> $DIR/issue-37884.rs:3:6
    |
diff --git a/tests/ui/regions/explicit-static-bound-on-trait.rs b/tests/ui/regions/explicit-static-bound-on-trait.rs
new file mode 100644
index 00000000000..835da34d1bb
--- /dev/null
+++ b/tests/ui/regions/explicit-static-bound-on-trait.rs
@@ -0,0 +1,13 @@
+struct Hello<'a> {
+    value: Box<dyn std::any::Any + 'a>,
+    //~^ ERROR lifetime bound not satisfied
+}
+
+impl<'a> Hello<'a> {
+    fn new<T: 'a>(value: T) -> Self {
+        Self { value: Box::new(value) }
+        //~^ ERROR the parameter type `T` may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/regions/explicit-static-bound-on-trait.stderr b/tests/ui/regions/explicit-static-bound-on-trait.stderr
new file mode 100644
index 00000000000..30d39c6e86e
--- /dev/null
+++ b/tests/ui/regions/explicit-static-bound-on-trait.stderr
@@ -0,0 +1,32 @@
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/explicit-static-bound-on-trait.rs:2:12
+   |
+LL |     value: Box<dyn std::any::Any + 'a>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined here
+  --> $DIR/explicit-static-bound-on-trait.rs:1:14
+   |
+LL | struct Hello<'a> {
+   |              ^^
+note: but lifetime parameter must outlive the static lifetime
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/explicit-static-bound-on-trait.rs:8:23
+   |
+LL |         Self { value: Box::new(value) }
+   |                       ^^^^^^^^^^^^^^^
+   |                       |
+   |                       the parameter type `T` must be valid for the static lifetime...
+   |                       ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     fn new<T: 'a + 'static>(value: T) -> Self {
+   |                  +++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0310, E0478.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs
index 8958871ed5d..6660ff040f7 100644
--- a/tests/ui/traits/object/pretty.rs
+++ b/tests/ui/traits/object/pretty.rs
@@ -18,6 +18,10 @@ trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {}
 trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {}
 trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super<Assoc = u8> {}
 
+trait HasGat<Outer> {
+    type Assoc<Inner> where Self: Sized;
+}
+
 fn dyn_super(x: &dyn Super<Assoc = u8>) { x } //~ERROR mismatched types
 fn dyn_any(x: &dyn Any<Assoc = u8>) { x } //~ERROR mismatched types
 fn dyn_fixed(x: &dyn Fixed) { x } //~ERROR mismatched types
@@ -34,4 +38,7 @@ fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types
 fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } //~ERROR mismatched types
 fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } //~ERROR mismatched types
 
+fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x } //~ERROR mismatched types
+//~^ WARN unnecessary associated type bound
+
 fn main() {}
diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr
index bc645e5f967..6964d97c08e 100644
--- a/tests/ui/traits/object/pretty.stderr
+++ b/tests/ui/traits/object/pretty.stderr
@@ -1,5 +1,14 @@
+warning: unnecessary associated type bound for not object safe associated type
+  --> $DIR/pretty.rs:41:35
+   |
+LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
+   |                                   ^^^^^^^^^^^^^^^^ help: remove this bound
+   |
+   = note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized`
+   = note: `#[warn(unused_associated_type_bounds)]` on by default
+
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:21:43
+  --> $DIR/pretty.rs:25:43
    |
 LL | fn dyn_super(x: &dyn Super<Assoc = u8>) { x }
    |                                        -  ^ expected `()`, found `&dyn Super<Assoc = u8>`
@@ -10,7 +19,7 @@ LL | fn dyn_super(x: &dyn Super<Assoc = u8>) { x }
               found reference `&dyn Super<Assoc = u8>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:22:39
+  --> $DIR/pretty.rs:26:39
    |
 LL | fn dyn_any(x: &dyn Any<Assoc = u8>) { x }
    |                                    -  ^ expected `()`, found `&dyn Any<Assoc = u8>`
@@ -21,7 +30,7 @@ LL | fn dyn_any(x: &dyn Any<Assoc = u8>) { x }
               found reference `&dyn Any<Assoc = u8>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:23:31
+  --> $DIR/pretty.rs:27:31
    |
 LL | fn dyn_fixed(x: &dyn Fixed) { x }
    |                            -  ^ expected `()`, found `&dyn Fixed`
@@ -32,7 +41,7 @@ LL | fn dyn_fixed(x: &dyn Fixed) { x }
               found reference `&dyn Fixed`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:24:50
+  --> $DIR/pretty.rs:28:50
    |
 LL | fn dyn_fixed_multi(x: &dyn Fixed<Assoc = u16>) { x }
    |                                               -  ^ expected `()`, found `&dyn Fixed<Assoc = u16>`
@@ -43,7 +52,7 @@ LL | fn dyn_fixed_multi(x: &dyn Fixed<Assoc = u16>) { x }
               found reference `&dyn Fixed<Assoc = u16>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:25:38
+  --> $DIR/pretty.rs:29:38
    |
 LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x }
    |                                   -  ^ expected `()`, found `&dyn FixedSub`
@@ -54,7 +63,7 @@ LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x }
               found reference `&dyn FixedSub`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:26:44
+  --> $DIR/pretty.rs:30:44
    |
 LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x }
    |                                         -  ^ expected `()`, found `&dyn FixedStatic`
@@ -65,7 +74,7 @@ LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x }
               found reference `&dyn FixedStatic`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:28:75
+  --> $DIR/pretty.rs:32:75
    |
 LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x }
    |                                                                        -  ^ expected `()`, found `&dyn SuperGeneric<'a, Assoc2 = &u8>`
@@ -76,7 +85,7 @@ LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x
               found reference `&dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:29:71
+  --> $DIR/pretty.rs:33:71
    |
 LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x }
    |                                                                    -  ^ expected `()`, found `&dyn AnyGeneric<'a, Assoc2 = &u8>`
@@ -87,7 +96,7 @@ LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x }
               found reference `&dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:30:60
+  --> $DIR/pretty.rs:34:60
    |
 LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x }
    |                                                         -  ^ expected `()`, found `&dyn FixedGeneric1<'a>`
@@ -98,7 +107,7 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x }
               found reference `&dyn for<'a> FixedGeneric1<'a>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:31:60
+  --> $DIR/pretty.rs:35:60
    |
 LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x }
    |                                                         -  ^ expected `()`, found `&dyn FixedGeneric2<'a>`
@@ -109,7 +118,7 @@ LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x }
               found reference `&dyn for<'a> FixedGeneric2<'a>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:32:79
+  --> $DIR/pretty.rs:36:79
    |
 LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x }
    |                                                                            -  ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>`
@@ -120,7 +129,7 @@ LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>)
               found reference `&dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:33:40
+  --> $DIR/pretty.rs:37:40
    |
 LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x }
    |                                     -  ^ expected `()`, found `&dyn FixedHrtb`
@@ -131,7 +140,7 @@ LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x }
               found reference `&dyn FixedHrtb`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:34:73
+  --> $DIR/pretty.rs:38:73
    |
 LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x }
    |                                                                      -  ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = ...>`
@@ -142,7 +151,7 @@ LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x }
               found reference `&dyn AnyDifferentBinders<Assoc = u8>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:35:65
+  --> $DIR/pretty.rs:39:65
    |
 LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x }
    |                                                              -  ^ expected `()`, found `&dyn FixedDifferentBinders`
@@ -152,6 +161,17 @@ LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x }
    = note: expected unit type `()`
               found reference `&dyn FixedDifferentBinders`
 
-error: aborting due to 14 previous errors
+error[E0308]: mismatched types
+  --> $DIR/pretty.rs:41:56
+   |
+LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
+   |                                                     -  ^ expected `()`, found `&dyn HasGat<u8, Assoc<bool> = ()>`
+   |                                                     |
+   |                                                     help: try adding a return type: `-> &dyn HasGat<u8, Assoc<bool> = ()>`
+   |
+   = note: expected unit type `()`
+              found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
+
+error: aborting due to 15 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0308`.