about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock9
-rw-r--r--compiler/rustc_abi/src/layout.rs581
-rw-r--r--compiler/rustc_arena/src/lib.rs42
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/README.md18
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/action.yml13
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js162
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/package-lock.json571
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/package.json11
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml7
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml62
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml18
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock143
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml16
-rw-r--r--compiler/rustc_codegen_cranelift/Readme.md5
-rw-r--r--compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock28
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs29
-rw-r--r--compiler/rustc_codegen_cranelift/example/alloc_example.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/example/dst-field-align.rs41
-rw-r--r--compiler/rustc_codegen_cranelift/example/example.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/example/issue-72793.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs52
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/example/mod_bench.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs27
-rw-r--r--compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs8
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh72
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/comments.rs32
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/returning.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs54
-rw-r--r--compiler/rustc_codegen_cranelift/src/cast.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs147
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs26
-rw-r--r--compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs67
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/mod.rs29
-rw-r--r--compiler/rustc_codegen_cranelift/src/global_asm.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs57
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs330
-rwxr-xr-xcompiler/rustc_codegen_cranelift/y.rs6
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs79
-rw-r--r--compiler/rustc_metadata/src/creader.rs10
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs7
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs15
-rw-r--r--compiler/rustc_resolve/src/late.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs19
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs58
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs22
-rw-r--r--library/alloc/src/collections/btree/map.rs60
-rw-r--r--library/alloc/src/collections/btree/set.rs20
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs2
-rw-r--r--library/core/src/array/mod.rs4
-rw-r--r--library/core/src/iter/range.rs20
-rw-r--r--library/portable-simd/crates/core_simd/src/ops/deref.rs2
-rw-r--r--src/bootstrap/bootstrap.py35
-rw-r--r--src/bootstrap/builder.rs13
-rw-r--r--src/bootstrap/builder/tests.rs1
-rw-r--r--src/bootstrap/lib.rs1
-rw-r--r--src/bootstrap/metadata.rs42
-rw-r--r--src/bootstrap/test.rs505
-rw-r--r--src/bootstrap/tool.rs2
-rw-r--r--src/doc/rustdoc/src/lints.md38
-rw-r--r--src/librustdoc/html/render/mod.rs18
-rw-r--r--src/librustdoc/lib.rs11
-rw-r--r--src/librustdoc/lint.rs12
-rw-r--r--src/librustdoc/passes/lint.rs2
-rw-r--r--src/librustdoc/passes/lint/unescaped_backticks.rs416
-rw-r--r--src/tools/compiletest/src/header.rs11
-rw-r--r--src/tools/compiletest/src/header/cfg.rs6
-rw-r--r--src/tools/compiletest/src/runtest.rs25
-rw-r--r--src/tools/tidy/src/deps.rs10
-rw-r--r--tests/codegen/issues/issue-103840.rs1
-rw-r--r--tests/codegen/issues/issue-105386-ub-in-debuginfo.rs3
-rw-r--r--tests/codegen/issues/issue-86106.rs29
-rw-r--r--tests/mir-opt/issue_41888.main.ElaborateDrops.diff2
-rw-r--r--tests/run-make/core-no-oom-handling/Makefile6
-rw-r--r--tests/rustdoc-ui/unescaped_backticks.rs342
-rw-r--r--tests/rustdoc-ui/unescaped_backticks.stderr959
-rw-r--r--tests/rustdoc/deref/deref-const-fn.rs (renamed from tests/rustdoc/deref-const-fn.rs)0
-rw-r--r--tests/rustdoc/deref/deref-multiple-impl-blocks.rs43
-rw-r--r--tests/rustdoc/deref/deref-mut-methods.rs (renamed from tests/rustdoc/deref-mut-methods.rs)0
-rw-r--r--tests/rustdoc/deref/deref-recursive-pathbuf.rs (renamed from tests/rustdoc/deref-recursive-pathbuf.rs)0
-rw-r--r--tests/rustdoc/deref/deref-recursive.rs (renamed from tests/rustdoc/deref-recursive.rs)0
-rw-r--r--tests/rustdoc/deref/deref-slice-core.rs (renamed from tests/rustdoc/deref-slice-core.rs)0
-rw-r--r--tests/rustdoc/deref/deref-to-primitive.rs (renamed from tests/rustdoc/deref-to-primitive.rs)0
-rw-r--r--tests/rustdoc/deref/deref-typedef.rs (renamed from tests/rustdoc/deref-typedef.rs)0
-rw-r--r--tests/rustdoc/deref/escape-deref-methods.rs (renamed from tests/rustdoc/escape-deref-methods.rs)0
-rw-r--r--tests/rustdoc/deref/issue-100679-sidebar-links-deref.rs (renamed from tests/rustdoc/issue-100679-sidebar-links-deref.rs)0
-rw-r--r--tests/rustdoc/deref/recursive-deref-sidebar.rs (renamed from tests/rustdoc/recursive-deref-sidebar.rs)0
-rw-r--r--tests/rustdoc/deref/recursive-deref.rs (renamed from tests/rustdoc/recursive-deref.rs)0
-rw-r--r--tests/ui/async-await/future-sizes/async-awaiting-fut.stdout40
-rw-r--r--tests/ui/async-await/future-sizes/large-arg.stdout24
-rw-r--r--tests/ui/async-await/in-trait/nested-rpit.rs4
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-early.rs48
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-early.stderr45
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-late.rs50
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-late.stderr19
-rw-r--r--tests/ui/binding/issue-53114-safety-checks.stderr18
-rw-r--r--tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr3
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.32bit.stderr4
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.64bit.stderr4
-rw-r--r--tests/ui/feature-gates/test-listing-format-json.rs18
-rw-r--r--tests/ui/feature-gates/test-listing-format-json.run.stderr1
-rw-r--r--tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr40
-rw-r--r--tests/ui/lint/unaligned_references.stderr30
-rw-r--r--tests/ui/lint/unaligned_references_external_macro.stderr3
-rw-r--r--tests/ui/native-library-link-flags/msvc-non-utf8-output.rs6
-rw-r--r--tests/ui/native-library-link-flags/msvc-non-utf8-output.stderr7
-rw-r--r--tests/ui/packed/issue-27060.stderr12
-rw-r--r--tests/ui/packed/packed-struct-borrow-element-64bit.stderr3
-rw-r--r--tests/ui/packed/packed-struct-borrow-element.stderr6
-rw-r--r--tests/ui/print_type_sizes/async.stdout8
-rw-r--r--tests/ui/print_type_sizes/generator.stdout8
-rw-r--r--tests/ui/structs-enums/type-sizes.rs67
-rw-r--r--tests/ui/test-attrs/tests-listing-format-json.rs1
-rw-r--r--tests/ui/test-attrs/tests-listing-format-json.run.stdout6
-rw-r--r--tests/ui/traits/new-solver/exponential-trait-goals.rs20
-rw-r--r--tests/ui/traits/new-solver/exponential-trait-goals.stderr23
133 files changed, 4689 insertions, 1456 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 06a2a36f455..cc539fb0a43 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1956,9 +1956,9 @@ dependencies = [
 
 [[package]]
 name = "libffi-sys"
-version = "2.2.1"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc65067b78c0fc069771e8b9a9e02df71e08858bec92c1f101377c67b9dca7c7"
+checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c"
 dependencies = [
  "cc",
 ]
@@ -2370,9 +2370,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.84"
+version = "0.9.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa"
+checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e"
 dependencies = [
  "cc",
  "libc",
@@ -3250,6 +3250,7 @@ dependencies = [
  "tempfile",
  "thorin-dwp",
  "tracing",
+ "windows 0.46.0",
 ]
 
 [[package]]
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index f3af031ade4..b4597d5bc78 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -1,4 +1,5 @@
 use super::*;
+use std::fmt::Write;
 use std::{borrow::Borrow, cmp, iter, ops::Bound};
 
 #[cfg(feature = "randomize")]
@@ -49,220 +50,60 @@ pub trait LayoutCalculator {
         repr: &ReprOptions,
         kind: StructKind,
     ) -> Option<LayoutS> {
-        let pack = repr.pack;
-        let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
-        let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
-        let optimize = !repr.inhibit_struct_field_reordering_opt();
-        if optimize {
-            let end =
-                if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
-            let optimizing = &mut inverse_memory_index.raw[..end];
-            let effective_field_align = |layout: Layout<'_>| {
-                if let Some(pack) = pack {
-                    // return the packed alignment in bytes
-                    layout.align().abi.min(pack).bytes()
-                } else {
-                    // returns log2(effective-align).
-                    // This is ok since `pack` applies to all fields equally.
-                    // The calculation assumes that size is an integer multiple of align, except for ZSTs.
-                    //
-                    // group [u8; 4] with align-4 or [u8; 6] with align-2 fields
-                    layout.align().abi.bytes().max(layout.size().bytes()).trailing_zeros() as u64
-                }
-            };
-
-            // If `-Z randomize-layout` was enabled for the type definition we can shuffle
-            // the field ordering to try and catch some code making assumptions about layouts
-            // we don't guarantee
-            if repr.can_randomize_type_layout() && cfg!(feature = "randomize") {
-                #[cfg(feature = "randomize")]
-                {
-                    // `ReprOptions.layout_seed` is a deterministic seed that we can use to
-                    // randomize field ordering with
-                    let mut rng =
-                        Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed.as_u64());
-
-                    // Shuffle the ordering of the fields
-                    optimizing.shuffle(&mut rng);
-                }
-                // Otherwise we just leave things alone and actually optimize the type's fields
-            } else {
-                match kind {
-                    StructKind::AlwaysSized | StructKind::MaybeUnsized => {
-                        optimizing.sort_by_key(|&x| {
-                            // Place ZSTs first to avoid "interesting offsets",
-                            // especially with only one or two non-ZST fields.
-                            // Then place largest alignments first, largest niches within an alignment group last
-                            let f = fields[x];
-                            let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
-                            (!f.0.is_zst(), cmp::Reverse(effective_field_align(f)), niche_size)
-                        });
-                    }
-
-                    StructKind::Prefixed(..) => {
-                        // Sort in ascending alignment so that the layout stays optimal
-                        // regardless of the prefix.
-                        // And put the largest niche in an alignment group at the end
-                        // so it can be used as discriminant in jagged enums
-                        optimizing.sort_by_key(|&x| {
-                            let f = fields[x];
-                            let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
-                            (effective_field_align(f), niche_size)
-                        });
+        let layout = univariant(self, dl, fields, repr, kind, NicheBias::Start);
+        // Enums prefer niches close to the beginning or the end of the variants so that other (smaller)
+        // data-carrying variants can be packed into the space after/before the niche.
+        // If the default field ordering does not give us a niche at the front then we do a second
+        // run and bias niches to the right and then check which one is closer to one of the struct's
+        // edges.
+        if let Some(layout) = &layout {
+            if let Some(niche) = layout.largest_niche {
+                let head_space = niche.offset.bytes();
+                let niche_length = niche.value.size(dl).bytes();
+                let tail_space = layout.size.bytes() - head_space - niche_length;
+
+                // This may end up doing redundant work if the niche is already in the last field
+                // (e.g. a trailing bool) and there is tail padding. But it's non-trivial to get
+                // the unpadded size so we try anyway.
+                if fields.len() > 1 && head_space != 0 && tail_space > 0 {
+                    let alt_layout = univariant(self, dl, fields, repr, kind, NicheBias::End)
+                        .expect("alt layout should always work");
+                    let niche = alt_layout
+                        .largest_niche
+                        .expect("alt layout should have a niche like the regular one");
+                    let alt_head_space = niche.offset.bytes();
+                    let alt_niche_len = niche.value.size(dl).bytes();
+                    let alt_tail_space = alt_layout.size.bytes() - alt_head_space - alt_niche_len;
+
+                    debug_assert_eq!(layout.size.bytes(), alt_layout.size.bytes());
+
+                    let prefer_alt_layout =
+                        alt_head_space > head_space && alt_head_space > tail_space;
+
+                    debug!(
+                        "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\
+                        layout: {}\n\
+                        alt_layout: {}\n",
+                        layout.size.bytes(),
+                        head_space,
+                        niche_length,
+                        tail_space,
+                        alt_head_space,
+                        alt_niche_len,
+                        alt_tail_space,
+                        layout.fields.count(),
+                        prefer_alt_layout,
+                        format_field_niches(&layout, &fields, &dl),
+                        format_field_niches(&alt_layout, &fields, &dl),
+                    );
+
+                    if prefer_alt_layout {
+                        return Some(alt_layout);
                     }
                 }
-
-                // FIXME(Kixiron): We can always shuffle fields within a given alignment class
-                //                 regardless of the status of `-Z randomize-layout`
             }
         }
-        // inverse_memory_index holds field indices by increasing memory offset.
-        // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
-        // We now write field offsets to the corresponding offset slot;
-        // field 5 with offset 0 puts 0 in offsets[5].
-        // At the bottom of this function, we invert `inverse_memory_index` to
-        // produce `memory_index` (see `invert_mapping`).
-        let mut sized = true;
-        let mut offsets = IndexVec::from_elem(Size::ZERO, &fields);
-        let mut offset = Size::ZERO;
-        let mut largest_niche = None;
-        let mut largest_niche_available = 0;
-        if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
-            let prefix_align =
-                if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align };
-            align = align.max(AbiAndPrefAlign::new(prefix_align));
-            offset = prefix_size.align_to(prefix_align);
-        }
-        for &i in &inverse_memory_index {
-            let field = &fields[i];
-            if !sized {
-                self.delay_bug(&format!(
-                    "univariant: field #{} comes after unsized field",
-                    offsets.len(),
-                ));
-            }
-
-            if field.0.is_unsized() {
-                sized = false;
-            }
-
-            // Invariant: offset < dl.obj_size_bound() <= 1<<61
-            let field_align = if let Some(pack) = pack {
-                field.align().min(AbiAndPrefAlign::new(pack))
-            } else {
-                field.align()
-            };
-            offset = offset.align_to(field_align.abi);
-            align = align.max(field_align);
-
-            debug!("univariant offset: {:?} field: {:#?}", offset, field);
-            offsets[i] = offset;
-
-            if let Some(mut niche) = field.largest_niche() {
-                let available = niche.available(dl);
-                if available > largest_niche_available {
-                    largest_niche_available = available;
-                    niche.offset += offset;
-                    largest_niche = Some(niche);
-                }
-            }
-
-            offset = offset.checked_add(field.size(), dl)?;
-        }
-        if let Some(repr_align) = repr.align {
-            align = align.max(AbiAndPrefAlign::new(repr_align));
-        }
-        debug!("univariant min_size: {:?}", offset);
-        let min_size = offset;
-        // As stated above, inverse_memory_index holds field indices by increasing offset.
-        // This makes it an already-sorted view of the offsets vec.
-        // To invert it, consider:
-        // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
-        // Field 5 would be the first element, so memory_index is i:
-        // Note: if we didn't optimize, it's already right.
-        let memory_index = if optimize {
-            inverse_memory_index.invert_bijective_mapping()
-        } else {
-            debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
-            inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect()
-        };
-        let size = min_size.align_to(align.abi);
-        let mut abi = Abi::Aggregate { sized };
-        // Unpack newtype ABIs and find scalar pairs.
-        if sized && size.bytes() > 0 {
-            // All other fields must be ZSTs.
-            let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst());
-
-            match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) {
-                // We have exactly one non-ZST field.
-                (Some((i, field)), None, None) => {
-                    // Field fills the struct and it has a scalar or scalar pair ABI.
-                    if offsets[i].bytes() == 0
-                        && align.abi == field.align().abi
-                        && size == field.size()
-                    {
-                        match field.abi() {
-                            // For plain scalars, or vectors of them, we can't unpack
-                            // newtypes for `#[repr(C)]`, as that affects C ABIs.
-                            Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
-                                abi = field.abi();
-                            }
-                            // But scalar pairs are Rust-specific and get
-                            // treated as aggregates by C ABIs anyway.
-                            Abi::ScalarPair(..) => {
-                                abi = field.abi();
-                            }
-                            _ => {}
-                        }
-                    }
-                }
-
-                // Two non-ZST fields, and they're both scalars.
-                (Some((i, a)), Some((j, b)), None) => {
-                    match (a.abi(), b.abi()) {
-                        (Abi::Scalar(a), Abi::Scalar(b)) => {
-                            // Order by the memory placement, not source order.
-                            let ((i, a), (j, b)) = if offsets[i] < offsets[j] {
-                                ((i, a), (j, b))
-                            } else {
-                                ((j, b), (i, a))
-                            };
-                            let pair = self.scalar_pair(a, b);
-                            let pair_offsets = match pair.fields {
-                                FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
-                                    assert_eq!(memory_index.raw, [0, 1]);
-                                    offsets
-                                }
-                                _ => panic!(),
-                            };
-                            if offsets[i] == pair_offsets[FieldIdx::from_usize(0)]
-                                && offsets[j] == pair_offsets[FieldIdx::from_usize(1)]
-                                && align == pair.align
-                                && size == pair.size
-                            {
-                                // We can use `ScalarPair` only when it matches our
-                                // already computed layout (including `#[repr(C)]`).
-                                abi = pair.abi;
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-
-                _ => {}
-            }
-        }
-        if fields.iter().any(|f| f.abi().is_uninhabited()) {
-            abi = Abi::Uninhabited;
-        }
-        Some(LayoutS {
-            variants: Variants::Single { index: FIRST_VARIANT },
-            fields: FieldsShape::Arbitrary { offsets, memory_index },
-            abi,
-            largest_niche,
-            align,
-            size,
-        })
+        layout
     }
 
     fn layout_of_never_type(&self) -> LayoutS {
@@ -934,3 +775,323 @@ pub trait LayoutCalculator {
         })
     }
 }
+
+/// Determines towards which end of a struct layout optimizations will try to place the best niches.
+enum NicheBias {
+    Start,
+    End,
+}
+
+fn univariant(
+    this: &(impl LayoutCalculator + ?Sized),
+    dl: &TargetDataLayout,
+    fields: &IndexSlice<FieldIdx, Layout<'_>>,
+    repr: &ReprOptions,
+    kind: StructKind,
+    niche_bias: NicheBias,
+) -> Option<LayoutS> {
+    let pack = repr.pack;
+    let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
+    let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
+    let optimize = !repr.inhibit_struct_field_reordering_opt();
+    if optimize && fields.len() > 1 {
+        let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
+        let optimizing = &mut inverse_memory_index.raw[..end];
+
+        // If `-Z randomize-layout` was enabled for the type definition we can shuffle
+        // the field ordering to try and catch some code making assumptions about layouts
+        // we don't guarantee
+        if repr.can_randomize_type_layout() && cfg!(feature = "randomize") {
+            #[cfg(feature = "randomize")]
+            {
+                // `ReprOptions.layout_seed` is a deterministic seed that we can use to
+                // randomize field ordering with
+                let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed.as_u64());
+
+                // Shuffle the ordering of the fields
+                optimizing.shuffle(&mut rng);
+            }
+            // Otherwise we just leave things alone and actually optimize the type's fields
+        } else {
+            let max_field_align = fields.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1);
+            let largest_niche_size = fields
+                .iter()
+                .filter_map(|f| f.largest_niche())
+                .map(|n| n.available(dl))
+                .max()
+                .unwrap_or(0);
+
+            // Calculates a sort key to group fields by their alignment or possibly some size-derived
+            // pseudo-alignment.
+            let alignment_group_key = |layout: Layout<'_>| {
+                if let Some(pack) = pack {
+                    // return the packed alignment in bytes
+                    layout.align().abi.min(pack).bytes()
+                } else {
+                    // returns log2(effective-align).
+                    // This is ok since `pack` applies to all fields equally.
+                    // The calculation assumes that size is an integer multiple of align, except for ZSTs.
+                    //
+                    let align = layout.align().abi.bytes();
+                    let size = layout.size().bytes();
+                    let niche_size = layout.largest_niche().map(|n| n.available(dl)).unwrap_or(0);
+                    // group [u8; 4] with align-4 or [u8; 6] with align-2 fields
+                    let size_as_align = align.max(size).trailing_zeros();
+                    let size_as_align = if largest_niche_size > 0 {
+                        match niche_bias {
+                            // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the array
+                            // to the front in the first case (for aligned loads) but keep the bool in front
+                            // in the second case for its niches.
+                            NicheBias::Start => max_field_align.trailing_zeros().min(size_as_align),
+                            // When moving niches towards the end of the struct then for
+                            // A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple
+                            // in the align-1 group because its bool can be moved closer to the end.
+                            NicheBias::End if niche_size == largest_niche_size => {
+                                align.trailing_zeros()
+                            }
+                            NicheBias::End => size_as_align,
+                        }
+                    } else {
+                        size_as_align
+                    };
+                    size_as_align as u64
+                }
+            };
+
+            match kind {
+                StructKind::AlwaysSized | StructKind::MaybeUnsized => {
+                    // Currently `LayoutS` only exposes a single niche so sorting is usually sufficient
+                    // to get one niche into the preferred position. If it ever supported multiple niches
+                    // then a more advanced pick-and-pack approach could provide better results.
+                    // But even for the single-niche cache it's not optimal. E.g. for
+                    // A(u32, (bool, u8), u16) it would be possible to move the bool to the front
+                    // but it would require packing the tuple together with the u16 to build a 4-byte
+                    // group so that the u32 can be placed after it without padding. This kind
+                    // of packing can't be achieved by sorting.
+                    optimizing.sort_by_key(|&x| {
+                        let f = fields[x];
+                        let field_size = f.size().bytes();
+                        let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
+                        let niche_size_key = match niche_bias {
+                            // large niche first
+                            NicheBias::Start => !niche_size,
+                            // large niche last
+                            NicheBias::End => niche_size,
+                        };
+                        let inner_niche_offset_key = match niche_bias {
+                            NicheBias::Start => f.largest_niche().map_or(0, |n| n.offset.bytes()),
+                            NicheBias::End => f.largest_niche().map_or(0, |n| {
+                                !(field_size - n.value.size(dl).bytes() - n.offset.bytes())
+                            }),
+                        };
+
+                        (
+                            // Place ZSTs first to avoid "interesting offsets", especially with only one
+                            // or two non-ZST fields. This helps Scalar/ScalarPair layouts.
+                            !f.0.is_zst(),
+                            // Then place largest alignments first.
+                            cmp::Reverse(alignment_group_key(f)),
+                            // Then prioritize niche placement within alignment group according to
+                            // `niche_bias_start`.
+                            niche_size_key,
+                            // Then among fields with equally-sized niches prefer the ones
+                            // closer to the start/end of the field.
+                            inner_niche_offset_key,
+                        )
+                    });
+                }
+
+                StructKind::Prefixed(..) => {
+                    // Sort in ascending alignment so that the layout stays optimal
+                    // regardless of the prefix.
+                    // And put the largest niche in an alignment group at the end
+                    // so it can be used as discriminant in jagged enums
+                    optimizing.sort_by_key(|&x| {
+                        let f = fields[x];
+                        let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
+                        (alignment_group_key(f), niche_size)
+                    });
+                }
+            }
+
+            // FIXME(Kixiron): We can always shuffle fields within a given alignment class
+            //                 regardless of the status of `-Z randomize-layout`
+        }
+    }
+    // inverse_memory_index holds field indices by increasing memory offset.
+    // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
+    // We now write field offsets to the corresponding offset slot;
+    // field 5 with offset 0 puts 0 in offsets[5].
+    // At the bottom of this function, we invert `inverse_memory_index` to
+    // produce `memory_index` (see `invert_mapping`).
+    let mut sized = true;
+    let mut offsets = IndexVec::from_elem(Size::ZERO, &fields);
+    let mut offset = Size::ZERO;
+    let mut largest_niche = None;
+    let mut largest_niche_available = 0;
+    if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
+        let prefix_align =
+            if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align };
+        align = align.max(AbiAndPrefAlign::new(prefix_align));
+        offset = prefix_size.align_to(prefix_align);
+    }
+    for &i in &inverse_memory_index {
+        let field = &fields[i];
+        if !sized {
+            this.delay_bug(&format!(
+                "univariant: field #{} comes after unsized field",
+                offsets.len(),
+            ));
+        }
+
+        if field.0.is_unsized() {
+            sized = false;
+        }
+
+        // Invariant: offset < dl.obj_size_bound() <= 1<<61
+        let field_align = if let Some(pack) = pack {
+            field.align().min(AbiAndPrefAlign::new(pack))
+        } else {
+            field.align()
+        };
+        offset = offset.align_to(field_align.abi);
+        align = align.max(field_align);
+
+        debug!("univariant offset: {:?} field: {:#?}", offset, field);
+        offsets[i] = offset;
+
+        if let Some(mut niche) = field.largest_niche() {
+            let available = niche.available(dl);
+            // Pick up larger niches.
+            let prefer_new_niche = match niche_bias {
+                NicheBias::Start => available > largest_niche_available,
+                // if there are several niches of the same size then pick the last one
+                NicheBias::End => available >= largest_niche_available,
+            };
+            if prefer_new_niche {
+                largest_niche_available = available;
+                niche.offset += offset;
+                largest_niche = Some(niche);
+            }
+        }
+
+        offset = offset.checked_add(field.size(), dl)?;
+    }
+    if let Some(repr_align) = repr.align {
+        align = align.max(AbiAndPrefAlign::new(repr_align));
+    }
+    debug!("univariant min_size: {:?}", offset);
+    let min_size = offset;
+    // As stated above, inverse_memory_index holds field indices by increasing offset.
+    // This makes it an already-sorted view of the offsets vec.
+    // To invert it, consider:
+    // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
+    // Field 5 would be the first element, so memory_index is i:
+    // Note: if we didn't optimize, it's already right.
+    let memory_index = if optimize {
+        inverse_memory_index.invert_bijective_mapping()
+    } else {
+        debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
+        inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect()
+    };
+    let size = min_size.align_to(align.abi);
+    let mut abi = Abi::Aggregate { sized };
+    // Unpack newtype ABIs and find scalar pairs.
+    if sized && size.bytes() > 0 {
+        // All other fields must be ZSTs.
+        let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst());
+
+        match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) {
+            // We have exactly one non-ZST field.
+            (Some((i, field)), None, None) => {
+                // Field fills the struct and it has a scalar or scalar pair ABI.
+                if offsets[i].bytes() == 0 && align.abi == field.align().abi && size == field.size()
+                {
+                    match field.abi() {
+                        // For plain scalars, or vectors of them, we can't unpack
+                        // newtypes for `#[repr(C)]`, as that affects C ABIs.
+                        Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
+                            abi = field.abi();
+                        }
+                        // But scalar pairs are Rust-specific and get
+                        // treated as aggregates by C ABIs anyway.
+                        Abi::ScalarPair(..) => {
+                            abi = field.abi();
+                        }
+                        _ => {}
+                    }
+                }
+            }
+
+            // Two non-ZST fields, and they're both scalars.
+            (Some((i, a)), Some((j, b)), None) => {
+                match (a.abi(), b.abi()) {
+                    (Abi::Scalar(a), Abi::Scalar(b)) => {
+                        // Order by the memory placement, not source order.
+                        let ((i, a), (j, b)) = if offsets[i] < offsets[j] {
+                            ((i, a), (j, b))
+                        } else {
+                            ((j, b), (i, a))
+                        };
+                        let pair = this.scalar_pair(a, b);
+                        let pair_offsets = match pair.fields {
+                            FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
+                                assert_eq!(memory_index.raw, [0, 1]);
+                                offsets
+                            }
+                            _ => panic!(),
+                        };
+                        if offsets[i] == pair_offsets[FieldIdx::from_usize(0)]
+                            && offsets[j] == pair_offsets[FieldIdx::from_usize(1)]
+                            && align == pair.align
+                            && size == pair.size
+                        {
+                            // We can use `ScalarPair` only when it matches our
+                            // already computed layout (including `#[repr(C)]`).
+                            abi = pair.abi;
+                        }
+                    }
+                    _ => {}
+                }
+            }
+
+            _ => {}
+        }
+    }
+    if fields.iter().any(|f| f.abi().is_uninhabited()) {
+        abi = Abi::Uninhabited;
+    }
+    Some(LayoutS {
+        variants: Variants::Single { index: FIRST_VARIANT },
+        fields: FieldsShape::Arbitrary { offsets, memory_index },
+        abi,
+        largest_niche,
+        align,
+        size,
+    })
+}
+
+fn format_field_niches(
+    layout: &LayoutS,
+    fields: &IndexSlice<FieldIdx, Layout<'_>>,
+    dl: &TargetDataLayout,
+) -> String {
+    let mut s = String::new();
+    for i in layout.fields.index_by_increasing_offset() {
+        let offset = layout.fields.offset(i);
+        let f = fields[i.into()];
+        write!(s, "[o{}a{}s{}", offset.bytes(), f.align().abi.bytes(), f.size().bytes()).unwrap();
+        if let Some(n) = f.largest_niche() {
+            write!(
+                s,
+                " n{}b{}s{}",
+                n.offset.bytes(),
+                n.available(dl).ilog2(),
+                n.value.size(dl).bytes()
+            )
+            .unwrap();
+        }
+        write!(s, "] ").unwrap();
+    }
+    s
+}
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 236bdb99709..6e15f06a76d 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -20,6 +20,7 @@
 #![feature(rustc_attrs)]
 #![cfg_attr(test, feature(test))]
 #![feature(strict_provenance)]
+#![deny(unsafe_op_in_unsafe_fn)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 #![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
@@ -74,19 +75,27 @@ impl<T> ArenaChunk<T> {
     #[inline]
     unsafe fn new(capacity: usize) -> ArenaChunk<T> {
         ArenaChunk {
-            storage: NonNull::new_unchecked(Box::into_raw(Box::new_uninit_slice(capacity))),
+            storage: NonNull::from(Box::leak(Box::new_uninit_slice(capacity))),
             entries: 0,
         }
     }
 
     /// Destroys this arena chunk.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `len` elements of this chunk have been initialized.
     #[inline]
     unsafe fn destroy(&mut self, len: usize) {
         // The branch on needs_drop() is an -O1 performance optimization.
-        // Without the branch, dropping TypedArena<u8> takes linear time.
+        // Without the branch, dropping TypedArena<T> takes linear time.
         if mem::needs_drop::<T>() {
-            let slice = self.storage.as_mut();
-            ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len]));
+            // SAFETY: The caller must ensure that `len` elements of this chunk have
+            // been initialized.
+            unsafe {
+                let slice = self.storage.as_mut();
+                ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len]));
+            }
         }
     }
 
@@ -255,7 +264,9 @@ impl<T> TypedArena<T> {
         self.ensure_capacity(len);
 
         let start_ptr = self.ptr.get();
-        self.ptr.set(start_ptr.add(len));
+        // SAFETY: `self.ensure_capacity` makes sure that there is enough space
+        // for `len` elements.
+        unsafe { self.ptr.set(start_ptr.add(len)) };
         start_ptr
     }
 
@@ -483,6 +494,10 @@ impl DroplessArena {
         }
     }
 
+    /// # Safety
+    ///
+    /// The caller must ensure that `mem` is valid for writes up to
+    /// `size_of::<T>() * len`.
     #[inline]
     unsafe fn write_from_iter<T, I: Iterator<Item = T>>(
         &self,
@@ -494,13 +509,18 @@ impl DroplessArena {
         // Use a manual loop since LLVM manages to optimize it better for
         // slice iterators
         loop {
-            let value = iter.next();
-            if i >= len || value.is_none() {
-                // We only return as many items as the iterator gave us, even
-                // though it was supposed to give us `len`
-                return slice::from_raw_parts_mut(mem, i);
+            // SAFETY: The caller must ensure that `mem` is valid for writes up to
+            // `size_of::<T>() * len`.
+            unsafe {
+                match iter.next() {
+                    Some(value) if i < len => mem.add(i).write(value),
+                    Some(_) | None => {
+                        // We only return as many items as the iterator gave us, even
+                        // though it was supposed to give us `len`
+                        return slice::from_raw_parts_mut(mem, i);
+                    }
+                }
             }
-            ptr::write(mem.add(i), value.unwrap());
             i += 1;
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/README.md b/compiler/rustc_codegen_cranelift/.github/actions/github-release/README.md
new file mode 100644
index 00000000000..c70ba8f4953
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/README.md
@@ -0,0 +1,18 @@
+# github-release
+
+An action used to publish GitHub releases for `wasmtime`.
+
+As of the time of this writing there's a few actions floating around which
+perform github releases but they all tend to have their set of drawbacks.
+Additionally nothing handles deleting releases which we need for our rolling
+`dev` release.
+
+To handle all this this action rolls-its-own implementation using the
+actions/toolkit repository and packages published there. These run in a Docker
+container and take various inputs to orchestrate the release from the build.
+
+More comments can be found in `main.js`.
+
+Testing this is really hard. If you want to try though run `npm install` and
+then `node main.js`. You'll have to configure a bunch of env vars though to get
+anything reasonably working.
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/action.yml b/compiler/rustc_codegen_cranelift/.github/actions/github-release/action.yml
new file mode 100644
index 00000000000..36e5209f50c
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/action.yml
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+name: 'rustc_codegen_cranelift github releases'
+description: 'rustc_codegen_cranelift github releases'
+inputs:
+  token:
+    description: ''
+    required: true
+  files:
+    description: ''
+    required: true
+runs:
+  using: 'node16'
+  main: 'main.js'
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
new file mode 100644
index 00000000000..6fcfca34ea7
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+const core = require('@actions/core');
+const path = require("path");
+const fs = require("fs");
+const github = require('@actions/github');
+const glob = require('glob');
+
+function sleep(milliseconds) {
+  return new Promise(resolve => setTimeout(resolve, milliseconds))
+}
+
+async function runOnce() {
+  // Load all our inputs and env vars. Note that `getInput` reads from `INPUT_*`
+  const files = core.getInput('files');
+  const token = core.getInput('token');
+  const slug = process.env.GITHUB_REPOSITORY;
+  const owner = slug.split('/')[0];
+  const repo = slug.split('/')[1];
+  const sha = process.env.GITHUB_SHA;
+  let name = 'dev';
+  if (process.env.GITHUB_REF.startsWith('refs/tags/v')) {
+    name = process.env.GITHUB_REF.substring(10);
+  }
+
+  core.info(`files: ${files}`);
+  core.info(`name: ${name}`);
+  core.info(`token: ${token}`);
+
+  const octokit = github.getOctokit(token);
+
+  // For the `dev` release we may need to update the tag to point to the new
+  // commit on this branch. All other names should already have tags associated
+  // with them.
+  if (name == 'dev') {
+    let tag = null;
+    try {
+      tag = await octokit.request("GET /repos/:owner/:repo/git/refs/tags/:name", { owner, repo, name });
+      core.info(`found existing tag`);
+      console.log("tag: ", JSON.stringify(tag.data, null, 2));
+    } catch (e) {
+      // ignore if this tag doesn't exist
+      core.info(`no existing tag found`);
+    }
+
+    if (tag === null || tag.data.object.sha !== sha) {
+      core.info(`updating existing tag or creating new one`);
+
+      try {
+        core.info(`updating dev tag`);
+        await octokit.rest.git.updateRef({
+          owner,
+          repo,
+          ref: 'tags/dev',
+          sha,
+          force: true,
+        });
+      } catch (e) {
+        console.log("ERROR: ", JSON.stringify(e.data, null, 2));
+        core.info(`creating dev tag`);
+        try {
+          await octokit.rest.git.createRef({
+            owner,
+            repo,
+            ref: 'refs/tags/dev',
+            sha,
+          });
+        } catch (e) {
+          // we might race with others, so assume someone else has created the
+          // tag by this point.
+          console.log("failed to create tag: ", JSON.stringify(e.data, null, 2));
+        }
+      }
+
+      console.log("double-checking tag is correct");
+      tag = await octokit.request("GET /repos/:owner/:repo/git/refs/tags/:name", { owner, repo, name });
+      if (tag.data.object.sha !== sha) {
+        console.log("tag: ", JSON.stringify(tag.data, null, 2));
+        throw new Error("tag didn't work");
+      }
+    } else {
+      core.info(`existing tag works`);
+    }
+  }
+
+  // Delete a previous release
+  try {
+    core.info(`fetching release`);
+    let release = await octokit.rest.repos.getReleaseByTag({ owner, repo, tag: name });
+    console.log("found release: ", JSON.stringify(release.data, null, 2));
+    await octokit.rest.repos.deleteRelease({
+      owner,
+      repo,
+      release_id: release.data.id,
+    });
+    console.log("deleted release");
+  } catch (e) {
+    console.log("ERROR: ", JSON.stringify(e, null, 2));
+  }
+
+  console.log("creating a release");
+  let release = await octokit.rest.repos.createRelease({
+    owner,
+    repo,
+    tag_name: name,
+    prerelease: name === 'dev',
+  });
+
+  // Delete all assets from a previous run
+  for (const asset of release.data.assets) {
+    console.log(`deleting prior asset ${asset.id}`);
+    await octokit.rest.repos.deleteReleaseAsset({
+      owner,
+      repo,
+      asset_id: asset.id,
+    });
+  }
+
+  // Upload all the relevant assets for this release as just general blobs.
+  for (const file of glob.sync(files)) {
+    const size = fs.statSync(file).size;
+    const name = path.basename(file);
+    core.info(`upload ${file}`);
+    await octokit.rest.repos.uploadReleaseAsset({
+      data: fs.createReadStream(file),
+      headers: { 'content-length': size, 'content-type': 'application/octet-stream' },
+      name,
+      url: release.data.upload_url,
+    });
+  }
+}
+
+async function run() {
+  const retries = 10;
+  for (let i = 0; i < retries; i++) {
+    try {
+      await runOnce();
+      break;
+    } catch (e) {
+      if (i === retries - 1)
+        throw e;
+      logError(e);
+      console.log("RETRYING after 10s");
+      await sleep(10000)
+    }
+  }
+}
+
+function logError(e) {
+  console.log("ERROR: ", e.message);
+  try {
+    console.log(JSON.stringify(e, null, 2));
+  } catch (e) {
+    // ignore json errors for now
+  }
+  console.log(e.stack);
+}
+
+run().catch(err => {
+  logError(err);
+  core.setFailed(err.message);
+});
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/package-lock.json b/compiler/rustc_codegen_cranelift/.github/actions/github-release/package-lock.json
new file mode 100644
index 00000000000..dd3b2a048f0
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/package-lock.json
@@ -0,0 +1,571 @@
+{
+  "name": "rustc_codegen_cranelift-github-release",
+  "version": "0.0.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "rustc_codegen_cranelift-github-release",
+      "version": "0.0.0",
+      "dependencies": {
+        "@actions/core": "^1.9.1",
+        "@actions/github": "^5.1.0",
+        "glob": "^7.1.5"
+      }
+    },
+    "node_modules/@actions/core": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
+      "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
+      "dependencies": {
+        "@actions/http-client": "^2.0.1",
+        "uuid": "^8.3.2"
+      }
+    },
+    "node_modules/@actions/github": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz",
+      "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==",
+      "dependencies": {
+        "@actions/http-client": "^2.0.1",
+        "@octokit/core": "^3.6.0",
+        "@octokit/plugin-paginate-rest": "^2.17.0",
+        "@octokit/plugin-rest-endpoint-methods": "^5.13.0"
+      }
+    },
+    "node_modules/@actions/http-client": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
+      "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
+      "dependencies": {
+        "tunnel": "^0.0.6"
+      }
+    },
+    "node_modules/@octokit/auth-token": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+      "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+      "dependencies": {
+        "@octokit/types": "^6.0.3"
+      }
+    },
+    "node_modules/@octokit/core": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
+      "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
+      "dependencies": {
+        "@octokit/auth-token": "^2.4.4",
+        "@octokit/graphql": "^4.5.8",
+        "@octokit/request": "^5.6.3",
+        "@octokit/request-error": "^2.0.5",
+        "@octokit/types": "^6.0.3",
+        "before-after-hook": "^2.2.0",
+        "universal-user-agent": "^6.0.0"
+      }
+    },
+    "node_modules/@octokit/endpoint": {
+      "version": "6.0.12",
+      "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+      "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+      "dependencies": {
+        "@octokit/types": "^6.0.3",
+        "is-plain-object": "^5.0.0",
+        "universal-user-agent": "^6.0.0"
+      }
+    },
+    "node_modules/@octokit/graphql": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+      "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+      "dependencies": {
+        "@octokit/request": "^5.6.0",
+        "@octokit/types": "^6.0.3",
+        "universal-user-agent": "^6.0.0"
+      }
+    },
+    "node_modules/@octokit/openapi-types": {
+      "version": "12.11.0",
+      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz",
+      "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
+    },
+    "node_modules/@octokit/plugin-paginate-rest": {
+      "version": "2.21.3",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
+      "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
+      "dependencies": {
+        "@octokit/types": "^6.40.0"
+      },
+      "peerDependencies": {
+        "@octokit/core": ">=2"
+      }
+    },
+    "node_modules/@octokit/plugin-rest-endpoint-methods": {
+      "version": "5.16.2",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
+      "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
+      "dependencies": {
+        "@octokit/types": "^6.39.0",
+        "deprecation": "^2.3.1"
+      },
+      "peerDependencies": {
+        "@octokit/core": ">=3"
+      }
+    },
+    "node_modules/@octokit/request": {
+      "version": "5.6.3",
+      "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
+      "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
+      "dependencies": {
+        "@octokit/endpoint": "^6.0.1",
+        "@octokit/request-error": "^2.1.0",
+        "@octokit/types": "^6.16.1",
+        "is-plain-object": "^5.0.0",
+        "node-fetch": "^2.6.7",
+        "universal-user-agent": "^6.0.0"
+      }
+    },
+    "node_modules/@octokit/request-error": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+      "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+      "dependencies": {
+        "@octokit/types": "^6.0.3",
+        "deprecation": "^2.0.0",
+        "once": "^1.4.0"
+      }
+    },
+    "node_modules/@octokit/types": {
+      "version": "6.41.0",
+      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
+      "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
+      "dependencies": {
+        "@octokit/openapi-types": "^12.11.0"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/before-after-hook": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
+      "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "node_modules/deprecation": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+      "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/is-plain-object": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+      "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/node-fetch": {
+      "version": "2.6.7",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+    },
+    "node_modules/tunnel": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+      "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+      "engines": {
+        "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+      }
+    },
+    "node_modules/universal-user-agent": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
+      "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
+    },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    }
+  },
+  "dependencies": {
+    "@actions/core": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
+      "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
+      "requires": {
+        "@actions/http-client": "^2.0.1",
+        "uuid": "^8.3.2"
+      }
+    },
+    "@actions/github": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz",
+      "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==",
+      "requires": {
+        "@actions/http-client": "^2.0.1",
+        "@octokit/core": "^3.6.0",
+        "@octokit/plugin-paginate-rest": "^2.17.0",
+        "@octokit/plugin-rest-endpoint-methods": "^5.13.0"
+      }
+    },
+    "@actions/http-client": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
+      "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
+      "requires": {
+        "tunnel": "^0.0.6"
+      }
+    },
+    "@octokit/auth-token": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+      "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+      "requires": {
+        "@octokit/types": "^6.0.3"
+      }
+    },
+    "@octokit/core": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
+      "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
+      "requires": {
+        "@octokit/auth-token": "^2.4.4",
+        "@octokit/graphql": "^4.5.8",
+        "@octokit/request": "^5.6.3",
+        "@octokit/request-error": "^2.0.5",
+        "@octokit/types": "^6.0.3",
+        "before-after-hook": "^2.2.0",
+        "universal-user-agent": "^6.0.0"
+      }
+    },
+    "@octokit/endpoint": {
+      "version": "6.0.12",
+      "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+      "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+      "requires": {
+        "@octokit/types": "^6.0.3",
+        "is-plain-object": "^5.0.0",
+        "universal-user-agent": "^6.0.0"
+      }
+    },
+    "@octokit/graphql": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+      "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+      "requires": {
+        "@octokit/request": "^5.6.0",
+        "@octokit/types": "^6.0.3",
+        "universal-user-agent": "^6.0.0"
+      }
+    },
+    "@octokit/openapi-types": {
+      "version": "12.11.0",
+      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz",
+      "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
+    },
+    "@octokit/plugin-paginate-rest": {
+      "version": "2.21.3",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
+      "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
+      "requires": {
+        "@octokit/types": "^6.40.0"
+      }
+    },
+    "@octokit/plugin-rest-endpoint-methods": {
+      "version": "5.16.2",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
+      "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
+      "requires": {
+        "@octokit/types": "^6.39.0",
+        "deprecation": "^2.3.1"
+      }
+    },
+    "@octokit/request": {
+      "version": "5.6.3",
+      "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
+      "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
+      "requires": {
+        "@octokit/endpoint": "^6.0.1",
+        "@octokit/request-error": "^2.1.0",
+        "@octokit/types": "^6.16.1",
+        "is-plain-object": "^5.0.0",
+        "node-fetch": "^2.6.7",
+        "universal-user-agent": "^6.0.0"
+      }
+    },
+    "@octokit/request-error": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+      "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+      "requires": {
+        "@octokit/types": "^6.0.3",
+        "deprecation": "^2.0.0",
+        "once": "^1.4.0"
+      }
+    },
+    "@octokit/types": {
+      "version": "6.41.0",
+      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
+      "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
+      "requires": {
+        "@octokit/openapi-types": "^12.11.0"
+      }
+    },
+    "balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "before-after-hook": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
+      "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "deprecation": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+      "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    },
+    "glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "is-plain-object": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+      "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
+    },
+    "minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "node-fetch": {
+      "version": "2.6.7",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+      "requires": {
+        "whatwg-url": "^5.0.0"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
+    },
+    "tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+    },
+    "tunnel": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+      "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
+    },
+    "universal-user-agent": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
+      "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
+    },
+    "uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
+    },
+    "webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+    },
+    "whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "requires": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    }
+  }
+}
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/package.json b/compiler/rustc_codegen_cranelift/.github/actions/github-release/package.json
new file mode 100644
index 00000000000..d9c23f8873e
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/package.json
@@ -0,0 +1,11 @@
+{
+  "name": "rustc_codegen_cranelift-github-release",
+  "version": "0.0.0",
+  "license": "Apache-2.0 WITH LLVM-exception",
+  "main": "main.js",
+  "dependencies": {
+    "@actions/core": "^1.9.1",
+    "@actions/github": "^5.1.0",
+    "glob": "^7.1.5"
+  }
+}
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
index 5f5510a5796..3c40555669c 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
@@ -45,13 +45,6 @@ jobs:
       if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       run: rustup set default-host x86_64-pc-windows-gnu
 
-    - name: Use sparse cargo registry
-      run: |
-        cat >> ~/.cargo/config.toml <<EOF
-        [unstable]
-        sparse-registry = true
-        EOF
-
     - name: Prepare dependencies
       run: ./y.rs prepare
 
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 98b34c65dea..e4af73ea644 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -20,6 +20,7 @@ jobs:
       run: |
         cargo fmt --check
         rustfmt --check build_system/mod.rs
+        rustfmt --check example/*
 
 
   test:
@@ -89,13 +90,6 @@ jobs:
         sudo apt-get update
         sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
 
-    - name: Use sparse cargo registry
-      run: |
-        cat >> ~/.cargo/config.toml <<EOF
-        [unstable]
-        sparse-registry = true
-        EOF
-
     - name: Prepare dependencies
       run: ./y.rs prepare
 
@@ -137,13 +131,6 @@ jobs:
         path: ~/.cargo/bin
         key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-bin-dir-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
-    - name: Use sparse cargo registry
-      run: |
-        cat >> ~/.cargo/config.toml <<EOF
-        [unstable]
-        sparse-registry = true
-        EOF
-
     - name: Install hyperfine
       run: cargo install hyperfine || true
 
@@ -206,13 +193,6 @@ jobs:
         sudo apt-get update
         sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
 
-    - name: Use sparse cargo registry
-      run: |
-        cat >> ~/.cargo/config.toml <<EOF
-        [unstable]
-        sparse-registry = true
-        EOF
-
     - name: Prepare dependencies
       run: ./y.rs prepare
 
@@ -238,3 +218,43 @@ jobs:
       with:
         name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
         path: cg_clif.tar.xz
+
+  release:
+    runs-on: ubuntu-latest
+    timeout-minutes: 10
+    if: ${{ github.ref == 'refs/heads/master' }}
+    needs: [rustfmt, test, bench, dist]
+
+    concurrency:
+      group: release-dev
+      cancel-in-progress: true
+
+    steps:
+      - uses: actions/checkout@v3
+
+      - name: Download all built artifacts
+        uses: actions/download-artifact@v3
+        with:
+          path: artifacts/
+
+      - run: |
+          ls -R artifacts/
+          mkdir release/
+          pushd artifacts/
+          for dir in *; do
+            mv $dir/cg_clif.tar.xz ../release/$dir.tar.xz
+            rmdir $dir/ # verify $dir is empty
+          done
+          popd
+          rmdir artifacts/ # verify all artifacts are represented in release/
+          ls -R release/
+
+      - run: npm install --production
+        working-directory: .github/actions/github-release
+
+      - name: Publish Release
+        uses: ./.github/actions/github-release
+        with:
+          files: "release/*"
+          token: ${{ github.token }}
+        continue-on-error: true
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
index 5faa8f05404..b2f772c4fc4 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
@@ -6,6 +6,7 @@ on:
 jobs:
   bootstrap_rustc:
     runs-on: ubuntu-latest
+    timeout-minutes: 60
 
     steps:
     - uses: actions/checkout@v3
@@ -16,20 +17,16 @@ jobs:
         path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
-    - name: Use sparse cargo registry
-      run: |
-        cat >> ~/.cargo/config.toml <<EOF
-        [unstable]
-        sparse-registry = true
-        EOF
-
     - name: Prepare dependencies
       run: ./y.rs prepare
 
     - name: Test
       run: ./scripts/test_bootstrap.sh
+
+
   rustc_test_suite:
     runs-on: ubuntu-latest
+    timeout-minutes: 60
 
     steps:
     - uses: actions/checkout@v3
@@ -40,13 +37,6 @@ jobs:
         path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
-    - name: Use sparse cargo registry
-      run: |
-        cat >> ~/.cargo/config.toml <<EOF
-        [unstable]
-        sparse-registry = true
-        EOF
-
     - name: Prepare dependencies
       run: ./y.rs prepare
 
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 87e4ac26605..07a8e431a0e 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -4,11 +4,11 @@ version = 3
 
 [[package]]
 name = "ahash"
-version = "0.7.6"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
 dependencies = [
- "getrandom",
+ "cfg-if",
  "once_cell",
  "version_check",
 ]
@@ -20,12 +20,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
 
 [[package]]
-name = "arrayvec"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
-
-[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -57,20 +51,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.93.1"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7379abaacee0f14abf3204a7606118f0465785252169d186337bcb75030815a"
+checksum = "1277fbfa94bc82c8ec4af2ded3e639d49ca5f7f3c7eeab2c66accd135ece4e70"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.93.1"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9489fa336927df749631f1008007ced2871068544f40a202ce6d93fbf2366a7b"
+checksum = "c6e8c31ad3b2270e9aeec38723888fe1b0ace3bea2b06b3f749ccf46661d3220"
 dependencies = [
- "arrayvec",
  "bumpalo",
  "cranelift-bforest",
  "cranelift-codegen-meta",
@@ -78,7 +71,7 @@ dependencies = [
  "cranelift-entity",
  "cranelift-isle",
  "gimli",
- "hashbrown",
+ "hashbrown 0.13.2",
  "log",
  "regalloc2",
  "smallvec",
@@ -87,30 +80,30 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.93.1"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05bbb67da91ec721ed57cef2f7c5ef7728e1cd9bde9ffd3ef8601022e73e3239"
+checksum = "c8ac5ac30d62b2d66f12651f6b606dbdfd9c2cfd0908de6b387560a277c5c9da"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.93.1"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418ecb2f36032f6665dc1a5e2060a143dbab41d83b784882e97710e890a7a16d"
+checksum = "dd82b8b376247834b59ed9bdc0ddeb50f517452827d4a11bccf5937b213748b8"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.93.1"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705"
+checksum = "40099d38061b37e505e63f89bab52199037a72b931ad4868d9089ff7268660b0"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.93.0"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d361ed0373cf5f086b49c499aa72227b646a64f899f32e34312f97c0fadff75"
+checksum = "64a25d9d0a0ae3079c463c34115ec59507b4707175454f0eee0891e83e30e82d"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -120,15 +113,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.93.1"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "649782a39ce99798dd6b4029e2bb318a2fbeaade1b4fa25330763c10c65bc358"
+checksum = "80de6a7d0486e4acbd5f9f87ec49912bf4c8fb6aea00087b989685460d4469ba"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.93.0"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c9909222db472fcc98d9e4e7192fa9d064dac63a3fa657df8c6daae86fb2604"
+checksum = "3ca96b05988aa057eda09a817a6e31915fabd7f476b513123aff08053cd193dd"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -145,9 +138,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.93.0"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68689b83e52e605ba48652882d3fccc2e2e136abf139eb64ae667888ba0d52f8"
+checksum = "e5112c0be9cc5da064e0620570d67852f11ce44f2e572a58ecf7f11df73978b8"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -155,9 +148,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.93.0"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98e4e99a353703475d5acb402b9c13482d41d8a4008b352559bd560afb90363"
+checksum = "bb6b03e0e03801c4b3fd8ce0758a94750c07a44e7944cc0ffbf0d3f2e7c79b00"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -166,9 +159,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.93.0"
+version = "0.95.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7a006ce1d8dd11df67567d8673e5920f3a56441812aed52a007ffce8f1b20e9"
+checksum = "48ed1b37d0972abe804cb5bf2b35f3a76a276ebbe148e3a726d8e31042790978"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -203,21 +196,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "getrandom"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
 name = "gimli"
-version = "0.26.2"
+version = "0.27.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
+checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
 dependencies = [
  "fallible-iterator",
  "indexmap",
@@ -229,6 +211,12 @@ name = "hashbrown"
 version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
 dependencies = [
  "ahash",
 ]
@@ -240,7 +228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
 ]
 
 [[package]]
@@ -285,12 +273,12 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "object"
-version = "0.29.0"
+version = "0.30.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
 dependencies = [
  "crc32fast",
- "hashbrown",
+ "hashbrown 0.13.2",
  "indexmap",
  "memchr",
 ]
@@ -303,9 +291,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
 
 [[package]]
 name = "regalloc2"
-version = "0.5.1"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c"
+checksum = "80535183cae11b149d618fbd3c37e38d7cda589d82d7769e196ca9a9042d7621"
 dependencies = [
  "fxhash",
  "log",
@@ -375,16 +363,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "6.0.0"
+version = "8.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec1fd0f0dd79e7cc0f55b102e320d7c77ab76cd272008a8fd98e25b5777e2636"
+checksum = "aecae978b13f7f67efb23bd827373ace4578f2137ec110bbf6a4a7cde4121bbd"
 dependencies = [
  "cfg-if",
  "libc",
@@ -415,9 +397,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-sys"
-version = "0.42.0"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
@@ -430,42 +421,42 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 5dadcaaec42..a2890f6ddf9 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -15,15 +15,15 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.93", features = ["unwind", "all-arch"] }
-cranelift-frontend = { version = "0.93" }
-cranelift-module = { version = "0.93" }
-cranelift-native = { version = "0.93" }
-cranelift-jit = { version = "0.93", optional = true }
-cranelift-object = { version = "0.93" }
+cranelift-codegen = { version = "0.95.1", features = ["unwind", "all-arch"] }
+cranelift-frontend = { version = "0.95.1" }
+cranelift-module = { version = "0.95.1" }
+cranelift-native = { version = "0.95.1" }
+cranelift-jit = { version = "0.95.1", optional = true }
+cranelift-object = { version = "0.95.1" }
 target-lexicon = "0.12.0"
-gimli = { version = "0.26.0", default-features = false, features = ["write"]}
-object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+gimli = { version = "0.27.2", default-features = false, features = ["write"]}
+object = { version = "0.30.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
 indexmap = "1.9.3"
 libloading = { version = "0.7.3", optional = true }
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index b87a9dc51e8..c5222982aa7 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -22,10 +22,9 @@ $ ./test.sh
 
 For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.rs`.
 
-Alternatively you can download a pre built version from [Github Actions]. It is listed in the artifacts section
-of workflow runs. Unfortunately due to GHA restrictions you need to be logged in to access it.
+Alternatively you can download a pre built version from the [releases] page.
 
-[Github Actions]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
+[releases]: https://github.com/bjorn3/rustc_codegen_cranelift/releases/tag/dev
 
 ## Usage
 
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index f2150762991..7ddf91ad01f 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.17.0"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
 dependencies = [
  "compiler_builtins",
  "gimli",
@@ -50,9 +50,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.89"
+version = "0.1.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fc9c2080d347a2c316518840ac9194644a9993dfa1e9778ef38979a339f5d8b"
+checksum = "571298a3cce7e2afbd3d61abb91a18667d5ab25993ec577a88ee8ac45f00cc3a"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -95,9 +95,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.26.2"
+version = "0.27.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
+checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -128,9 +128,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.140"
+version = "0.2.142"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
+checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -147,9 +147,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.5.4"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
 dependencies = [
  "adler",
  "compiler_builtins",
@@ -159,9 +159,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.29.0"
+version = "0.30.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
 dependencies = [
  "compiler_builtins",
  "memchr",
@@ -202,9 +202,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.21"
+version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs
index 8a53acdf7e3..e4ed9be23b7 100644
--- a/compiler/rustc_codegen_cranelift/build_system/mod.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs
@@ -43,7 +43,7 @@ pub(crate) enum SysrootKind {
     Llvm,
 }
 
-pub fn main() {
+pub(crate) fn main() {
     if env::var("RUST_BACKTRACE").is_err() {
         env::set_var("RUST_BACKTRACE", "1");
     }
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index 261948a6971..0c25b4aadfa 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -2,7 +2,6 @@ use super::build_sysroot;
 use super::config;
 use super::path::{Dirs, RelPath};
 use super::prepare::GitRepo;
-use super::rustc_info::get_host_triple;
 use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler};
 use super::SysrootKind;
 use std::env;
@@ -102,14 +101,14 @@ pub(crate) static RAND_REPO: GitRepo =
 pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
 
 pub(crate) static REGEX_REPO: GitRepo =
-    GitRepo::github("rust-lang", "regex", "a9b2e02352db92ce1f6e5b7ecd41b8bbffbe161a", "regex");
+    GitRepo::github("rust-lang", "regex", "32fed9429eafba0ae92a64b01796a0c5a75b88c8", "regex");
 
 pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
 
 pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
     "rust-lang",
     "portable-simd",
-    "9bd30e77b3a3c699af102ebb3df0f6110f8aa02e",
+    "ad8afa8c81273b3b49acbea38cd3bcf17a34cf2b",
     "portable-simd",
 );
 
@@ -186,7 +185,9 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
 
         if runner.is_native {
             let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
-            run_cmd.args(["--workspace", "--", "-q"]);
+            // regex-capi and regex-debug don't have any tests. Nor do they contain any code
+            // that is useful to test with cg_clif. Skip building them to reduce test time.
+            run_cmd.args(["-p", "regex", "-p", "regex-syntax", "--", "-q"]);
             spawn_and_wait(run_cmd);
         } else {
             eprintln!("Cross-Compiling: Not running tests");
@@ -228,8 +229,11 @@ pub(crate) fn run_tests(
             target_triple.clone(),
         );
 
-        let runner =
-            TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
+        let runner = TestRunner::new(
+            dirs.clone(),
+            target_compiler,
+            bootstrap_host_compiler.triple == target_triple,
+        );
 
         BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
         runner.run_testsuite(NO_SYSROOT_SUITE);
@@ -250,8 +254,11 @@ pub(crate) fn run_tests(
             target_triple.clone(),
         );
 
-        let runner =
-            TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
+        let runner = TestRunner::new(
+            dirs.clone(),
+            target_compiler,
+            bootstrap_host_compiler.triple == target_triple,
+        );
 
         if run_base_sysroot {
             runner.run_testsuite(BASE_SYSROOT_SUITE);
@@ -275,7 +282,7 @@ struct TestRunner {
 }
 
 impl TestRunner {
-    pub fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
+    fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
         if let Ok(rustflags) = env::var("RUSTFLAGS") {
             target_compiler.rustflags.push(' ');
             target_compiler.rustflags.push_str(&rustflags);
@@ -297,7 +304,7 @@ impl TestRunner {
         Self { is_native, jit_supported, dirs, target_compiler }
     }
 
-    pub fn run_testsuite(&self, tests: &[TestCase]) {
+    fn run_testsuite(&self, tests: &[TestCase]) {
         for TestCase { config, cmd } in tests {
             let (tag, testname) = config.split_once('.').unwrap();
             let tag = tag.to_uppercase();
@@ -382,7 +389,7 @@ impl TestRunner {
         spawn_and_wait(self.rustc_command(args));
     }
 
-    fn run_out_command<'a>(&self, name: &str, args: &[&str]) {
+    fn run_out_command(&self, name: &str, args: &[&str]) {
         let mut full_cmd = vec![];
 
         // Prepend the RUN_WRAPPER's
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
index 4ede2fe4efe..d994e2fbc0a 100644
--- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
@@ -18,7 +18,7 @@ extern "C" {
 }
 
 #[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
     core::intrinsics::abort();
 }
 
diff --git a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
index d270fec6b71..f7edfa960a2 100644
--- a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
+++ b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -3,8 +3,8 @@
 #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
 
 use std::{
-    ops::{Deref, CoerceUnsized, DispatchFromDyn},
     marker::Unsize,
+    ops::{CoerceUnsized, Deref, DispatchFromDyn},
 };
 
 struct Ptr<T: ?Sized>(Box<T>);
@@ -33,7 +33,6 @@ impl<T: ?Sized> Deref for Wrapper<T> {
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
 impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
 
-
 trait Trait {
     // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
     // without unsized_locals), but wrappers around `Self` currently are not.
diff --git a/compiler/rustc_codegen_cranelift/example/dst-field-align.rs b/compiler/rustc_codegen_cranelift/example/dst-field-align.rs
index 6c338e99912..22fc6ff33e3 100644
--- a/compiler/rustc_codegen_cranelift/example/dst-field-align.rs
+++ b/compiler/rustc_codegen_cranelift/example/dst-field-align.rs
@@ -2,7 +2,7 @@
 #![allow(dead_code)]
 struct Foo<T: ?Sized> {
     a: u16,
-    b: T
+    b: T,
 }
 
 trait Bar {
@@ -10,58 +10,57 @@ trait Bar {
 }
 
 impl Bar for usize {
-    fn get(&self) -> usize { *self }
+    fn get(&self) -> usize {
+        *self
+    }
 }
 
 struct Baz<T: ?Sized> {
-    a: T
+    a: T,
 }
 
 struct HasDrop<T: ?Sized> {
     ptr: Box<usize>,
-    data: T
+    data: T,
 }
 
 fn main() {
     // Test that zero-offset works properly
-    let b : Baz<usize> = Baz { a: 7 };
+    let b: Baz<usize> = Baz { a: 7 };
     assert_eq!(b.a.get(), 7);
-    let b : &Baz<dyn Bar> = &b;
+    let b: &Baz<dyn Bar> = &b;
     assert_eq!(b.a.get(), 7);
 
     // Test that the field is aligned properly
-    let f : Foo<usize> = Foo { a: 0, b: 11 };
+    let f: Foo<usize> = Foo { a: 0, b: 11 };
     assert_eq!(f.b.get(), 11);
-    let ptr1 : *const u8 = &f.b as *const _ as *const u8;
+    let ptr1: *const u8 = &f.b as *const _ as *const u8;
 
-    let f : &Foo<dyn Bar> = &f;
-    let ptr2 : *const u8 = &f.b as *const _ as *const u8;
+    let f: &Foo<dyn Bar> = &f;
+    let ptr2: *const u8 = &f.b as *const _ as *const u8;
     assert_eq!(f.b.get(), 11);
 
     // The pointers should be the same
     assert_eq!(ptr1, ptr2);
 
     // Test that nested DSTs work properly
-    let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
+    let f: Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 } };
     assert_eq!(f.b.b.get(), 17);
-    let f : &Foo<Foo<dyn Bar>> = &f;
+    let f: &Foo<Foo<dyn Bar>> = &f;
     assert_eq!(f.b.b.get(), 17);
 
     // Test that get the pointer via destructuring works
 
-    let f : Foo<usize> = Foo { a: 0, b: 11 };
-    let f : &Foo<dyn Bar> = &f;
+    let f: Foo<usize> = Foo { a: 0, b: 11 };
+    let f: &Foo<dyn Bar> = &f;
     let &Foo { a: _, b: ref bar } = f;
     assert_eq!(bar.get(), 11);
 
     // Make sure that drop flags don't screw things up
 
-    let d : HasDrop<Baz<[i32; 4]>> = HasDrop {
-        ptr: Box::new(0),
-        data: Baz { a: [1,2,3,4] }
-    };
-    assert_eq!([1,2,3,4], d.data.a);
+    let d: HasDrop<Baz<[i32; 4]>> = HasDrop { ptr: Box::new(0), data: Baz { a: [1, 2, 3, 4] } };
+    assert_eq!([1, 2, 3, 4], d.data.a);
 
-    let d : &HasDrop<Baz<[i32]>> = &d;
-    assert_eq!(&[1,2,3,4], &d.data.a);
+    let d: &HasDrop<Baz<[i32]>> = &d;
+    assert_eq!(&[1, 2, 3, 4], &d.data.a);
 }
diff --git a/compiler/rustc_codegen_cranelift/example/example.rs b/compiler/rustc_codegen_cranelift/example/example.rs
index d5c122bf681..885e55bc764 100644
--- a/compiler/rustc_codegen_cranelift/example/example.rs
+++ b/compiler/rustc_codegen_cranelift/example/example.rs
@@ -11,11 +11,7 @@ pub fn abc(a: u8) -> u8 {
 }
 
 pub fn bcd(b: bool, a: u8) -> u8 {
-    if b {
-        a * 2
-    } else {
-        a * 3
-    }
+    if b { a * 2 } else { a * 3 }
 }
 
 pub fn call() {
diff --git a/compiler/rustc_codegen_cranelift/example/issue-72793.rs b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
index b1bb9b8e1e7..166b0060043 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-72793.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
@@ -2,7 +2,9 @@
 
 #![feature(type_alias_impl_trait)]
 
-trait T { type Item; }
+trait T {
+    type Item;
+}
 
 type Alias<'a> = impl T<Item = &'a ()>;
 
diff --git a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
index 03910069633..6f39c5edcad 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
@@ -40,10 +40,7 @@ impl<T, const N: usize> ListImpl<T, N> {
     }
 }
 
-pub static A: ListImpl<u128, 3> = ListImpl {
-    len: 3,
-    data: [5, 6, 7],
-};
+pub static A: ListImpl<u128, 3> = ListImpl { len: 3, data: [5, 6, 7] };
 pub static A_REF: &'static List<u128> = A.as_list();
 pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list());
 
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 73b83b89f6d..ea97e9f060e 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -37,13 +37,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
 pub trait DispatchFromDyn<T> {}
 
 // &T -> &U
-impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
 // &mut T -> &mut U
-impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
 // *const T -> *const U
-impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
 // *mut T -> *mut U
-impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
 
 #[lang = "receiver"]
@@ -288,7 +288,6 @@ impl PartialEq for u32 {
     }
 }
 
-
 impl PartialEq for u64 {
     fn eq(&self, other: &u64) -> bool {
         (*self) == (*other)
@@ -361,7 +360,7 @@ impl<T: ?Sized> PartialEq for *const T {
     }
 }
 
-impl <T: PartialEq> PartialEq for Option<T> {
+impl<T: PartialEq> PartialEq for Option<T> {
     fn eq(&self, other: &Self) -> bool {
         match (self, other) {
             (Some(lhs), Some(rhs)) => *lhs == *rhs,
@@ -472,7 +471,20 @@ pub fn panic(_msg: &'static str) -> ! {
 #[track_caller]
 fn panic_bounds_check(index: usize, len: usize) -> ! {
     unsafe {
-        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        libc::printf(
+            "index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8,
+            len,
+            index,
+        );
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_cannot_unwind"]
+#[track_caller]
+fn panic_cannot_unwind() -> ! {
+    unsafe {
+        libc::puts("panic in a function that cannot unwind\n\0" as *const str as *const i8);
         intrinsics::abort();
     }
 }
@@ -599,7 +611,7 @@ pub mod libc {
     // functions. legacy_stdio_definitions.lib which provides the printf wrapper functions as normal
     // symbols to link against.
     #[cfg_attr(unix, link(name = "c"))]
-    #[cfg_attr(target_env="msvc", link(name="legacy_stdio_definitions"))]
+    #[cfg_attr(target_env = "msvc", link(name = "legacy_stdio_definitions"))]
     extern "C" {
         pub fn printf(format: *const i8, ...) -> i32;
     }
@@ -638,7 +650,7 @@ impl<T> Index<usize> for [T] {
     }
 }
 
-extern {
+extern "C" {
     type VaListImpl;
 }
 
@@ -648,23 +660,33 @@ pub struct VaList<'a>(&'a mut VaListImpl);
 
 #[rustc_builtin_macro]
 #[rustc_macro_transparency = "semitransparent"]
-pub macro stringify($($t:tt)*) { /* compiler built-in */ }
+pub macro stringify($($t:tt)*) {
+    /* compiler built-in */
+}
 
 #[rustc_builtin_macro]
 #[rustc_macro_transparency = "semitransparent"]
-pub macro file() { /* compiler built-in */ }
+pub macro file() {
+    /* compiler built-in */
+}
 
 #[rustc_builtin_macro]
 #[rustc_macro_transparency = "semitransparent"]
-pub macro line() { /* compiler built-in */ }
+pub macro line() {
+    /* compiler built-in */
+}
 
 #[rustc_builtin_macro]
 #[rustc_macro_transparency = "semitransparent"]
-pub macro cfg() { /* compiler built-in */ }
+pub macro cfg() {
+    /* compiler built-in */
+}
 
 #[rustc_builtin_macro]
 #[rustc_macro_transparency = "semitransparent"]
-pub macro global_asm() { /* compiler built-in */ }
+pub macro global_asm() {
+    /* compiler built-in */
+}
 
 pub static A_STATIC: u8 = 42;
 
@@ -676,7 +698,7 @@ struct PanicLocation {
 }
 
 #[no_mangle]
-#[cfg(not(windows))]
+#[cfg(not(all(windows, target_env = "gnu")))]
 pub fn get_tls() -> u8 {
     #[thread_local]
     static A: u8 = 42;
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 6ad3268e70d..5a55aa215bf 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -319,7 +319,7 @@ fn main() {
 
     from_decimal_string();
 
-    #[cfg(not(any(jit, windows)))]
+    #[cfg(all(not(jit), not(all(windows, target_env = "gnu"))))]
     test_tls();
 
     #[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "darwin")))]
@@ -524,6 +524,7 @@ pub enum E1 {
 // Computing the discriminant used to be done using the niche type (here `u8`,
 // from the `bool` field of `V1`), overflowing for variants with large enough
 // indices (`V3` and `V4`), causing them to be interpreted as other variants.
+#[rustfmt::skip]
 pub enum E2<X> {
     V1 { f: bool },
 
diff --git a/compiler/rustc_codegen_cranelift/example/mod_bench.rs b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
index e3e8a3c2d6a..f15e48acc41 100644
--- a/compiler/rustc_codegen_cranelift/example/mod_bench.rs
+++ b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
@@ -3,15 +3,15 @@
 
 #[cfg_attr(unix, link(name = "c"))]
 #[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
-extern {}
+extern "C" {}
 
 #[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
     core::intrinsics::abort();
 }
 
-#[lang="eh_personality"]
-fn eh_personality(){}
+#[lang = "eh_personality"]
+fn eh_personality() {}
 
 // Required for rustc_codegen_llvm
 #[no_mangle]
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index e34b35d5c4a..ab4045d11a6 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -1,4 +1,4 @@
-#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
+#![feature(core_intrinsics, generators, generator_trait, is_sorted, repr_simd)]
 
 #[cfg(target_arch = "x86_64")]
 use std::arch::x86_64::*;
@@ -56,7 +56,10 @@ fn main() {
 
     assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
     assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
-    assert_eq!(core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128), 170141183460469231731687303715884105727i128);
+    assert_eq!(
+        core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128),
+        170141183460469231731687303715884105727i128
+    );
 
     std::hint::black_box(std::hint::black_box(7571400400375753350092698930310845914i128) * 10);
     assert!(0i128.checked_div(2i128).is_some());
@@ -113,7 +116,9 @@ fn main() {
 
     Box::pin(move |mut _task_context| {
         yield ();
-    }).as_mut().resume(0);
+    })
+    .as_mut()
+    .resume(0);
 
     #[derive(Copy, Clone)]
     enum Nums {
@@ -148,12 +153,20 @@ fn main() {
 
         enum Never {}
     }
+
+    foo(I64X2(0, 0));
 }
 
 fn panic(_: u128) {
     panic!();
 }
 
+#[repr(simd)]
+struct I64X2(i64, i64);
+
+#[allow(improper_ctypes_definitions)]
+extern "C" fn foo(_a: I64X2) {}
+
 #[cfg(target_arch = "x86_64")]
 #[target_feature(enable = "sse2")]
 unsafe fn test_simd() {
@@ -168,7 +181,10 @@ unsafe fn test_simd() {
     let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x);
     assert_eq!((zero0, zero1), (0, 0));
     assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
-    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
+    assert_eq!(
+        std::mem::transmute::<_, [u16; 8]>(cmp_eq),
+        [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]
+    );
     assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
 
     test_mm_slli_si128();
@@ -182,6 +198,7 @@ unsafe fn test_simd() {
     test_mm_extract_epi8();
     test_mm_insert_epi16();
 
+    #[rustfmt::skip]
     let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
     assert_eq!(mask1, 1);
 }
@@ -343,7 +360,7 @@ fn test_checked_mul() {
 #[derive(PartialEq)]
 enum LoopState {
     Continue(()),
-    Break(())
+    Break(()),
 }
 
 pub enum Instruction {
diff --git a/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs b/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs
index 2cb84786f56..3c878916663 100644
--- a/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs
+++ b/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs
@@ -19,7 +19,9 @@ macro_rules! n {
 // This macro has an unused variable so that it can be repeated base on the
 // number of times a repeated variable (`$e` in `z`) occurs.
 macro_rules! zed {
-    ($e:expr) => { Z }
+    ($e:expr) => {
+        Z
+    };
 }
 
 macro_rules! z {
@@ -32,12 +34,14 @@ macro_rules! z {
 macro_rules! compare_evaluation {
     ($e:expr, $t:ty $(,)?) => {{
         const CONST_EVAL: $t = $e;
-        const fn const_eval() -> $t { $e }
+        const fn const_eval() -> $t {
+            $e
+        }
         static CONST_EVAL2: $t = const_eval();
         let runtime_eval = $e;
         assert_eq!(CONST_EVAL, runtime_eval);
         assert_eq!(CONST_EVAL2, runtime_eval);
-    }}
+    }};
 }
 
 // Repeat `$test`, substituting the given macro variables with the given
@@ -65,6 +69,7 @@ macro_rules! repeat {
     }
 }
 
+#[rustfmt::skip]
 fn main() {
     repeat! {
         ($arr $Ty); n, N; z, Z:
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 2236a6ca155..59ad80c3207 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-03-15"
+channel = "nightly-2023-04-29"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
index 939a1f1ca59..e2db7d03a9d 100644
--- a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
@@ -64,7 +64,7 @@ fn main() {
     };
 
     #[cfg(unix)]
-    Command::new("cargo").args(args).exec();
+    panic!("Failed to spawn cargo: {}", Command::new("cargo").args(args).exec());
 
     #[cfg(not(unix))]
     std::process::exit(
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
index b9bba7f2e08..ab496a4a684 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
@@ -15,22 +15,24 @@ fn main() {
         env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
     );
 
-    let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+    let passed_args = std::env::args_os().skip(1).collect::<Vec<_>>();
+    let mut args = vec![];
     args.push(OsString::from("-Cpanic=abort"));
     args.push(OsString::from("-Zpanic-abort-tests"));
     let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
     codegen_backend_arg.push(cg_clif_dylib_path);
     args.push(codegen_backend_arg);
-    if !args.contains(&OsString::from("--sysroot")) {
+    if !passed_args.contains(&OsString::from("--sysroot")) {
         args.push(OsString::from("--sysroot"));
         args.push(OsString::from(sysroot.to_str().unwrap()));
     }
+    args.extend(passed_args);
 
     // Ensure that the right toolchain is used
     env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
 
     #[cfg(unix)]
-    Command::new("rustc").args(args).exec();
+    panic!("Failed to spawn rustc: {}", Command::new("rustc").args(args).exec());
 
     #[cfg(not(unix))]
     std::process::exit(
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
index 167631eaf7e..545844446c5 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
@@ -15,22 +15,24 @@ fn main() {
         env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
     );
 
-    let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+    let passed_args = std::env::args_os().skip(1).collect::<Vec<_>>();
+    let mut args = vec![];
     args.push(OsString::from("-Cpanic=abort"));
     args.push(OsString::from("-Zpanic-abort-tests"));
     let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
     codegen_backend_arg.push(cg_clif_dylib_path);
     args.push(codegen_backend_arg);
-    if !args.contains(&OsString::from("--sysroot")) {
+    if !passed_args.contains(&OsString::from("--sysroot")) {
         args.push(OsString::from("--sysroot"));
         args.push(OsString::from(sysroot.to_str().unwrap()));
     }
+    args.extend(passed_args);
 
     // Ensure that the right toolchain is used
     env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
 
     #[cfg(unix)]
-    Command::new("rustdoc").args(args).exec();
+    panic!("Failed to spawn rustdoc: {}", Command::new("rustdoc").args(args).exec());
 
     #[cfg(not(unix))]
     std::process::exit(
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 20dcb4cf34d..1329d3ea076 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -10,7 +10,8 @@ pushd rust
 
 command -v rg >/dev/null 2>&1 || cargo install ripgrep
 
-rm -r tests/ui/{extern/,unsized-locals/,lto/,linkage*} || true
+# FIXME add needs-asm-support to all tests in tests/ui/asm
+rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
 for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{codegen-units,ui,incremental}); do
   rm $test
 done
@@ -27,13 +28,24 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
 # ================
 
 # requires stack unwinding
+# FIXME add needs-unwind to these tests
 rm tests/incremental/change_crate_dep_kind.rs
 rm tests/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101)
+rm -r tests/run-make/c-unwind-abi-catch-lib-panic
+rm -r tests/run-make/c-unwind-abi-catch-panic
+rm -r tests/run-make/debug-assertions
+rm -r tests/run-make/foreign-double-unwind
+rm -r tests/run-make/foreign-exceptions
+rm -r tests/run-make/foreign-rust-exceptions
+rm -r tests/run-make/libtest-json
+rm -r tests/run-make/static-unwinding
 
 # requires compiling with -Cpanic=unwind
 rm -r tests/ui/macros/rfc-2011-nicer-assert-messages/
 rm -r tests/run-make/test-benches
 rm tests/ui/test-attrs/test-type.rs
+rm -r tests/run-make/const_fn_mir
+rm -r tests/run-make/intrinsic-unreachable
 
 # vendor intrinsics
 rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected
@@ -49,6 +61,7 @@ rm tests/incremental/hashes/statics.rs # same
 # variadic arguments
 rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs
 rm tests/ui/abi/variadic-ffi.rs # requires callee side vararg support
+rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg support
 
 # unsized locals
 rm -r tests/run-pass-valgrind/unsized-locals
@@ -59,6 +72,19 @@ rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
 rm tests/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
 rm -r tests/run-make/emit-named-files # requires full --emit support
 rm -r tests/run-make/repr128-dwarf # debuginfo test
+rm -r tests/run-make/split-debuginfo # same
+rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported
+rm -r tests/run-make/target-specs # i686 not supported by Cranelift
+rm -r tests/run-make/mismatching-target-triples # same
+rm -r tests/run-make/use-extern-for-plugins # same
+
+# requires LTO
+rm -r tests/run-make/cdylib
+rm -r tests/run-make/issue-14500
+rm -r tests/run-make/issue-64153
+rm -r tests/run-make/codegen-options-parsing
+rm -r tests/run-make/lto-*
+rm -r tests/run-make/reproducible-build-2
 
 # optimization tests
 # ==================
@@ -70,7 +96,14 @@ rm -r tests/run-make/fmt-write-bloat/ # tests an optimization
 # backend specific tests
 # ======================
 rm tests/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM
+rm -r tests/run-make/cross-lang-lto # same
+rm -r tests/run-make/issue-7349 # same
+rm -r tests/run-make/sepcomp-inlining # same
+rm -r tests/run-make/sepcomp-separate # same
+rm -r tests/run-make/sepcomp-cci-copies # same
+rm -r tests/run-make/volatile-intrinsics # same
 rm tests/ui/abi/stack-protector.rs # requires stack protector support
+rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes
 
 # giving different but possibly correct results
 # =============================================
@@ -95,13 +128,12 @@ rm tests/ui/proc-macro/no-missing-docs.rs # same
 rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs # same
 rm tests/ui/proc-macro/allowed-signatures.rs # same
 
+# rustdoc-clif passes extra args, suppressing the help message when no args are passed
+rm -r tests/run-make/issue-88756-default-output
+
 # doesn't work due to the way the rustc test suite is invoked.
 # should work when using ./x.py test the way it is intended
 # ============================================================
-rm -r tests/run-make/emit-shared-files # requires the rustdoc executable in dist/bin/
-rm -r tests/run-make/unstable-flag-required # same
-rm -r tests/run-make/rustdoc-* # same
-rm -r tests/run-make/issue-88756-default-output # same
 rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
 rm -r tests/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to be elsewhere
 
@@ -112,17 +144,41 @@ rm tests/incremental/spike-neg2.rs # same
 
 rm tests/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 
-rm tests/ui/simd/intrinsic/generic-as.rs # crash when accessing vector type field (#1318)
 rm tests/ui/simd/simd-bitmask.rs # crash
 
+rm -r tests/run-make/issue-51671 # wrong filename given in case of --emit=obj
+rm -r tests/run-make/issue-30063 # same
+rm -r tests/run-make/multiple-emits # same
+rm -r tests/run-make/output-type-permutations # same
+rm -r tests/run-make/used # same
+
 # bugs in the test suite
 # ======================
 rm tests/ui/backtrace.rs # TODO warning
-rm tests/ui/simple_global_asm.rs # TODO add needs-asm-support
 rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
 
 rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
 
+cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist
+
+# prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by
+# rustdoc-clif
+cat <<EOF | git apply -
+diff --git a/tests/run-make/tools.mk b/tests/run-make/tools.mk
+index ea06b620c4c..b969d0009c6 100644
+--- a/tests/run-make/tools.mk
++++ b/tests/run-make/tools.mk
+@@ -9,7 +9,7 @@ RUSTC_ORIGINAL := \$(RUSTC)
+ BARE_RUSTC := \$(HOST_RPATH_ENV) '\$(RUSTC)'
+ BARE_RUSTDOC := \$(HOST_RPATH_ENV) '\$(RUSTDOC)'
+ RUSTC := \$(BARE_RUSTC) --out-dir \$(TMPDIR) -L \$(TMPDIR) \$(RUSTFLAGS)
+-RUSTDOC := \$(BARE_RUSTDOC) -L \$(TARGET_RPATH_DIR)
++RUSTDOC := \$(BARE_RUSTDOC)
+ ifdef RUSTC_LINKER
+ RUSTC := \$(RUSTC) -Clinker='\$(RUSTC_LINKER)'
+ RUSTDOC := \$(RUSTDOC) -Clinker='\$(RUSTC_LINKER)'
+EOF
+
 echo "[TEST] rustc test suite"
-RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 tests/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
+COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
 popd
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index abf63e33c35..364503fd363 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -6,8 +6,6 @@ use std::borrow::Cow;
 use rustc_middle::mir;
 use rustc_target::abi::call::PassMode;
 
-use cranelift_codegen::entity::EntityRef;
-
 use crate::prelude::*;
 
 pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, '_>) {
@@ -91,35 +89,7 @@ pub(super) fn add_local_place_comments<'tcx>(
         largest_niche: _,
     } = layout.0.0;
 
-    let (kind, extra) = match *place.inner() {
-        CPlaceInner::Var(place_local, var) => {
-            assert_eq!(local, place_local);
-            ("ssa", Cow::Owned(format!(",var={}", var.index())))
-        }
-        CPlaceInner::VarPair(place_local, var1, var2) => {
-            assert_eq!(local, place_local);
-            ("ssa", Cow::Owned(format!("var=({}, {})", var1.index(), var2.index())))
-        }
-        CPlaceInner::VarLane(_local, _var, _lane) => unreachable!(),
-        CPlaceInner::Addr(ptr, meta) => {
-            let meta = if let Some(meta) = meta {
-                Cow::Owned(format!("meta={}", meta))
-            } else {
-                Cow::Borrowed("")
-            };
-            match ptr.debug_base_and_offset() {
-                (crate::pointer::PointerBase::Addr(addr), offset) => {
-                    ("reuse", format!("storage={}{}{}", addr, offset, meta).into())
-                }
-                (crate::pointer::PointerBase::Stack(stack_slot), offset) => {
-                    ("stack", format!("storage={}{}{}", stack_slot, offset, meta).into())
-                }
-                (crate::pointer::PointerBase::Dangling(align), offset) => {
-                    ("zst", format!("align={},offset={}", align.bytes(), offset).into())
-                }
-            }
-        }
-    };
+    let (kind, extra) = place.debug_comment();
 
     fx.add_global_comment(format!(
         "{:<5} {:5} {:30} {:4}b {}, {}{}{}",
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 0b4d4ecf2e4..e533afcfaa9 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -605,9 +605,9 @@ pub(crate) fn codegen_drop<'tcx>(
                 //                | ...   |
                 //                \-------/
                 //
-                let (ptr, vtable) = drop_place.to_ptr_maybe_unsized();
+                let (ptr, vtable) = drop_place.to_ptr_unsized();
                 let ptr = ptr.get_addr(fx);
-                let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
+                let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
 
                 // FIXME(eddyb) perhaps move some of this logic into
                 // `Instance::resolve_drop_in_place`?
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index e5ad31eb948..d847e524f8c 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -84,7 +84,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                     attrs
                 )],
                 Abi::Vector { .. } => {
-                    let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
+                    let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout);
                     smallvec![AbiParam::new(vector_ty)]
                 }
                 _ => unreachable!("{:?}", self.layout.abi),
@@ -135,7 +135,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                     (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))])
                 }
                 Abi::Vector { .. } => {
-                    let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
+                    let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout);
                     (None, vec![AbiParam::new(vector_ty)])
                 }
                 _ => unreachable!("{:?}", self.layout.abi),
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index bd055216e36..14e54d5ee38 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -63,11 +63,11 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
     let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
         PassMode::Ignore => (None, None),
         PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
-            if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) {
+            if let Some(ret_ptr) = ret_place.try_to_ptr() {
                 // This is an optimization to prevent unnecessary copies of the return value when
                 // the return place is already a memory place as opposed to a register.
                 // This match arm can be safely removed.
-                (None, Some(ret_place.to_ptr().get_addr(fx)))
+                (None, Some(ret_ptr.get_addr(fx)))
             } else {
                 let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout);
                 (Some(place), Some(place.to_ptr().get_addr(fx)))
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index c181c73e4be..a259a4f30b2 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -141,16 +141,6 @@ pub(crate) fn compile_fn(
     context.clear();
     context.func = codegened_func.func;
 
-    // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
-    // instruction, which doesn't have an encoding.
-    context.compute_cfg();
-    context.compute_domtree();
-    context.eliminate_unreachable_code(module.isa()).unwrap();
-    context.dce(module.isa()).unwrap();
-    // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
-    // invalidate it when it would change.
-    context.domtree.clear();
-
     #[cfg(any())] // This is never true
     let _clif_guard = {
         use std::fmt::Write;
@@ -182,27 +172,6 @@ pub(crate) fn compile_fn(
     cx.profiler.generic_activity("define function").run(|| {
         context.want_disasm = cx.should_write_ir;
         module.define_function(codegened_func.func_id, context).unwrap();
-
-        if cx.profiler.enabled() {
-            let mut recording_args = false;
-            cx.profiler
-                .generic_activity_with_arg_recorder(
-                    "define function (clif pass timings)",
-                    |recorder| {
-                        let pass_times = cranelift_codegen::timing::take_current();
-                        // Replace newlines with | as measureme doesn't allow control characters like
-                        // newlines inside strings.
-                        recorder.record_arg(format!("{}", pass_times).replace('\n', " | "));
-                        recording_args = true;
-                    },
-                )
-                .run(|| {
-                    if recording_args {
-                        // Wait a tiny bit to ensure chrome's profiler doesn't hide the event
-                        std::thread::sleep(std::time::Duration::from_nanos(2))
-                    }
-                });
-        }
     });
 
     if cx.should_write_ir {
@@ -216,7 +185,7 @@ pub(crate) fn compile_fn(
             &clif_comments,
         );
 
-        if let Some(disasm) = &context.compiled_code().unwrap().disasm {
+        if let Some(disasm) = &context.compiled_code().unwrap().vcode {
             crate::pretty_clif::write_ir_file(
                 &cx.output_filenames,
                 &format!("{}.vcode", codegened_func.symbol_name),
@@ -524,13 +493,14 @@ fn codegen_stmt<'tcx>(
 
     fx.set_debug_loc(stmt.source_info);
 
-    #[cfg(any())] // This is never true
     match &stmt.kind {
         StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
         _ => {
             if fx.clif_comments.enabled() {
                 let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap();
-                fx.add_comment(inst, format!("{:?}", stmt));
+                with_no_trimmed_paths!({
+                    fx.add_comment(inst, format!("{:?}", stmt));
+                });
             }
         }
     }
@@ -715,11 +685,11 @@ fn codegen_stmt<'tcx>(
                 }
                 Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => {
                     let operand = codegen_operand(fx, operand);
-                    operand.unsize_value(fx, lval);
+                    crate::unsize::coerce_unsized_into(fx, operand, lval);
                 }
                 Rvalue::Cast(CastKind::DynStar, ref operand, _) => {
                     let operand = codegen_operand(fx, operand);
-                    operand.coerce_dyn_star(fx, lval);
+                    crate::unsize::coerce_dyn_star(fx, operand, lval);
                 }
                 Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
                     let operand = codegen_operand(fx, operand);
@@ -791,7 +761,10 @@ fn codegen_stmt<'tcx>(
                             layout.offset_of_subfield(fx, fields.iter().map(|f| f.index())).bytes()
                         }
                     };
-                    let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into());
+                    let val = CValue::by_val(
+                        fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()),
+                        fx.layout_of(fx.tcx.types.usize),
+                    );
                     lval.write_cvalue(fx, val);
                 }
                 Rvalue::Aggregate(ref kind, ref operands) => {
@@ -866,9 +839,7 @@ fn codegen_array_len<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx
             let len = fx.monomorphize(len).eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
             fx.bcx.ins().iconst(fx.pointer_type, len)
         }
-        ty::Slice(_elem_ty) => {
-            place.to_ptr_maybe_unsized().1.expect("Length metadata for slice place")
-        }
+        ty::Slice(_elem_ty) => place.to_ptr_unsized().1,
         _ => bug!("Rvalue::Len({:?})", place),
     }
 }
@@ -922,8 +893,7 @@ pub(crate) fn codegen_place<'tcx>(
                     ty::Slice(elem_ty) => {
                         assert!(from_end, "slice subslices should be `from_end`");
                         let elem_layout = fx.layout_of(*elem_ty);
-                        let (ptr, len) = cplace.to_ptr_maybe_unsized();
-                        let len = len.unwrap();
+                        let (ptr, len) = cplace.to_ptr_unsized();
                         cplace = CPlace::for_ptr_with_extra(
                             ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
                             fx.bcx.ins().iadd_imm(len, -(from as i64 + to as i64)),
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 032d1151041..6bf3a866ba4 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -103,7 +103,7 @@ pub(crate) fn clif_int_or_float_cast(
                     vec![AbiParam::new(types::I64X2)],
                     &[from],
                 )[0];
-                // FIXME use bitcast instead of store to get from i64x2 to i128
+                // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
                 let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
                     kind: StackSlotKind::ExplicitSlot,
                     size: 16,
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index f674ce776a6..f751d8c179d 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -7,7 +7,6 @@ use crate::prelude::*;
 pub(crate) fn maybe_codegen<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     bin_op: BinOp,
-    checked: bool,
     lhs: CValue<'tcx>,
     rhs: CValue<'tcx>,
 ) -> Option<CValue<'tcx>> {
@@ -22,69 +21,23 @@ pub(crate) fn maybe_codegen<'tcx>(
     let is_signed = type_sign(lhs.layout().ty);
 
     match bin_op {
-        BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => {
-            assert!(!checked);
-            None
-        }
-        BinOp::Add | BinOp::Sub if !checked => None,
-        BinOp::Mul if !checked || is_signed => {
-            if !checked {
-                let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
-                let ret_val = fx.lib_call(
-                    "__multi3",
-                    vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
-                    vec![AbiParam::new(types::I128)],
-                    &args,
-                )[0];
-                Some(CValue::by_val(
-                    ret_val,
-                    fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }),
-                ))
-            } else {
-                let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
-                let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
-                let lhs = lhs.load_scalar(fx);
-                let rhs = rhs.load_scalar(fx);
-                let oflow_ptr = oflow.to_ptr().get_addr(fx);
-                let res = fx.lib_call_unadjusted(
-                    "__muloti4",
-                    vec![
-                        AbiParam::new(types::I128),
-                        AbiParam::new(types::I128),
-                        AbiParam::new(fx.pointer_type),
-                    ],
-                    vec![AbiParam::new(types::I128)],
-                    &[lhs, rhs, oflow_ptr],
-                )[0];
-                let oflow = oflow.to_cvalue(fx).load_scalar(fx);
-                let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
-                Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
-            }
-        }
-        BinOp::Add | BinOp::Sub | BinOp::Mul => {
-            assert!(checked);
-            let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
-            let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
-            let param_types = vec![
-                AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
-                AbiParam::new(types::I128),
-                AbiParam::new(types::I128),
-            ];
-            let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
-            let name = match (bin_op, is_signed) {
-                (BinOp::Add, false) => "__rust_u128_addo",
-                (BinOp::Add, true) => "__rust_i128_addo",
-                (BinOp::Sub, false) => "__rust_u128_subo",
-                (BinOp::Sub, true) => "__rust_i128_subo",
-                (BinOp::Mul, false) => "__rust_u128_mulo",
-                _ => unreachable!(),
-            };
-            fx.lib_call(name, param_types, vec![], &args);
-            Some(out_place.to_cvalue(fx))
+        BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => None,
+        BinOp::Add | BinOp::Sub => None,
+        BinOp::Mul => {
+            let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
+            let ret_val = fx.lib_call(
+                "__multi3",
+                vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
+                vec![AbiParam::new(types::I128)],
+                &args,
+            )[0];
+            Some(CValue::by_val(
+                ret_val,
+                fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }),
+            ))
         }
         BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
         BinOp::Div | BinOp::Rem => {
-            assert!(!checked);
             let name = match (bin_op, is_signed) {
                 (BinOp::Div, false) => "__udivti3",
                 (BinOp::Div, true) => "__divti3",
@@ -100,7 +53,7 @@ pub(crate) fn maybe_codegen<'tcx>(
                     vec![AbiParam::new(types::I64X2)],
                     &args,
                 )[0];
-                // FIXME use bitcast instead of store to get from i64x2 to i128
+                // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
                 let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
                 ret_place.to_ptr().store(fx, ret, MemFlags::trusted());
                 Some(ret_place.to_cvalue(fx))
@@ -115,10 +68,72 @@ pub(crate) fn maybe_codegen<'tcx>(
                 Some(CValue::by_val(ret_val, lhs.layout()))
             }
         }
-        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => {
-            assert!(!checked);
-            None
-        }
+        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None,
         BinOp::Shl | BinOp::Shr => None,
     }
 }
+
+pub(crate) fn maybe_codegen_checked<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    bin_op: BinOp,
+    lhs: CValue<'tcx>,
+    rhs: CValue<'tcx>,
+) -> Option<CValue<'tcx>> {
+    if lhs.layout().ty != fx.tcx.types.u128
+        && lhs.layout().ty != fx.tcx.types.i128
+        && rhs.layout().ty != fx.tcx.types.u128
+        && rhs.layout().ty != fx.tcx.types.i128
+    {
+        return None;
+    }
+
+    let is_signed = type_sign(lhs.layout().ty);
+
+    match bin_op {
+        BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
+        BinOp::Mul if is_signed => {
+            let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
+            let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
+            let lhs = lhs.load_scalar(fx);
+            let rhs = rhs.load_scalar(fx);
+            let oflow_ptr = oflow.to_ptr().get_addr(fx);
+            let res = fx.lib_call_unadjusted(
+                "__muloti4",
+                vec![
+                    AbiParam::new(types::I128),
+                    AbiParam::new(types::I128),
+                    AbiParam::new(fx.pointer_type),
+                ],
+                vec![AbiParam::new(types::I128)],
+                &[lhs, rhs, oflow_ptr],
+            )[0];
+            let oflow = oflow.to_cvalue(fx).load_scalar(fx);
+            let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
+            Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
+        }
+        BinOp::Add | BinOp::Sub | BinOp::Mul => {
+            let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
+            let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
+            let param_types = vec![
+                AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
+                AbiParam::new(types::I128),
+                AbiParam::new(types::I128),
+            ];
+            let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
+            let name = match (bin_op, is_signed) {
+                (BinOp::Add, false) => "__rust_u128_addo",
+                (BinOp::Add, true) => "__rust_i128_addo",
+                (BinOp::Sub, false) => "__rust_u128_subo",
+                (BinOp::Sub, true) => "__rust_i128_subo",
+                (BinOp::Mul, false) => "__rust_u128_mulo",
+                _ => unreachable!(),
+            };
+            fx.lib_call(name, param_types, vec![], &args);
+            Some(out_place.to_cvalue(fx))
+        }
+        BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
+        BinOp::Div | BinOp::Rem => unreachable!(),
+        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
+        BinOp::Shl | BinOp::Shr => unreachable!(),
+    }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 528b35283d7..30f4cf4473c 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -72,19 +72,6 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ
                 pointer_ty(tcx)
             }
         }
-        ty::Adt(adt_def, _) if adt_def.repr().simd() => {
-            let (element, count) = match &tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().abi
-            {
-                Abi::Vector { element, count } => (*element, *count),
-                _ => unreachable!(),
-            };
-
-            match scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()) {
-                // Cranelift currently only implements icmp for 128bit vectors.
-                Some(vector_ty) if vector_ty.bits() == 128 => vector_ty,
-                _ => return None,
-            }
-        }
         ty::Param(_) => bug!("ty param {:?}", ty),
         _ => return None,
     })
@@ -96,12 +83,7 @@ fn clif_pair_type_from_ty<'tcx>(
 ) -> Option<(types::Type, types::Type)> {
     Some(match ty.kind() {
         ty::Tuple(types) if types.len() == 2 => {
-            let a = clif_type_from_ty(tcx, types[0])?;
-            let b = clif_type_from_ty(tcx, types[1])?;
-            if a.is_vector() || b.is_vector() {
-                return None;
-            }
-            (a, b)
+            (clif_type_from_ty(tcx, types[0])?, clif_type_from_ty(tcx, types[1])?)
         }
         ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
             if has_ptr_meta(tcx, *pointee_ty) {
@@ -431,7 +413,11 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
 
     // Note: must be kept in sync with get_caller_location from cg_ssa
     pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> {
-        let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| {
+        let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, mut span: Span| {
+            // Remove `Inlined` marks as they pollute `expansion_cause`.
+            while span.is_inlined() {
+                span.remove_mark();
+            }
             let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
             let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo());
             let const_loc = fx.tcx.const_caller_location((
diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
index 203219a8a75..54df04f8c2c 100644
--- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
+++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
@@ -25,8 +25,18 @@ impl ConcurrencyLimiter {
             .clone()
             .into_helper_thread(move |token| {
                 let mut state = state_helper.lock().unwrap();
-                state.add_new_token(token.unwrap());
-                available_token_condvar_helper.notify_one();
+                match token {
+                    Ok(token) => {
+                        state.add_new_token(token);
+                        available_token_condvar_helper.notify_one();
+                    }
+                    Err(err) => {
+                        state.poison(format!("failed to acquire jobserver token: {}", err));
+                        // Notify all threads waiting for a token to give them a chance to
+                        // gracefully exit.
+                        available_token_condvar_helper.notify_all();
+                    }
+                }
             })
             .unwrap();
         ConcurrencyLimiter {
@@ -37,16 +47,31 @@ impl ConcurrencyLimiter {
         }
     }
 
-    pub(super) fn acquire(&mut self) -> ConcurrencyLimiterToken {
+    pub(super) fn acquire(&mut self, handler: &rustc_errors::Handler) -> ConcurrencyLimiterToken {
         let mut state = self.state.lock().unwrap();
         loop {
             state.assert_invariants();
 
-            if state.try_start_job() {
-                return ConcurrencyLimiterToken {
-                    state: self.state.clone(),
-                    available_token_condvar: self.available_token_condvar.clone(),
-                };
+            match state.try_start_job() {
+                Ok(true) => {
+                    return ConcurrencyLimiterToken {
+                        state: self.state.clone(),
+                        available_token_condvar: self.available_token_condvar.clone(),
+                    };
+                }
+                Ok(false) => {}
+                Err(err) => {
+                    // An error happened when acquiring the token. Raise it as fatal error.
+                    // Make sure to drop the mutex guard first to prevent poisoning the mutex.
+                    drop(state);
+                    if let Some(err) = err {
+                        handler.fatal(&err).raise();
+                    } else {
+                        // The error was already emitted, but compilation continued. Raise a silent
+                        // fatal error.
+                        rustc_errors::FatalError.raise();
+                    }
+                }
             }
 
             self.helper_thread.as_mut().unwrap().request_token();
@@ -100,13 +125,22 @@ mod state {
         pending_jobs: usize,
         active_jobs: usize,
 
+        poisoned: bool,
+        stored_error: Option<String>,
+
         // None is used to represent the implicit token, Some to represent explicit tokens
         tokens: Vec<Option<Acquired>>,
     }
 
     impl ConcurrencyLimiterState {
         pub(super) fn new(pending_jobs: usize) -> Self {
-            ConcurrencyLimiterState { pending_jobs, active_jobs: 0, tokens: vec![None] }
+            ConcurrencyLimiterState {
+                pending_jobs,
+                active_jobs: 0,
+                poisoned: false,
+                stored_error: None,
+                tokens: vec![None],
+            }
         }
 
         pub(super) fn assert_invariants(&self) {
@@ -127,14 +161,18 @@ mod state {
             self.drop_excess_capacity();
         }
 
-        pub(super) fn try_start_job(&mut self) -> bool {
+        pub(super) fn try_start_job(&mut self) -> Result<bool, Option<String>> {
+            if self.poisoned {
+                return Err(self.stored_error.take());
+            }
+
             if self.active_jobs < self.tokens.len() {
                 // Using existing token
                 self.job_started();
-                return true;
+                return Ok(true);
             }
 
-            false
+            Ok(false)
         }
 
         pub(super) fn job_started(&mut self) {
@@ -161,6 +199,11 @@ mod state {
             self.assert_invariants();
         }
 
+        pub(super) fn poison(&mut self, error: String) {
+            self.poisoned = true;
+            self.stored_error = Some(error);
+        }
+
         fn drop_excess_capacity(&mut self) {
             self.assert_invariants();
 
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index aacf37bb5b7..bf5d29c16f6 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -159,6 +159,8 @@ pub(crate) fn codegen_const_value<'tcx>(
                         _ => unreachable!(),
                     };
 
+                    // FIXME avoid this extra copy to the stack and directly write to the final
+                    // destination
                     let place = CPlace::new_stack_slot(fx, layout);
                     place.to_ptr().store(fx, val, MemFlags::trusted());
                     place.to_cvalue(fx)
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 3e2e2af9688..0e6c6ad95aa 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -324,6 +324,10 @@ fn module_codegen(
     OngoingModuleCodegen::Async(std::thread::spawn(move || {
         cx.profiler.clone().verbose_generic_activity_with_arg("compile functions", &*cgu_name).run(
             || {
+                cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
+                    cx.profiler.clone(),
+                )));
+
                 let mut cached_context = Context::new();
                 for codegened_func in codegened_functions {
                     crate::base::compile_fn(
@@ -407,7 +411,7 @@ pub(crate) fn run_aot(
                                     backend_config.clone(),
                                     global_asm_config.clone(),
                                     cgu.name(),
-                                    concurrency_limiter.acquire(),
+                                    concurrency_limiter.acquire(tcx.sess.diagnostic()),
                                 ),
                                 module_codegen,
                                 Some(rustc_middle::dep_graph::hash_result),
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index f6a48e3257b..3118105a4e2 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -224,6 +224,10 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
     module: &mut dyn Module,
     instance: Instance<'tcx>,
 ) {
+    cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
+        cx.profiler.clone(),
+    )));
+
     tcx.prof.generic_activity("codegen and compile fn").run(|| {
         let _inst_guard =
             crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
index d09d3a52975..5c52c9c18ad 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -4,6 +4,7 @@
 //! [`codegen_fn`]: crate::base::codegen_fn
 //! [`codegen_static`]: crate::constant::codegen_static
 
+use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
 
 use crate::prelude::*;
@@ -39,3 +40,31 @@ fn predefine_mono_items<'tcx>(
         }
     });
 }
+
+struct MeasuremeProfiler(SelfProfilerRef);
+
+struct TimingGuard {
+    profiler: std::mem::ManuallyDrop<SelfProfilerRef>,
+    inner: Option<rustc_data_structures::profiling::TimingGuard<'static>>,
+}
+
+impl Drop for TimingGuard {
+    fn drop(&mut self) {
+        self.inner.take();
+        unsafe {
+            std::mem::ManuallyDrop::drop(&mut self.profiler);
+        }
+    }
+}
+
+impl cranelift_codegen::timing::Profiler for MeasuremeProfiler {
+    fn start_pass(&self, pass: cranelift_codegen::timing::Pass) -> Box<dyn std::any::Any> {
+        let mut timing_guard =
+            TimingGuard { profiler: std::mem::ManuallyDrop::new(self.0.clone()), inner: None };
+        timing_guard.inner = Some(
+            unsafe { &*(&*timing_guard.profiler as &SelfProfilerRef as *const SelfProfilerRef) }
+                .generic_activity(pass.description()),
+        );
+        Box::new(timing_guard)
+    }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index a74f8ffa23d..63a1f6959dd 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -104,7 +104,6 @@ pub(crate) fn compile_global_asm(
             return Ok(None);
         }
 
-        // FIXME fix linker error on macOS
         if cfg!(not(feature = "inline_asm")) {
             return Err(
                 "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift"
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 90b36c61114..539f8c103db 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -51,17 +51,13 @@ fn report_atomic_type_validation_error<'tcx>(
     fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
 }
 
-pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
+pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Type {
     let (element, count) = match layout.abi {
         Abi::Vector { element, count } => (element, count),
         _ => unreachable!(),
     };
 
-    match scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()) {
-        // Cranelift currently only implements icmp for 128bit vectors.
-        Some(vector_ty) if vector_ty.bits() == 128 => Some(vector_ty),
-        _ => None,
-    }
+    scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()).unwrap()
 }
 
 fn simd_for_each_lane<'tcx>(
@@ -1107,8 +1103,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
             fx.bcx.ins().call_indirect(f_sig, f, &[data]);
 
-            let layout = ret.layout();
-            let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
+            let layout = fx.layout_of(fx.tcx.types.i32);
+            let ret_val = CValue::by_val(fx.bcx.ins().iconst(types::I32, 0), layout);
             ret.write_cvalue(fx, ret_val);
         }
 
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 6f54a8d49c8..264b578c168 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -253,7 +253,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             }
 
             ret.write_cvalue(fx, base);
-            let ret_lane = ret.place_field(fx, FieldIdx::new(idx.try_into().unwrap()));
+            let ret_lane = ret.place_lane(fx, idx.try_into().unwrap());
             ret_lane.write_cvalue(fx, val);
         }
 
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 74d9b72b90c..f0b399ae280 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -110,7 +110,7 @@ mod prelude {
     pub(crate) use crate::common::*;
     pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
     pub(crate) use crate::pointer::Pointer;
-    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
+    pub(crate) use crate::value_and_place::{CPlace, CValue};
 }
 
 struct PrintOnPanic<F: Fn() -> String>(F);
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 1357b7be1e0..ba53e01c7a2 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -118,7 +118,7 @@ pub(crate) fn codegen_int_binop<'tcx>(
         );
     }
 
-    if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, in_lhs, in_rhs) {
+    if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, in_lhs, in_rhs) {
         return res;
     }
 
@@ -173,7 +173,7 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
     let lhs = in_lhs.load_scalar(fx);
     let rhs = in_rhs.load_scalar(fx);
 
-    if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs) {
+    if let Some(res) = crate::codegen_i128::maybe_codegen_checked(fx, bin_op, in_lhs, in_rhs) {
         return res;
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index e0a081c9d49..27e21183c55 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -7,48 +7,51 @@
 //! test compile
 //! target x86_64
 //!
-//! function u0:0(i64, i64, i64) system_v {
-//! ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
-//! ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
-//! ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
+//! function u0:22(i64) -> i8, i8 system_v {
+//! ; symbol _ZN97_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$RF$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17hd517c453d67c0915E
+//! ; instance Instance { def: Item(WithOptConstParam { did: DefId(0:42 ~ example[4e51]::{impl#0}::call_once), const_param_did: None }), substs: [ReErased, ReErased] }
+//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, abi: Aggregate { sized: true }, fields: Arbitrary { offsets: [], memory_index: [] }, largest_niche: None, variants: Single { index: 0 } } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), variants: Single { index: 0 } } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, variants: Single { index: 0 } } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false }
 //!
-//! ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
-//! ; msg   loc.idx    param    pass mode            ssa flags  ty
-//! ; ret    _0      = v0       ByRef                NOT_SSA    (u8, u8)
-//! ; arg    _1      = v1       ByRef                NOT_SSA    IsNotEmpty
-//! ; arg    _2.0    = v2       ByVal(types::I64)    NOT_SSA    &&[u16]
+//! ; kind  loc.idx   param    pass mode                            ty
+//! ; ssa   _0    (u8, u8)                          2b 1, 8              var=(0, 1)
+//! ; ret   _0      -          Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) (u8, u8)
+//! ; arg   _1      -          Ignore                               IsNotEmpty
+//! ; arg   _2.0    = v0       Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) &&[u16]
 //!
-//!     ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
-//!     ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
-//!     ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
-//!     sig0 = (i64, i64, i64) system_v
-//!     sig1 = (i64, i64, i64) system_v
-//!     fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
+//! ; kind  local ty                              size align (abi,pref)
+//! ; zst   _1    IsNotEmpty                        0b 1, 8              align=8,offset=
+//! ; stack _2    (&&[u16],)                        8b 8, 8              storage=ss0
+//! ; ssa   _3    &mut IsNotEmpty                   8b 8, 8              var=2
 //!
-//! block0(v0: i64, v1: i64, v2: i64):
-//!     v3 = stack_addr.i64 ss0
-//!     v4 = stack_addr.i64 ss1
-//!     store v2, v4
-//!     v5 = stack_addr.i64 ss2
+//!     ss0 = explicit_slot 16
+//!     sig0 = (i64, i64) -> i8, i8 system_v
+//!     fn0 = colocated u0:23 sig0 ; Instance { def: Item(WithOptConstParam { did: DefId(0:46 ~ example[4e51]::{impl#1}::call_mut), const_param_did: None }), substs: [ReErased, ReErased] }
+//!
+//! block0(v0: i64):
+//!     nop
+//! ; write_cvalue: Addr(Pointer { base: Stack(ss0), offset: Offset32(0) }, None): &&[u16] <- ByVal(v0): &&[u16]
+//!     stack_store v0, ss0
 //!     jump block1
 //!
 //! block1:
 //!     nop
 //! ; _3 = &mut _1
-//! ; _4 = _2
-//!     v6 = load.i64 v4
-//!     store v6, v5
+//!     v1 = iconst.i64 8
+//! ; write_cvalue: Var(_3, var2): &mut IsNotEmpty <- ByVal(v1): &mut IsNotEmpty
 //! ;
-//! ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
-//!     v7 = load.i64 v5
-//!     call fn0(v0, v3, v7)
+//! ; _0 = <IsNotEmpty as mini_core::FnMut<(&&[u16],)>>::call_mut(move _3, _2)
+//!     v2 = stack_load.i64 ss0
+//!     v3, v4 = call fn0(v1, v2)  ; v1 = 8
+//!     v5 -> v3
+//!     v6 -> v4
+//! ; write_cvalue: VarPair(_0, var0, var1): (u8, u8) <- ByValPair(v3, v4): (u8, u8)
 //!     jump block2
 //!
 //! block2:
 //!     nop
 //! ;
 //! ; return
-//!     return
+//!     return v5, v6
 //! }
 //! ```
 
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 1b69862ce2c..c964d1ac5e0 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -2,8 +2,8 @@
 
 use crate::prelude::*;
 
+use cranelift_codegen::entity::EntityRef;
 use cranelift_codegen::ir::immediates::Offset32;
-use cranelift_codegen::ir::{InstructionData, Opcode};
 
 fn codegen_field<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
@@ -214,17 +214,7 @@ impl<'tcx> CValue<'tcx> {
     ) -> CValue<'tcx> {
         let layout = self.1;
         match self.0 {
-            CValueInner::ByVal(val) => match layout.abi {
-                Abi::Vector { element: _, count } => {
-                    let count = u8::try_from(count).expect("SIMD type with more than 255 lanes???");
-                    let field = u8::try_from(field.index()).unwrap();
-                    assert!(field < count);
-                    let lane = fx.bcx.ins().extractlane(val, field);
-                    let field_layout = layout.field(&*fx, usize::from(field));
-                    CValue::by_val(lane, field_layout)
-                }
-                _ => unreachable!("value_field for ByVal with abi {:?}", layout.abi),
-            },
+            CValueInner::ByVal(_) => unreachable!(),
             CValueInner::ByValPair(val1, val2) => match layout.abi {
                 Abi::ScalarPair(_, _) => {
                     let val = match field.as_u32() {
@@ -258,16 +248,7 @@ impl<'tcx> CValue<'tcx> {
         let lane_layout = fx.layout_of(lane_ty);
         assert!(lane_idx < lane_count);
         match self.0 {
-            CValueInner::ByVal(val) => match layout.abi {
-                Abi::Vector { element: _, count: _ } => {
-                    assert!(lane_count <= u8::MAX.into(), "SIMD type with more than 255 lanes???");
-                    let lane_idx = u8::try_from(lane_idx).unwrap();
-                    let lane = fx.bcx.ins().extractlane(val, lane_idx);
-                    CValue::by_val(lane, lane_layout)
-                }
-                _ => unreachable!("value_lane for ByVal with abi {:?}", layout.abi),
-            },
-            CValueInner::ByValPair(_, _) => unreachable!(),
+            CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => unreachable!(),
             CValueInner::ByRef(ptr, None) => {
                 let field_offset = lane_layout.size * lane_idx;
                 let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
@@ -277,14 +258,6 @@ impl<'tcx> CValue<'tcx> {
         }
     }
 
-    pub(crate) fn unsize_value(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) {
-        crate::unsize::coerce_unsized_into(fx, self, dest);
-    }
-
-    pub(crate) fn coerce_dyn_star(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) {
-        crate::unsize::coerce_dyn_star(fx, self, dest);
-    }
-
     /// If `ty` is signed, `const_val` must already be sign extended.
     pub(crate) fn const_val(
         fx: &mut FunctionCx<'_, '_, 'tcx>,
@@ -345,10 +318,9 @@ pub(crate) struct CPlace<'tcx> {
 }
 
 #[derive(Debug, Copy, Clone)]
-pub(crate) enum CPlaceInner {
+enum CPlaceInner {
     Var(Local, Variable),
     VarPair(Local, Variable, Variable),
-    VarLane(Local, Variable, u8),
     Addr(Pointer, Option<Value>),
 }
 
@@ -357,10 +329,6 @@ impl<'tcx> CPlace<'tcx> {
         self.layout
     }
 
-    pub(crate) fn inner(&self) -> &CPlaceInner {
-        &self.inner
-    }
-
     pub(crate) fn new_stack_slot(
         fx: &mut FunctionCx<'_, '_, 'tcx>,
         layout: TyAndLayout<'tcx>,
@@ -442,12 +410,6 @@ impl<'tcx> CPlace<'tcx> {
                 //fx.bcx.set_val_label(val2, cranelift_codegen::ir::ValueLabel::new(var2.index()));
                 CValue::by_val_pair(val1, val2, layout)
             }
-            CPlaceInner::VarLane(_local, var, lane) => {
-                let val = fx.bcx.use_var(var);
-                //fx.bcx.set_val_label(val, cranelift_codegen::ir::ValueLabel::new(var.index()));
-                let val = fx.bcx.ins().extractlane(val, lane);
-                CValue::by_val(val, layout)
-            }
             CPlaceInner::Addr(ptr, extra) => {
                 if let Some(extra) = extra {
                     CValue::by_ref_unsized(ptr, extra, layout)
@@ -458,21 +420,56 @@ impl<'tcx> CPlace<'tcx> {
         }
     }
 
+    pub(crate) fn debug_comment(self) -> (&'static str, String) {
+        match self.inner {
+            CPlaceInner::Var(_local, var) => ("ssa", format!("var={}", var.index())),
+            CPlaceInner::VarPair(_local, var1, var2) => {
+                ("ssa", format!("var=({}, {})", var1.index(), var2.index()))
+            }
+            CPlaceInner::Addr(ptr, meta) => {
+                let meta =
+                    if let Some(meta) = meta { format!(",meta={}", meta) } else { String::new() };
+                match ptr.debug_base_and_offset() {
+                    (crate::pointer::PointerBase::Addr(addr), offset) => {
+                        ("reuse", format!("storage={}{}{}", addr, offset, meta))
+                    }
+                    (crate::pointer::PointerBase::Stack(stack_slot), offset) => {
+                        ("stack", format!("storage={}{}{}", stack_slot, offset, meta))
+                    }
+                    (crate::pointer::PointerBase::Dangling(align), offset) => {
+                        ("zst", format!("align={},offset={}", align.bytes(), offset))
+                    }
+                }
+            }
+        }
+    }
+
     #[track_caller]
     pub(crate) fn to_ptr(self) -> Pointer {
-        match self.to_ptr_maybe_unsized() {
-            (ptr, None) => ptr,
-            (_, Some(_)) => bug!("Expected sized cplace, found {:?}", self),
+        match self.inner {
+            CPlaceInner::Addr(ptr, None) => ptr,
+            CPlaceInner::Addr(_, Some(_)) => bug!("Expected sized cplace, found {:?}", self),
+            CPlaceInner::Var(_, _) | CPlaceInner::VarPair(_, _, _) => {
+                bug!("Expected CPlace::Addr, found {:?}", self)
+            }
         }
     }
 
     #[track_caller]
-    pub(crate) fn to_ptr_maybe_unsized(self) -> (Pointer, Option<Value>) {
+    pub(crate) fn to_ptr_unsized(self) -> (Pointer, Value) {
         match self.inner {
-            CPlaceInner::Addr(ptr, extra) => (ptr, extra),
-            CPlaceInner::Var(_, _)
-            | CPlaceInner::VarPair(_, _, _)
-            | CPlaceInner::VarLane(_, _, _) => bug!("Expected CPlace::Addr, found {:?}", self),
+            CPlaceInner::Addr(ptr, Some(extra)) => (ptr, extra),
+            CPlaceInner::Addr(_, None) | CPlaceInner::Var(_, _) | CPlaceInner::VarPair(_, _, _) => {
+                bug!("Expected unsized cplace, found {:?}", self)
+            }
+        }
+    }
+
+    pub(crate) fn try_to_ptr(self) -> Option<Pointer> {
+        match self.inner {
+            CPlaceInner::Var(_, _) | CPlaceInner::VarPair(_, _, _) => None,
+            CPlaceInner::Addr(ptr, None) => Some(ptr),
+            CPlaceInner::Addr(_, Some(_)) => bug!("Expected sized cplace, found {:?}", self),
         }
     }
 
@@ -496,7 +493,7 @@ impl<'tcx> CPlace<'tcx> {
         from: CValue<'tcx>,
         method: &'static str,
     ) {
-        fn transmute_value<'tcx>(
+        fn transmute_scalar<'tcx>(
             fx: &mut FunctionCx<'_, '_, 'tcx>,
             var: Variable,
             data: Value,
@@ -520,7 +517,7 @@ impl<'tcx> CPlace<'tcx> {
                 | (types::F64, types::I64) => codegen_bitcast(fx, dst_ty, data),
                 _ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data),
                 _ if src_ty.is_vector() || dst_ty.is_vector() => {
-                    // FIXME do something more efficient for transmutes between vectors and integers.
+                    // FIXME(bytecodealliance/wasmtime#6104) do something more efficient for transmutes between vectors and integers.
                     let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
                         kind: StackSlotKind::ExplicitSlot,
                         // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
@@ -554,7 +551,7 @@ impl<'tcx> CPlace<'tcx> {
                 format!(
                     "{}: {:?}: {:?} <- {:?}: {:?}",
                     method,
-                    self.inner(),
+                    self.inner,
                     self.layout().ty,
                     from.0,
                     from.layout().ty
@@ -563,32 +560,11 @@ impl<'tcx> CPlace<'tcx> {
         }
 
         let dst_layout = self.layout();
-        let to_ptr = match self.inner {
+        match self.inner {
             CPlaceInner::Var(_local, var) => {
-                if let ty::Array(element, len) = dst_layout.ty.kind() {
-                    // Can only happen for vector types
-                    let len = u32::try_from(len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()))
-                        .unwrap();
-                    let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap();
-
-                    let data = match from.0 {
-                        CValueInner::ByRef(ptr, None) => {
-                            let mut flags = MemFlags::new();
-                            flags.set_notrap();
-                            ptr.load(fx, vector_ty, flags)
-                        }
-                        CValueInner::ByVal(_)
-                        | CValueInner::ByValPair(_, _)
-                        | CValueInner::ByRef(_, Some(_)) => bug!("array should be ByRef"),
-                    };
-
-                    fx.bcx.def_var(var, data);
-                    return;
-                }
                 let data = CValue(from.0, dst_layout).load_scalar(fx);
                 let dst_ty = fx.clif_type(self.layout().ty).unwrap();
-                transmute_value(fx, var, data, dst_ty);
-                return;
+                transmute_scalar(fx, var, data, dst_ty);
             }
             CPlaceInner::VarPair(_local, var1, var2) => {
                 let (data1, data2) = if from.layout().ty == dst_layout.ty {
@@ -599,80 +575,61 @@ impl<'tcx> CPlace<'tcx> {
                     CValue(CValueInner::ByRef(ptr, None), dst_layout).load_scalar_pair(fx)
                 };
                 let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap();
-                transmute_value(fx, var1, data1, dst_ty1);
-                transmute_value(fx, var2, data2, dst_ty2);
-                return;
+                transmute_scalar(fx, var1, data1, dst_ty1);
+                transmute_scalar(fx, var2, data2, dst_ty2);
             }
-            CPlaceInner::VarLane(_local, var, lane) => {
-                let data = from.load_scalar(fx);
-
-                // First get the old vector
-                let vector = fx.bcx.use_var(var);
-                //fx.bcx.set_val_label(vector, cranelift_codegen::ir::ValueLabel::new(var.index()));
-
-                // Next insert the written lane into the vector
-                let vector = fx.bcx.ins().insertlane(vector, data, lane);
-
-                // Finally write the new vector
-                //fx.bcx.set_val_label(vector, cranelift_codegen::ir::ValueLabel::new(var.index()));
-                fx.bcx.def_var(var, vector);
-
-                return;
-            }
-            CPlaceInner::Addr(ptr, None) => {
+            CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self),
+            CPlaceInner::Addr(to_ptr, None) => {
                 if dst_layout.size == Size::ZERO || dst_layout.abi == Abi::Uninhabited {
                     return;
                 }
-                ptr
-            }
-            CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self),
-        };
 
-        let mut flags = MemFlags::new();
-        flags.set_notrap();
-        match from.layout().abi {
-            // FIXME make Abi::Vector work too
-            Abi::Scalar(_) => {
-                let val = from.load_scalar(fx);
-                to_ptr.store(fx, val, flags);
-                return;
-            }
-            Abi::ScalarPair(a_scalar, b_scalar) => {
-                let (value, extra) = from.load_scalar_pair(fx);
-                let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
-                to_ptr.store(fx, value, flags);
-                to_ptr.offset(fx, b_offset).store(fx, extra, flags);
-                return;
-            }
-            _ => {}
-        }
+                let mut flags = MemFlags::new();
+                flags.set_notrap();
+                match from.layout().abi {
+                    Abi::Scalar(_) => {
+                        let val = from.load_scalar(fx);
+                        to_ptr.store(fx, val, flags);
+                        return;
+                    }
+                    Abi::ScalarPair(a_scalar, b_scalar) => {
+                        let (value, extra) = from.load_scalar_pair(fx);
+                        let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
+                        to_ptr.store(fx, value, flags);
+                        to_ptr.offset(fx, b_offset).store(fx, extra, flags);
+                        return;
+                    }
+                    _ => {}
+                }
 
-        match from.0 {
-            CValueInner::ByVal(val) => {
-                to_ptr.store(fx, val, flags);
-            }
-            CValueInner::ByValPair(_, _) => {
-                bug!("Non ScalarPair abi {:?} for ByValPair CValue", dst_layout.abi);
-            }
-            CValueInner::ByRef(from_ptr, None) => {
-                let from_addr = from_ptr.get_addr(fx);
-                let to_addr = to_ptr.get_addr(fx);
-                let src_layout = from.1;
-                let size = dst_layout.size.bytes();
-                let src_align = src_layout.align.abi.bytes() as u8;
-                let dst_align = dst_layout.align.abi.bytes() as u8;
-                fx.bcx.emit_small_memory_copy(
-                    fx.target_config,
-                    to_addr,
-                    from_addr,
-                    size,
-                    dst_align,
-                    src_align,
-                    true,
-                    flags,
-                );
+                match from.0 {
+                    CValueInner::ByVal(val) => {
+                        to_ptr.store(fx, val, flags);
+                    }
+                    CValueInner::ByValPair(_, _) => {
+                        bug!("Non ScalarPair abi {:?} for ByValPair CValue", dst_layout.abi);
+                    }
+                    CValueInner::ByRef(from_ptr, None) => {
+                        let from_addr = from_ptr.get_addr(fx);
+                        let to_addr = to_ptr.get_addr(fx);
+                        let src_layout = from.1;
+                        let size = dst_layout.size.bytes();
+                        let src_align = src_layout.align.abi.bytes() as u8;
+                        let dst_align = dst_layout.align.abi.bytes() as u8;
+                        fx.bcx.emit_small_memory_copy(
+                            fx.target_config,
+                            to_addr,
+                            from_addr,
+                            size,
+                            dst_align,
+                            src_align,
+                            true,
+                            flags,
+                        );
+                    }
+                    CValueInner::ByRef(_, Some(_)) => todo!(),
+                }
             }
-            CValueInner::ByRef(_, Some(_)) => todo!(),
         }
     }
 
@@ -692,40 +649,6 @@ impl<'tcx> CPlace<'tcx> {
         let layout = self.layout();
 
         match self.inner {
-            CPlaceInner::Var(local, var) => match layout.ty.kind() {
-                ty::Array(_, _) => {
-                    // Can only happen for vector types
-                    return CPlace {
-                        inner: CPlaceInner::VarLane(local, var, field.as_u32().try_into().unwrap()),
-                        layout: layout.field(fx, field.as_u32().try_into().unwrap()),
-                    };
-                }
-                ty::Adt(adt_def, substs) if layout.ty.is_simd() => {
-                    let f0 = &adt_def.non_enum_variant().fields[FieldIdx::from_u32(0)];
-                    let f0_ty = f0.ty(fx.tcx, substs);
-
-                    match f0_ty.kind() {
-                        ty::Array(_, _) => {
-                            assert_eq!(field.as_u32(), 0);
-                            return CPlace {
-                                inner: CPlaceInner::Var(local, var),
-                                layout: layout.field(fx, field.as_u32().try_into().unwrap()),
-                            };
-                        }
-                        _ => {
-                            return CPlace {
-                                inner: CPlaceInner::VarLane(
-                                    local,
-                                    var,
-                                    field.as_u32().try_into().unwrap(),
-                                ),
-                                layout: layout.field(fx, field.as_u32().try_into().unwrap()),
-                            };
-                        }
-                    }
-                }
-                _ => {}
-            },
             CPlaceInner::VarPair(local, var1, var2) => {
                 let layout = layout.field(&*fx, field.index());
 
@@ -738,7 +661,12 @@ impl<'tcx> CPlace<'tcx> {
             _ => {}
         }
 
-        let (base, extra) = self.to_ptr_maybe_unsized();
+        let (base, extra) = match self.inner {
+            CPlaceInner::Addr(ptr, extra) => (ptr, extra),
+            CPlaceInner::Var(_, _) | CPlaceInner::VarPair(_, _, _) => {
+                bug!("Expected CPlace::Addr, found {:?}", self)
+            }
+        };
 
         let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field);
         if field_layout.is_unsized() {
@@ -767,15 +695,8 @@ impl<'tcx> CPlace<'tcx> {
         assert!(lane_idx < lane_count);
 
         match self.inner {
-            CPlaceInner::Var(local, var) => {
-                assert!(matches!(layout.abi, Abi::Vector { .. }));
-                CPlace {
-                    inner: CPlaceInner::VarLane(local, var, lane_idx.try_into().unwrap()),
-                    layout: lane_layout,
-                }
-            }
+            CPlaceInner::Var(_, _) => unreachable!(),
             CPlaceInner::VarPair(_, _, _) => unreachable!(),
-            CPlaceInner::VarLane(_, _, _) => unreachable!(),
             CPlaceInner::Addr(ptr, None) => {
                 let field_offset = lane_layout.size * lane_idx;
                 let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
@@ -794,34 +715,13 @@ impl<'tcx> CPlace<'tcx> {
             ty::Array(elem_ty, _) => {
                 let elem_layout = fx.layout_of(*elem_ty);
                 match self.inner {
-                    CPlaceInner::Var(local, var) => {
-                        // This is a hack to handle `vector_val.0[1]`. It doesn't allow dynamic
-                        // indexing.
-                        let lane_idx = match fx.bcx.func.dfg.insts
-                            [fx.bcx.func.dfg.value_def(index).unwrap_inst()]
-                        {
-                            InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => imm,
-                            _ => bug!(
-                                "Dynamic indexing into a vector type is not supported: {self:?}[{index}]"
-                            ),
-                        };
-                        return CPlace {
-                            inner: CPlaceInner::VarLane(
-                                local,
-                                var,
-                                lane_idx.bits().try_into().unwrap(),
-                            ),
-                            layout: elem_layout,
-                        };
-                    }
                     CPlaceInner::Addr(addr, None) => (elem_layout, addr),
-                    CPlaceInner::Addr(_, Some(_))
-                    | CPlaceInner::VarPair(_, _, _)
-                    | CPlaceInner::VarLane(_, _, _) => bug!("Can't index into {self:?}"),
+                    CPlaceInner::Var(_, _)
+                    | CPlaceInner::Addr(_, Some(_))
+                    | CPlaceInner::VarPair(_, _, _) => bug!("Can't index into {self:?}"),
                 }
-                // FIXME use VarLane in case of Var with simd type
             }
-            ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_maybe_unsized().0),
+            ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_unsized().0),
             _ => bug!("place_index({:?})", self.layout().ty),
         };
 
@@ -846,12 +746,8 @@ impl<'tcx> CPlace<'tcx> {
         layout: TyAndLayout<'tcx>,
     ) -> CValue<'tcx> {
         if has_ptr_meta(fx.tcx, self.layout().ty) {
-            let (ptr, extra) = self.to_ptr_maybe_unsized();
-            CValue::by_val_pair(
-                ptr.get_addr(fx),
-                extra.expect("unsized type without metadata"),
-                layout,
-            )
+            let (ptr, extra) = self.to_ptr_unsized();
+            CValue::by_val_pair(ptr.get_addr(fx), extra, layout)
         } else {
             CValue::by_val(self.to_ptr().get_addr(fx), layout)
         }
diff --git a/compiler/rustc_codegen_cranelift/y.rs b/compiler/rustc_codegen_cranelift/y.rs
index fd825d02e35..a68a10500f5 100755
--- a/compiler/rustc_codegen_cranelift/y.rs
+++ b/compiler/rustc_codegen_cranelift/y.rs
@@ -3,10 +3,14 @@
 # This block is ignored by rustc
 set -e
 echo "[BUILD] y.rs" 1>&2
-rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021 -Cpanic=abort
+rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021
 exec ${0/.rs/.bin} $@
 */
 
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+#![warn(unreachable_pub)]
+
 //! The build system for cg_clif
 //!
 //! # Manual compilation
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index a421535c9b4..4f73b731f5a 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -49,3 +49,7 @@ libc = "0.2.50"
 version = "0.30.1"
 default-features = false
 features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
+
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = ["Win32_Globalization"]
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index eecfe13bb3e..c63e156beae 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -860,7 +860,7 @@ fn link_natively<'a>(
             if !prog.status.success() {
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
-                let escaped_output = escape_string(&output);
+                let escaped_output = escape_linker_output(&output, flavor);
                 // FIXME: Add UI tests for this error.
                 let err = errors::LinkingFailed {
                     linker_path: &linker_path,
@@ -1052,6 +1052,83 @@ fn escape_string(s: &[u8]) -> String {
     }
 }
 
+#[cfg(not(windows))]
+fn escape_linker_output(s: &[u8], _flavour: LinkerFlavor) -> String {
+    escape_string(s)
+}
+
+/// If the output of the msvc linker is not UTF-8 and the host is Windows,
+/// then try to convert the string from the OEM encoding.
+#[cfg(windows)]
+fn escape_linker_output(s: &[u8], flavour: LinkerFlavor) -> String {
+    // This only applies to the actual MSVC linker.
+    if flavour != LinkerFlavor::Msvc(Lld::No) {
+        return escape_string(s);
+    }
+    match str::from_utf8(s) {
+        Ok(s) => return s.to_owned(),
+        Err(_) => match win::locale_byte_str_to_string(s, win::oem_code_page()) {
+            Some(s) => s,
+            // The string is not UTF-8 and isn't valid for the OEM code page
+            None => format!("Non-UTF-8 output: {}", s.escape_ascii()),
+        },
+    }
+}
+
+/// Wrappers around the Windows API.
+#[cfg(windows)]
+mod win {
+    use windows::Win32::Globalization::{
+        GetLocaleInfoEx, MultiByteToWideChar, CP_OEMCP, LOCALE_IUSEUTF8LEGACYOEMCP,
+        LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_RETURN_NUMBER, MB_ERR_INVALID_CHARS,
+    };
+
+    /// Get the Windows system OEM code page. This is most notably the code page
+    /// used for link.exe's output.
+    pub fn oem_code_page() -> u32 {
+        unsafe {
+            let mut cp: u32 = 0;
+            // We're using the `LOCALE_RETURN_NUMBER` flag to return a u32.
+            // But the API requires us to pass the data as though it's a [u16] string.
+            let len = std::mem::size_of::<u32>() / std::mem::size_of::<u16>();
+            let data = std::slice::from_raw_parts_mut(&mut cp as *mut u32 as *mut u16, len);
+            let len_written = GetLocaleInfoEx(
+                LOCALE_NAME_SYSTEM_DEFAULT,
+                LOCALE_IUSEUTF8LEGACYOEMCP | LOCALE_RETURN_NUMBER,
+                Some(data),
+            );
+            if len_written as usize == len { cp } else { CP_OEMCP }
+        }
+    }
+    /// Try to convert a multi-byte string to a UTF-8 string using the given code page
+    /// The string does not need to be null terminated.
+    ///
+    /// This is implemented as a wrapper around `MultiByteToWideChar`.
+    /// See <https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar>
+    ///
+    /// It will fail if the multi-byte string is longer than `i32::MAX` or if it contains
+    /// any invalid bytes for the expected encoding.
+    pub fn locale_byte_str_to_string(s: &[u8], code_page: u32) -> Option<String> {
+        // `MultiByteToWideChar` requires a length to be a "positive integer".
+        if s.len() > isize::MAX as usize {
+            return None;
+        }
+        // Error if the string is not valid for the expected code page.
+        let flags = MB_ERR_INVALID_CHARS;
+        // Call MultiByteToWideChar twice.
+        // First to calculate the length then to convert the string.
+        let mut len = unsafe { MultiByteToWideChar(code_page, flags, s, None) };
+        if len > 0 {
+            let mut utf16 = vec![0; len as usize];
+            len = unsafe { MultiByteToWideChar(code_page, flags, s, Some(&mut utf16)) };
+            if len > 0 {
+                return utf16.get(..len as usize).map(String::from_utf16_lossy);
+            }
+        }
+        None
+    }
+}
+
 fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
     // On macOS the runtimes are distributed as dylibs which should be linked to
     // both executables and dynamic shared objects. Everywhere else the runtimes
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 179453238f2..01b69966ca9 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -27,6 +27,7 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 
 use proc_macro::bridge::client::ProcMacro;
+use std::error::Error;
 use std::ops::Fn;
 use std::path::Path;
 use std::time::Duration;
@@ -1094,5 +1095,12 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, S
     }
 
     debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
-    Err(format!("{} (retried {} times)", last_error.unwrap(), max_attempts))
+
+    let last_error = last_error.unwrap();
+    let message = if let Some(src) = last_error.source() {
+        format!("{last_error} ({src}) (retried {max_attempts} times)")
+    } else {
+        format!("{last_error} (retried {max_attempts} times)")
+    };
+    Err(message)
 }
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index f5f1c1010e1..b9bc89fcf8f 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -56,8 +56,11 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
                         "reference to packed field is unaligned"
                     )
                     .note(
-                        "fields of packed structs are not properly aligned, and creating \
-                        a misaligned reference is undefined behavior (even if that \
+                        "packed structs are only aligned by one byte, and many modern architectures \
+                        penalize unaligned field accesses"
+                    )
+                    .note(
+                        "creating a misaligned reference is undefined behavior (even if that \
                         reference is never dereferenced)",
                     ).help(
                         "copy the field contents to a local variable, or replace the \
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 1e115be2c2a..443f469ce52 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -1,7 +1,7 @@
 use crate::deref_separator::deref_finder;
 use crate::MirPass;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
+use rustc_index::IndexVec;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
@@ -84,12 +84,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
 
             let reachable = traversal::reachable_as_bitset(body);
 
+            let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths);
             ElaborateDropsCtxt {
                 tcx,
                 body,
                 env: &env,
                 init_data: InitializationData { inits, uninits },
-                drop_flags: Default::default(),
+                drop_flags,
                 patch: MirPatch::new(body),
                 un_derefer: un_derefer,
                 reachable,
@@ -293,7 +294,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> {
     body: &'a Body<'tcx>,
     env: &'a MoveDataParamEnv<'tcx>,
     init_data: InitializationData<'a, 'tcx>,
-    drop_flags: FxHashMap<MovePathIndex, Local>,
+    drop_flags: IndexVec<MovePathIndex, Option<Local>>,
     patch: MirPatch<'tcx>,
     un_derefer: UnDerefer<'tcx>,
     reachable: BitSet<BasicBlock>,
@@ -312,11 +313,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         let tcx = self.tcx;
         let patch = &mut self.patch;
         debug!("create_drop_flag({:?})", self.body.span);
-        self.drop_flags.entry(index).or_insert_with(|| patch.new_internal(tcx.types.bool, span));
+        self.drop_flags[index].get_or_insert_with(|| patch.new_internal(tcx.types.bool, span));
     }
 
     fn drop_flag(&mut self, index: MovePathIndex) -> Option<Place<'tcx>> {
-        self.drop_flags.get(&index).map(|t| Place::from(*t))
+        self.drop_flags[index].map(Place::from)
     }
 
     /// create a patch that elaborates all drops in the input
@@ -463,7 +464,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     }
 
     fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) {
-        if let Some(&flag) = self.drop_flags.get(&path) {
+        if let Some(flag) = self.drop_flags[path] {
             let span = self.patch.source_info_for_location(self.body, loc).span;
             let val = self.constant_bool(span, val.value());
             self.patch.add_assign(loc, Place::from(flag), val);
@@ -474,7 +475,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         let loc = Location::START;
         let span = self.patch.source_info_for_location(self.body, loc).span;
         let false_ = self.constant_bool(span, false);
-        for flag in self.drop_flags.values() {
+        for flag in self.drop_flags.iter().flatten() {
             self.patch.add_assign(loc, Place::from(*flag), false_.clone());
         }
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index a97857e05e2..5c02e7193a2 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -859,13 +859,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                             sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
                             &sig.decl.output,
                         );
-
-                        this.record_lifetime_params_for_async(
-                            fn_id,
-                            sig.header.asyncness.opt_return_id(),
-                        );
                     },
                 );
+                self.record_lifetime_params_for_async(fn_id, sig.header.asyncness.opt_return_id());
                 return;
             }
             FnKind::Fn(..) => {
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index bd52957d162..63a73f8d50d 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -3,7 +3,8 @@ use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{
-    DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
+    DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, RegionVariableOrigin,
+    TyCtxtInferExt,
 };
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::ObligationCause;
@@ -223,18 +224,20 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         {
             debug!("rerunning goal to check result is stable");
             let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
-            let canonical_response =
+            let new_canonical_response =
                 EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
-            if !canonical_response.value.var_values.is_identity() {
+            if !new_canonical_response.value.var_values.is_identity() {
                 bug!(
                     "unstable result: re-canonicalized goal={canonical_goal:#?} \
-                     response={canonical_response:#?}"
+                    first_response={canonical_response:#?} \
+                    second_response={new_canonical_response:#?}"
                 );
             }
-            if certainty != canonical_response.value.certainty {
+            if certainty != new_canonical_response.value.certainty {
                 bug!(
                     "unstable certainty: {certainty:#?} re-canonicalized goal={canonical_goal:#?} \
-                     response={canonical_response:#?}"
+                     first_response={canonical_response:#?} \
+                     second_response={new_canonical_response:#?}"
                 );
             }
         }
@@ -434,6 +437,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         })
     }
 
+    pub(super) fn next_region_infer(&self) -> ty::Region<'tcx> {
+        self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
+    }
+
     pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
         self.infcx.next_const_var(
             ty,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 226d29687e3..67ad7fb4bd2 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
+use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData, MaybeCause};
 use rustc_middle::ty::{self, BoundVar, GenericArgKind};
 use rustc_span::DUMMY_SP;
 use std::iter;
@@ -60,9 +60,27 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
         let certainty = certainty.unify_with(goals_certainty);
 
-        let external_constraints = self.compute_external_query_constraints()?;
+        let response = match certainty {
+            Certainty::Yes | Certainty::Maybe(MaybeCause::Ambiguity) => {
+                let external_constraints = self.compute_external_query_constraints()?;
+                Response { var_values: self.var_values, external_constraints, certainty }
+            }
+            Certainty::Maybe(MaybeCause::Overflow) => {
+                // If we have overflow, it's probable that we're substituting a type
+                // into itself infinitely and any partial substitutions in the query
+                // response are probably not useful anyways, so just return an empty
+                // query response.
+                //
+                // This may prevent us from potentially useful inference, e.g.
+                // 2 candidates, one ambiguous and one overflow, which both
+                // have the same inference constraints.
+                //
+                // Changing this to retain some constraints in the future
+                // won't be a breaking change, so this is good enough for now.
+                return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
+            }
+        };
 
-        let response = Response { var_values: self.var_values, external_constraints, certainty };
         let canonical = Canonicalizer::canonicalize(
             self.infcx,
             CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
@@ -72,6 +90,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         Ok(canonical)
     }
 
+    /// Constructs a totally unconstrained, ambiguous response to a goal.
+    ///
+    /// Take care when using this, since often it's useful to respond with
+    /// ambiguity but return constrained variables to guide inference.
+    pub(in crate::solve) fn make_ambiguous_response_no_constraints(
+        &self,
+        maybe_cause: MaybeCause,
+    ) -> CanonicalResponse<'tcx> {
+        let unconstrained_response = Response {
+            var_values: CanonicalVarValues {
+                var_values: self.tcx().mk_substs_from_iter(self.var_values.var_values.iter().map(
+                    |arg| -> ty::GenericArg<'tcx> {
+                        match arg.unpack() {
+                            GenericArgKind::Lifetime(_) => self.next_region_infer().into(),
+                            GenericArgKind::Type(_) => self.next_ty_infer().into(),
+                            GenericArgKind::Const(ct) => self.next_const_infer(ct.ty()).into(),
+                        }
+                    },
+                )),
+            },
+            external_constraints: self
+                .tcx()
+                .mk_external_constraints(ExternalConstraintsData::default()),
+            certainty: Certainty::Maybe(maybe_cause),
+        };
+
+        Canonicalizer::canonicalize(
+            self.infcx,
+            CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
+            &mut Default::default(),
+            unconstrained_response,
+        )
+    }
+
     #[instrument(level = "debug", skip(self), ret)]
     fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> {
         // Cannot use `take_registered_region_obligations` as we may compute the response
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 19bcbd46144..d94679fef28 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -340,17 +340,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         if responses.is_empty() {
             return Err(NoSolution);
         }
-        let certainty = responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| {
-            certainty.unify_with(response.value.certainty)
-        });
-
-        let response = self.evaluate_added_goals_and_make_canonical_response(certainty);
-        if let Ok(response) = response {
-            assert!(response.has_no_inference_or_external_constraints());
-            Ok(response)
-        } else {
-            bug!("failed to make floundered response: {responses:?}");
-        }
+
+        let Certainty::Maybe(maybe_cause) = responses.iter().fold(
+            Certainty::AMBIGUOUS,
+            |certainty, response| {
+                certainty.unify_with(response.value.certainty)
+            },
+        ) else {
+            bug!("expected flounder response to be ambiguous")
+        };
+
+        Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
     }
 }
 
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index afdc998172d..efbbc1c2331 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -1543,11 +1543,17 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
         self.next_back()
     }
 
-    fn min(mut self) -> Option<(&'a K, &'a V)> {
+    fn min(mut self) -> Option<(&'a K, &'a V)>
+    where
+        (&'a K, &'a V): Ord,
+    {
         self.next()
     }
 
-    fn max(mut self) -> Option<(&'a K, &'a V)> {
+    fn max(mut self) -> Option<(&'a K, &'a V)>
+    where
+        (&'a K, &'a V): Ord,
+    {
         self.next_back()
     }
 }
@@ -1612,11 +1618,17 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
         self.next_back()
     }
 
-    fn min(mut self) -> Option<(&'a K, &'a mut V)> {
+    fn min(mut self) -> Option<(&'a K, &'a mut V)>
+    where
+        (&'a K, &'a mut V): Ord,
+    {
         self.next()
     }
 
-    fn max(mut self) -> Option<(&'a K, &'a mut V)> {
+    fn max(mut self) -> Option<(&'a K, &'a mut V)>
+    where
+        (&'a K, &'a mut V): Ord,
+    {
         self.next_back()
     }
 }
@@ -1779,11 +1791,17 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> {
         self.next_back()
     }
 
-    fn min(mut self) -> Option<&'a K> {
+    fn min(mut self) -> Option<&'a K>
+    where
+        &'a K: Ord,
+    {
         self.next()
     }
 
-    fn max(mut self) -> Option<&'a K> {
+    fn max(mut self) -> Option<&'a K>
+    where
+        &'a K: Ord,
+    {
         self.next_back()
     }
 }
@@ -2008,11 +2026,17 @@ impl<'a, K, V> Iterator for Range<'a, K, V> {
         self.next_back()
     }
 
-    fn min(mut self) -> Option<(&'a K, &'a V)> {
+    fn min(mut self) -> Option<(&'a K, &'a V)>
+    where
+        (&'a K, &'a V): Ord,
+    {
         self.next()
     }
 
-    fn max(mut self) -> Option<(&'a K, &'a V)> {
+    fn max(mut self) -> Option<(&'a K, &'a V)>
+    where
+        (&'a K, &'a V): Ord,
+    {
         self.next_back()
     }
 }
@@ -2081,11 +2105,17 @@ impl<K, V, A: Allocator + Clone> Iterator for IntoKeys<K, V, A> {
         self.next_back()
     }
 
-    fn min(mut self) -> Option<K> {
+    fn min(mut self) -> Option<K>
+    where
+        K: Ord,
+    {
         self.next()
     }
 
-    fn max(mut self) -> Option<K> {
+    fn max(mut self) -> Option<K>
+    where
+        K: Ord,
+    {
         self.next_back()
     }
 }
@@ -2204,11 +2234,17 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> {
         self.next_back()
     }
 
-    fn min(mut self) -> Option<(&'a K, &'a mut V)> {
+    fn min(mut self) -> Option<(&'a K, &'a mut V)>
+    where
+        (&'a K, &'a mut V): Ord,
+    {
         self.next()
     }
 
-    fn max(mut self) -> Option<(&'a K, &'a mut V)> {
+    fn max(mut self) -> Option<(&'a K, &'a mut V)>
+    where
+        (&'a K, &'a mut V): Ord,
+    {
         self.next_back()
     }
 }
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index da952a13f1e..940fa30afb8 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -1501,11 +1501,17 @@ impl<'a, T> Iterator for Iter<'a, T> {
         self.next_back()
     }
 
-    fn min(mut self) -> Option<&'a T> {
+    fn min(mut self) -> Option<&'a T>
+    where
+        &'a T: Ord,
+    {
         self.next()
     }
 
-    fn max(mut self) -> Option<&'a T> {
+    fn max(mut self) -> Option<&'a T>
+    where
+        &'a T: Ord,
+    {
         self.next_back()
     }
 }
@@ -1604,11 +1610,17 @@ impl<'a, T> Iterator for Range<'a, T> {
         self.next_back()
     }
 
-    fn min(mut self) -> Option<&'a T> {
+    fn min(mut self) -> Option<&'a T>
+    where
+        &'a T: Ord,
+    {
         self.next()
     }
 
-    fn max(mut self) -> Option<&'a T> {
+    fn max(mut self) -> Option<&'a T>
+    where
+        &'a T: Ord,
+    {
         self.next_back()
     }
 }
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 8916b42eda0..896da37f94c 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2815,7 +2815,7 @@ impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> {
     }
 
     #[inline]
-    fn extend_one(&mut self, &elem: &T) {
+    fn extend_one(&mut self, &elem: &'a T) {
         self.push_back(elem);
     }
 
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 98c87b2c393..940558974e6 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -248,7 +248,7 @@ where
 impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
     type Error = TryFromSliceError;
 
-    fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> {
+    fn try_from(slice: &'a [T]) -> Result<&'a [T; N], TryFromSliceError> {
         if slice.len() == N {
             let ptr = slice.as_ptr() as *const [T; N];
             // SAFETY: ok because we just checked that the length fits
@@ -275,7 +275,7 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
 impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] {
     type Error = TryFromSliceError;
 
-    fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> {
+    fn try_from(slice: &'a mut [T]) -> Result<&'a mut [T; N], TryFromSliceError> {
         if slice.len() == N {
             let ptr = slice.as_mut_ptr() as *mut [T; N];
             // SAFETY: ok because we just checked that the length fits
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 37db074293d..0171d89812f 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -732,12 +732,18 @@ impl<A: Step> Iterator for ops::Range<A> {
     }
 
     #[inline]
-    fn min(mut self) -> Option<A> {
+    fn min(mut self) -> Option<A>
+    where
+        A: Ord,
+    {
         self.next()
     }
 
     #[inline]
-    fn max(mut self) -> Option<A> {
+    fn max(mut self) -> Option<A>
+    where
+        A: Ord,
+    {
         self.next_back()
     }
 
@@ -1158,12 +1164,18 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
     }
 
     #[inline]
-    fn min(mut self) -> Option<A> {
+    fn min(mut self) -> Option<A>
+    where
+        A: Ord,
+    {
         self.next()
     }
 
     #[inline]
-    fn max(mut self) -> Option<A> {
+    fn max(mut self) -> Option<A>
+    where
+        A: Ord,
+    {
         self.next_back()
     }
 
diff --git a/library/portable-simd/crates/core_simd/src/ops/deref.rs b/library/portable-simd/crates/core_simd/src/ops/deref.rs
index 9883a74c92d..302bf148bd3 100644
--- a/library/portable-simd/crates/core_simd/src/ops/deref.rs
+++ b/library/portable-simd/crates/core_simd/src/ops/deref.rs
@@ -71,7 +71,7 @@ macro_rules! deref_ops {
 
                 #[inline]
                 #[must_use = "operator returns a new vector without mutating the inputs"]
-                fn $call(self, rhs: &$simd) -> Self::Output {
+                fn $call(self, rhs: &'rhs $simd) -> Self::Output {
                     (*self).$call(*rhs)
                 }
             }
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 9c6c917ac4a..ff261ab9832 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -19,7 +19,10 @@ try:
 except ImportError:
     lzma = None
 
-if sys.platform == 'win32':
+def platform_is_win32():
+    return sys.platform == 'win32'
+
+if platform_is_win32():
     EXE_SUFFIX = ".exe"
 else:
     EXE_SUFFIX = ""
@@ -78,7 +81,6 @@ def _download(path, url, probably_big, verbose, exception):
     if probably_big or verbose:
         print("downloading {}".format(url))
 
-    platform_is_win32 = sys.platform == 'win32'
     try:
         if probably_big or verbose:
             option = "-#"
@@ -86,7 +88,7 @@ def _download(path, url, probably_big, verbose, exception):
             option = "-s"
         # If curl is not present on Win32, we should not sys.exit
         #   but raise `CalledProcessError` or `OSError` instead
-        require(["curl", "--version"], exception=platform_is_win32)
+        require(["curl", "--version"], exception=platform_is_win32())
         with open(path, "wb") as outfile:
             run(["curl", option,
                 "-L", # Follow redirect.
@@ -99,8 +101,8 @@ def _download(path, url, probably_big, verbose, exception):
             )
     except (subprocess.CalledProcessError, OSError, RuntimeError):
         # see http://serverfault.com/questions/301128/how-to-download
-        if platform_is_win32:
-            run(["PowerShell.exe", "/nologo", "-Command",
+        if platform_is_win32():
+            run_powershell([
                  "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
                  "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)],
                 verbose=verbose,
@@ -174,6 +176,10 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
         else:
             sys.exit(err)
 
+def run_powershell(script, *args, **kwargs):
+    """Run a powershell script"""
+    run(["PowerShell.exe", "/nologo", "-Command"] + script, *args, **kwargs)
+
 
 def require(cmd, exit=True, exception=False):
     '''Run a command, returning its output.
@@ -229,7 +235,7 @@ def default_build_triple(verbose):
                 print("pre-installed rustc not detected: {}".format(e))
                 print("falling back to auto-detect")
 
-    required = sys.platform != 'win32'
+    required = not platform_is_win32()
     ostype = require(["uname", "-s"], exit=required)
     cputype = require(['uname', '-m'], exit=required)
 
@@ -434,6 +440,23 @@ class RustBuild(object):
                 (not os.path.exists(self.rustc()) or
                  self.program_out_of_date(self.rustc_stamp(), key)):
             if os.path.exists(bin_root):
+                # HACK: On Windows, we can't delete rust-analyzer-proc-macro-server while it's
+                # running. Kill it.
+                if platform_is_win32():
+                    print("Killing rust-analyzer-proc-macro-srv before deleting stage0 toolchain")
+                    regex =  '{}\\\\(host|{})\\\\stage0\\\\libexec'.format(
+                        os.path.basename(self.build_dir),
+                        self.build
+                    )
+                    script = (
+                        # NOTE: can't use `taskkill` or `Get-Process -Name` because they error if
+                        # the server isn't running.
+                        'Get-Process | ' +
+                        'Where-Object {$_.Name -eq "rust-analyzer-proc-macro-srv"} |' +
+                        'Where-Object {{$_.Path -match "{}"}} |'.format(regex) +
+                        'Stop-Process'
+                    )
+                    run_powershell([script])
                 shutil.rmtree(bin_root)
             tarball_suffix = '.tar.gz' if lzma is None else '.tar.xz'
             filename = "rust-std-{}-{}{}".format(
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 0d2d512b4b2..d9d4685dfc7 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -634,6 +634,14 @@ impl Kind {
             Kind::Suggest => "suggest",
         }
     }
+
+    pub fn test_description(&self) -> &'static str {
+        match self {
+            Kind::Test => "Testing",
+            Kind::Bench => "Benchmarking",
+            _ => panic!("not a test command: {}!", self.as_str()),
+        }
+    }
 }
 
 impl<'a> Builder<'a> {
@@ -695,7 +703,6 @@ impl<'a> Builder<'a> {
                 crate::toolstate::ToolStateCheck,
                 test::ExpandYamlAnchors,
                 test::Tidy,
-                test::TidySelfTest,
                 test::Ui,
                 test::RunPassValgrind,
                 test::MirOpt,
@@ -711,11 +718,9 @@ impl<'a> Builder<'a> {
                 test::CrateLibrustc,
                 test::CrateRustdoc,
                 test::CrateRustdocJsonTypes,
-                test::CrateJsonDocLint,
-                test::SuggestTestsCrate,
+                test::CrateBootstrap,
                 test::Linkcheck,
                 test::TierCheck,
-                test::ReplacePlaceholderTest,
                 test::Cargotest,
                 test::Cargo,
                 test::RustAnalyzer,
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 3574f11189e..72ac46b6bfd 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -578,7 +578,6 @@ mod dist {
                 compiler: Compiler { host, stage: 0 },
                 target: host,
                 mode: Mode::Std,
-                test_kind: test::TestKind::Test,
                 crates: vec![INTERNER.intern_str("std")],
             },]
         );
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 14e1328171b..59d2e9cc69e 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -246,6 +246,7 @@ struct Crate {
     name: Interned<String>,
     deps: HashSet<Interned<String>>,
     path: PathBuf,
+    has_lib: bool,
 }
 
 impl Crate {
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs
index 597aefadcfe..8f2c3faca3a 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/metadata.rs
@@ -5,7 +5,7 @@ use serde_derive::Deserialize;
 
 use crate::cache::INTERNER;
 use crate::util::output;
-use crate::{Build, Crate};
+use crate::{t, Build, Crate};
 
 /// For more information, see the output of
 /// <https://doc.rust-lang.org/nightly/cargo/commands/cargo-metadata.html>
@@ -22,6 +22,7 @@ struct Package {
     source: Option<String>,
     manifest_path: String,
     dependencies: Vec<Dependency>,
+    targets: Vec<Target>,
 }
 
 /// For more information, see the output of
@@ -32,6 +33,11 @@ struct Dependency {
     source: Option<String>,
 }
 
+#[derive(Debug, Deserialize)]
+struct Target {
+    kind: Vec<String>,
+}
+
 /// Collects and stores package metadata of each workspace members into `build`,
 /// by executing `cargo metadata` commands.
 pub fn build(build: &mut Build) {
@@ -46,11 +52,16 @@ pub fn build(build: &mut Build) {
                 .filter(|dep| dep.source.is_none())
                 .map(|dep| INTERNER.intern_string(dep.name))
                 .collect();
-            let krate = Crate { name, deps, path };
+            let has_lib = package.targets.iter().any(|t| t.kind.iter().any(|k| k == "lib"));
+            let krate = Crate { name, deps, path, has_lib };
             let relative_path = krate.local_path(build);
             build.crates.insert(name, krate);
             let existing_path = build.crate_paths.insert(relative_path, name);
-            assert!(existing_path.is_none(), "multiple crates with the same path");
+            assert!(
+                existing_path.is_none(),
+                "multiple crates with the same path: {}",
+                existing_path.unwrap()
+            );
         }
     }
 }
@@ -60,7 +71,7 @@ pub fn build(build: &mut Build) {
 /// Note that `src/tools/cargo` is no longer a workspace member but we still
 /// treat it as one here, by invoking an additional `cargo metadata` command.
 fn workspace_members(build: &Build) -> impl Iterator<Item = Package> {
-    let cmd_metadata = |manifest_path| {
+    let collect_metadata = |manifest_path| {
         let mut cargo = Command::new(&build.initial_cargo);
         cargo
             .arg("metadata")
@@ -68,21 +79,20 @@ fn workspace_members(build: &Build) -> impl Iterator<Item = Package> {
             .arg("1")
             .arg("--no-deps")
             .arg("--manifest-path")
-            .arg(manifest_path);
-        cargo
+            .arg(build.src.join(manifest_path));
+        let metadata_output = output(&mut cargo);
+        let Output { packages, .. } = t!(serde_json::from_str(&metadata_output));
+        packages
     };
 
-    // Collects `metadata.packages` from the root workspace.
-    let root_manifest_path = build.src.join("Cargo.toml");
-    let root_output = output(&mut cmd_metadata(&root_manifest_path));
-    let Output { packages, .. } = serde_json::from_str(&root_output).unwrap();
-
-    // Collects `metadata.packages` from src/tools/cargo separately.
-    let cargo_manifest_path = build.src.join("src/tools/cargo/Cargo.toml");
-    let cargo_output = output(&mut cmd_metadata(&cargo_manifest_path));
-    let Output { packages: cargo_packages, .. } = serde_json::from_str(&cargo_output).unwrap();
+    // Collects `metadata.packages` from all workspaces.
+    let packages = collect_metadata("Cargo.toml");
+    let cargo_packages = collect_metadata("src/tools/cargo/Cargo.toml");
+    let ra_packages = collect_metadata("src/tools/rust-analyzer/Cargo.toml");
+    let bootstrap_packages = collect_metadata("src/bootstrap/Cargo.toml");
 
     // We only care about the root package from `src/tool/cargo` workspace.
     let cargo_package = cargo_packages.into_iter().find(|pkg| pkg.name == "cargo").into_iter();
-    packages.into_iter().chain(cargo_package)
+
+    packages.into_iter().chain(cargo_package).chain(ra_packages).chain(bootstrap_packages)
 }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 601351ea8e3..aee84e9c9be 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -13,6 +13,7 @@ use std::process::{Command, Stdio};
 use crate::builder::crate_description;
 use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::Interned;
+use crate::cache::INTERNER;
 use crate::compile;
 use crate::config::TargetSelection;
 use crate::dist;
@@ -27,44 +28,6 @@ use crate::{envify, CLang, DocTests, GitRepo, Mode};
 
 const ADB_TEST_DIR: &str = "/data/local/tmp/work";
 
-/// The two modes of the test runner; tests or benchmarks.
-#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
-pub enum TestKind {
-    /// Run `cargo test`.
-    Test,
-    /// Run `cargo bench`.
-    Bench,
-}
-
-impl From<Kind> for TestKind {
-    fn from(kind: Kind) -> Self {
-        match kind {
-            Kind::Test => TestKind::Test,
-            Kind::Bench => TestKind::Bench,
-            _ => panic!("unexpected kind in crate: {:?}", kind),
-        }
-    }
-}
-
-impl TestKind {
-    // Return the cargo subcommand for this test kind
-    fn subcommand(self) -> &'static str {
-        match self {
-            TestKind::Test => "test",
-            TestKind::Bench => "bench",
-        }
-    }
-}
-
-impl Into<Kind> for TestKind {
-    fn into(self) -> Kind {
-        match self {
-            TestKind::Test => Kind::Test,
-            TestKind::Bench => Kind::Bench,
-        }
-    }
-}
-
 fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool {
     if !builder.fail_fast {
         if !builder.try_run(cmd) {
@@ -92,26 +55,37 @@ fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool {
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct CrateJsonDocLint {
+pub struct CrateBootstrap {
+    path: Interned<PathBuf>,
     host: TargetSelection,
 }
 
-impl Step for CrateJsonDocLint {
+impl Step for CrateBootstrap {
     type Output = ();
     const ONLY_HOSTS: bool = true;
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         run.path("src/tools/jsondoclint")
+            .path("src/tools/suggest-tests")
+            .path("src/tools/replace-version-placeholder")
+            .alias("tidyselftest")
     }
 
     fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(CrateJsonDocLint { host: run.target });
+        for path in run.paths {
+            let path = INTERNER.intern_path(path.assert_single_path().path.clone());
+            run.builder.ensure(CrateBootstrap { host: run.target, path });
+        }
     }
 
     fn run(self, builder: &Builder<'_>) {
         let bootstrap_host = builder.config.build;
         let compiler = builder.compiler(0, bootstrap_host);
+        let mut path = self.path.to_str().unwrap();
+        if path == "tidyselftest" {
+            path = "src/tools/tidy";
+        }
 
         let cargo = tool::prepare_tool_cargo(
             builder,
@@ -119,47 +93,18 @@ impl Step for CrateJsonDocLint {
             Mode::ToolBootstrap,
             bootstrap_host,
             "test",
-            "src/tools/jsondoclint",
+            path,
             SourceType::InTree,
             &[],
         );
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct SuggestTestsCrate {
-    host: TargetSelection,
-}
-
-impl Step for SuggestTestsCrate {
-    type Output = ();
-    const ONLY_HOSTS: bool = true;
-    const DEFAULT: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/tools/suggest-tests")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(SuggestTestsCrate { host: run.target });
-    }
-
-    fn run(self, builder: &Builder<'_>) {
-        let bootstrap_host = builder.config.build;
-        let compiler = builder.compiler(0, bootstrap_host);
-
-        let suggest_tests = tool::prepare_tool_cargo(
-            builder,
-            compiler,
-            Mode::ToolBootstrap,
+        builder.info(&format!(
+            "{} {} stage0 ({})",
+            builder.kind.test_description(),
+            path,
             bootstrap_host,
-            "test",
-            "src/tools/suggest-tests",
-            SourceType::InTree,
-            &[],
-        );
-        add_flags_and_try_run_tests(builder, &mut suggest_tests.into());
+        ));
+        let crate_name = path.rsplit_once('/').unwrap().1;
+        run_cargo_test(cargo, &[], &[], crate_name, compiler, bootstrap_host, builder);
     }
 }
 
@@ -208,7 +153,11 @@ You can skip linkcheck with --exclude src/tools/linkchecker"
             SourceType::InTree,
             &[],
         );
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
+        run_cargo_test(cargo, &[], &[], "linkchecker", compiler, bootstrap_host, builder);
+
+        if builder.doc_tests == DocTests::No {
+            return;
+        }
 
         // Build all the default documentation.
         builder.default_doc(&[]);
@@ -344,7 +293,7 @@ impl Step for Cargo {
         let compiler = builder.compiler(self.stage, self.host);
 
         builder.ensure(tool::Cargo { compiler, target: self.host });
-        let mut cargo = tool::prepare_tool_cargo(
+        let cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
             Mode::ToolRustc,
@@ -355,10 +304,8 @@ impl Step for Cargo {
             &[],
         );
 
-        if !builder.fail_fast {
-            cargo.arg("--no-fail-fast");
-        }
-        cargo.arg("--").args(builder.config.cmd.test_args());
+        // NOTE: can't use `run_cargo_test` because we need to overwrite `PATH`
+        let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", compiler, self.host, builder);
 
         // Don't run cross-compile tests, we may not have cross-compiled libstd libs
         // available.
@@ -366,10 +313,10 @@ impl Step for Cargo {
         // Forcibly disable tests using nightly features since any changes to
         // those features won't be able to land.
         cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
-
         cargo.env("PATH", &path_for_cargo(builder, compiler));
 
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
+        let _time = util::timeit(&builder);
+        add_flags_and_try_run_tests(builder, &mut cargo);
     }
 }
 
@@ -426,9 +373,7 @@ impl Step for RustAnalyzer {
         cargo.env("SKIP_SLOW_TESTS", "1");
 
         cargo.add_rustc_lib_path(builder, compiler);
-        cargo.arg("--").args(builder.config.cmd.test_args());
-
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
+        run_cargo_test(cargo, &[], &[], "rust-analyzer", compiler, host, builder);
     }
 }
 
@@ -471,17 +416,13 @@ impl Step for Rustfmt {
             &[],
         );
 
-        if !builder.fail_fast {
-            cargo.arg("--no-fail-fast");
-        }
-
         let dir = testdir(builder, compiler.host);
         t!(fs::create_dir_all(&dir));
         cargo.env("RUSTFMT_TEST_DIR", dir);
 
         cargo.add_rustc_lib_path(builder, compiler);
 
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
+        run_cargo_test(cargo, &[], &[], "rustfmt", compiler, host, builder);
     }
 }
 
@@ -527,12 +468,9 @@ impl Step for RustDemangler {
         t!(fs::create_dir_all(&dir));
 
         cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler);
-
-        cargo.arg("--").args(builder.config.cmd.test_args());
-
         cargo.add_rustc_lib_path(builder, compiler);
 
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
+        run_cargo_test(cargo, &[], &[], "rust-demangler", compiler, host, builder);
     }
 }
 
@@ -655,10 +593,6 @@ impl Step for Miri {
         );
         cargo.add_rustc_lib_path(builder, compiler);
 
-        if !builder.fail_fast {
-            cargo.arg("--no-fail-fast");
-        }
-
         // miri tests need to know about the stage sysroot
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
         cargo.env("MIRI_HOST_SYSROOT", sysroot);
@@ -670,13 +604,14 @@ impl Step for Miri {
 
         // Set the target.
         cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
-        // Forward test filters.
-        cargo.arg("--").args(builder.config.cmd.test_args());
 
-        // This can NOT be `add_flags_and_try_run_tests` since the Miri test runner
-        // does not understand those flags!
-        let mut cargo = Command::from(cargo);
-        builder.run(&mut cargo);
+        // This can NOT be `run_cargo_test` since the Miri test runner
+        // does not understand the flags added by `add_flags_and_try_run_test`.
+        let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
+        {
+            let _time = util::timeit(&builder);
+            builder.run(&mut cargo);
+        }
 
         // # Run `cargo miri test`.
         // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures
@@ -709,6 +644,7 @@ impl Step for Miri {
         cargo.env("RUST_BACKTRACE", "1");
 
         let mut cargo = Command::from(cargo);
+        let _time = util::timeit(&builder);
         builder.run(&mut cargo);
     }
 }
@@ -748,8 +684,7 @@ impl Step for CompiletestTest {
             &[],
         );
         cargo.allow_features("test");
-
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
+        run_cargo_test(cargo, &[], &[], "compiletest", compiler, host, builder);
     }
 }
 
@@ -792,20 +727,15 @@ impl Step for Clippy {
             &[],
         );
 
-        if !builder.fail_fast {
-            cargo.arg("--no-fail-fast");
-        }
-
         cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
         cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
         let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
         cargo.env("HOST_LIBS", host_libs);
 
-        cargo.arg("--").args(builder.config.cmd.test_args());
-
         cargo.add_rustc_lib_path(builder, compiler);
+        let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
 
-        if builder.try_run(&mut cargo.into()) {
+        if builder.try_run(&mut cargo) {
             // The tests succeeded; nothing to do.
             return;
         }
@@ -1203,40 +1133,6 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy`
     }
 }
 
-/// Runs tidy's own tests.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct TidySelfTest;
-
-impl Step for TidySelfTest {
-    type Output = ();
-    const DEFAULT: bool = true;
-    const ONLY_HOSTS: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.alias("tidyselftest")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(TidySelfTest);
-    }
-
-    fn run(self, builder: &Builder<'_>) {
-        let bootstrap_host = builder.config.build;
-        let compiler = builder.compiler(0, bootstrap_host);
-        let cargo = tool::prepare_tool_cargo(
-            builder,
-            compiler,
-            Mode::ToolBootstrap,
-            bootstrap_host,
-            "test",
-            "src/tools/tidy",
-            SourceType::InTree,
-            &[],
-        );
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
-    }
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct ExpandYamlAnchors;
 
@@ -2111,7 +2007,6 @@ impl Step for RustcGuide {
 pub struct CrateLibrustc {
     compiler: Compiler,
     target: TargetSelection,
-    test_kind: TestKind,
     crates: Vec<Interned<String>>,
 }
 
@@ -2133,9 +2028,8 @@ impl Step for CrateLibrustc {
             .iter()
             .map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
             .collect();
-        let test_kind = builder.kind.into();
 
-        builder.ensure(CrateLibrustc { compiler, target: run.target, test_kind, crates });
+        builder.ensure(CrateLibrustc { compiler, target: run.target, crates });
     }
 
     fn run(self, builder: &Builder<'_>) {
@@ -2143,18 +2037,106 @@ impl Step for CrateLibrustc {
             compiler: self.compiler,
             target: self.target,
             mode: Mode::Rustc,
-            test_kind: self.test_kind,
             crates: self.crates,
         });
     }
 }
 
+/// Given a `cargo test` subcommand, add the appropriate flags and run it.
+///
+/// Returns whether the test succeeded.
+fn run_cargo_test(
+    cargo: impl Into<Command>,
+    libtest_args: &[&str],
+    crates: &[Interned<String>],
+    primary_crate: &str,
+    compiler: Compiler,
+    target: TargetSelection,
+    builder: &Builder<'_>,
+) -> bool {
+    let mut cargo =
+        prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder);
+    let _time = util::timeit(&builder);
+    add_flags_and_try_run_tests(builder, &mut cargo)
+}
+
+/// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`.
+fn prepare_cargo_test(
+    cargo: impl Into<Command>,
+    libtest_args: &[&str],
+    crates: &[Interned<String>],
+    primary_crate: &str,
+    compiler: Compiler,
+    target: TargetSelection,
+    builder: &Builder<'_>,
+) -> Command {
+    let mut cargo = cargo.into();
+
+    // Pass in some standard flags then iterate over the graph we've discovered
+    // in `cargo metadata` with the maps above and figure out what `-p`
+    // arguments need to get passed.
+    if builder.kind == Kind::Test && !builder.fail_fast {
+        cargo.arg("--no-fail-fast");
+    }
+    match builder.doc_tests {
+        DocTests::Only => {
+            cargo.arg("--doc");
+        }
+        DocTests::No => {
+            let krate = &builder
+                .crates
+                .get(&INTERNER.intern_str(primary_crate))
+                .unwrap_or_else(|| panic!("missing crate {primary_crate}"));
+            if krate.has_lib {
+                cargo.arg("--lib");
+            }
+            cargo.args(&["--bins", "--examples", "--tests", "--benches"]);
+        }
+        DocTests::Yes => {}
+    }
+
+    for &krate in crates {
+        cargo.arg("-p").arg(krate);
+    }
+
+    cargo.arg("--").args(&builder.config.cmd.test_args()).args(libtest_args);
+    if !builder.config.verbose_tests {
+        cargo.arg("--quiet");
+    }
+
+    // The tests are going to run with the *target* libraries, so we need to
+    // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
+    //
+    // Note that to run the compiler we need to run with the *host* libraries,
+    // but our wrapper scripts arrange for that to be the case anyway.
+    let mut dylib_path = dylib_path();
+    dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
+    cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
+
+    if target.contains("emscripten") {
+        cargo.env(
+            format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
+            builder.config.nodejs.as_ref().expect("nodejs not configured"),
+        );
+    } else if target.starts_with("wasm32") {
+        let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
+        let runner = format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
+        cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
+    } else if builder.remote_tested(target) {
+        cargo.env(
+            format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
+            format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
+        );
+    }
+
+    cargo
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Crate {
     pub compiler: Compiler,
     pub target: TargetSelection,
     pub mode: Mode,
-    pub test_kind: TestKind,
     pub crates: Vec<Interned<String>>,
 }
 
@@ -2170,14 +2152,13 @@ impl Step for Crate {
         let builder = run.builder;
         let host = run.build_triple();
         let compiler = builder.compiler_for(builder.top_stage, host, host);
-        let test_kind = builder.kind.into();
         let crates = run
             .paths
             .iter()
             .map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
             .collect();
 
-        builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, test_kind, crates });
+        builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, crates });
     }
 
     /// Runs all unit tests plus documentation tests for a given crate defined
@@ -2192,7 +2173,6 @@ impl Step for Crate {
         let compiler = self.compiler;
         let target = self.target;
         let mode = self.mode;
-        let test_kind = self.test_kind;
 
         builder.ensure(compile::Std::new(compiler, target));
         builder.ensure(RemoteCopyLibs { compiler, target });
@@ -2204,7 +2184,7 @@ impl Step for Crate {
         let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
 
         let mut cargo =
-            builder.cargo(compiler, mode, SourceType::InTree, target, test_kind.subcommand());
+            builder.cargo(compiler, mode, SourceType::InTree, target, builder.kind.as_str());
         match mode {
             Mode::Std => {
                 compile::std_cargo(builder, target, compiler.stage, &mut cargo);
@@ -2215,69 +2195,14 @@ impl Step for Crate {
             _ => panic!("can only test libraries"),
         };
 
-        // Build up the base `cargo test` command.
-        //
-        // Pass in some standard flags then iterate over the graph we've discovered
-        // in `cargo metadata` with the maps above and figure out what `-p`
-        // arguments need to get passed.
-        if test_kind.subcommand() == "test" && !builder.fail_fast {
-            cargo.arg("--no-fail-fast");
-        }
-        match builder.doc_tests {
-            DocTests::Only => {
-                cargo.arg("--doc");
-            }
-            DocTests::No => {
-                cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
-            }
-            DocTests::Yes => {}
-        }
-
-        for krate in &self.crates {
-            cargo.arg("-p").arg(krate);
-        }
-
-        // The tests are going to run with the *target* libraries, so we need to
-        // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
-        //
-        // Note that to run the compiler we need to run with the *host* libraries,
-        // but our wrapper scripts arrange for that to be the case anyway.
-        let mut dylib_path = dylib_path();
-        dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
-        cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
-
-        cargo.arg("--");
-        cargo.args(&builder.config.cmd.test_args());
-
-        cargo.arg("-Z").arg("unstable-options");
-        cargo.arg("--format").arg("json");
-
-        if target.contains("emscripten") {
-            cargo.env(
-                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
-                builder.config.nodejs.as_ref().expect("nodejs not configured"),
-            );
-        } else if target.starts_with("wasm32") {
-            let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
-            let runner =
-                format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
-            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
-        } else if builder.remote_tested(target) {
-            cargo.env(
-                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
-                format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
-            );
-        }
-
         let _guard = builder.msg(
-            test_kind,
+            builder.kind,
             compiler.stage,
             crate_description(&self.crates),
             compiler.host,
             target,
         );
-        let _time = util::timeit(&builder);
-        crate::render_tests::try_run_tests(builder, &mut cargo.into());
+        run_cargo_test(cargo, &[], &self.crates, &self.crates[0], compiler, target, builder);
     }
 }
 
@@ -2285,7 +2210,6 @@ impl Step for Crate {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateRustdoc {
     host: TargetSelection,
-    test_kind: TestKind,
 }
 
 impl Step for CrateRustdoc {
@@ -2300,13 +2224,10 @@ impl Step for CrateRustdoc {
     fn make_run(run: RunConfig<'_>) {
         let builder = run.builder;
 
-        let test_kind = builder.kind.into();
-
-        builder.ensure(CrateRustdoc { host: run.target, test_kind });
+        builder.ensure(CrateRustdoc { host: run.target });
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let test_kind = self.test_kind;
         let target = self.host;
 
         let compiler = if builder.download_rustc() {
@@ -2325,29 +2246,11 @@ impl Step for CrateRustdoc {
             compiler,
             Mode::ToolRustc,
             target,
-            test_kind.subcommand(),
+            builder.kind.as_str(),
             "src/tools/rustdoc",
             SourceType::InTree,
             &[],
         );
-        if test_kind.subcommand() == "test" && !builder.fail_fast {
-            cargo.arg("--no-fail-fast");
-        }
-        match builder.doc_tests {
-            DocTests::Only => {
-                cargo.arg("--doc");
-            }
-            DocTests::No => {
-                cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
-            }
-            DocTests::Yes => {}
-        }
-
-        cargo.arg("-p").arg("rustdoc:0.0.0");
-
-        cargo.arg("--");
-        cargo.args(&builder.config.cmd.test_args());
-
         if self.host.contains("musl") {
             cargo.arg("'-Ctarget-feature=-crt-static'");
         }
@@ -2387,22 +2290,22 @@ impl Step for CrateRustdoc {
         dylib_path.insert(0, PathBuf::from(&*libdir));
         cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
 
-        if !builder.config.verbose_tests {
-            cargo.arg("--quiet");
-        }
-
-        let _guard = builder.msg(test_kind, compiler.stage, "rustdoc", compiler.host, target);
-
-        let _time = util::timeit(&builder);
-
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
+        let _guard = builder.msg(builder.kind, compiler.stage, "rustdoc", compiler.host, target);
+        run_cargo_test(
+            cargo,
+            &[],
+            &[INTERNER.intern_str("rustdoc:0.0.0")],
+            "rustdoc",
+            compiler,
+            target,
+            builder,
+        );
     }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateRustdocJsonTypes {
     host: TargetSelection,
-    test_kind: TestKind,
 }
 
 impl Step for CrateRustdocJsonTypes {
@@ -2417,13 +2320,10 @@ impl Step for CrateRustdocJsonTypes {
     fn make_run(run: RunConfig<'_>) {
         let builder = run.builder;
 
-        let test_kind = builder.kind.into();
-
-        builder.ensure(CrateRustdocJsonTypes { host: run.target, test_kind });
+        builder.ensure(CrateRustdocJsonTypes { host: run.target });
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let test_kind = self.test_kind;
         let target = self.host;
 
         // Use the previous stage compiler to reuse the artifacts that are
@@ -2433,34 +2333,35 @@ impl Step for CrateRustdocJsonTypes {
         let compiler = builder.compiler_for(builder.top_stage, target, target);
         builder.ensure(compile::Rustc::new(compiler, target));
 
-        let mut cargo = tool::prepare_tool_cargo(
+        let cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
             Mode::ToolRustc,
             target,
-            test_kind.subcommand(),
+            builder.kind.as_str(),
             "src/rustdoc-json-types",
             SourceType::InTree,
             &[],
         );
-        if test_kind.subcommand() == "test" && !builder.fail_fast {
-            cargo.arg("--no-fail-fast");
-        }
-
-        cargo.arg("-p").arg("rustdoc-json-types");
-
-        cargo.arg("--");
-        cargo.args(&builder.config.cmd.test_args());
 
-        if self.host.contains("musl") {
-            cargo.arg("'-Ctarget-feature=-crt-static'");
-        }
+        // FIXME: this looks very wrong, libtest doesn't accept `-C` arguments and the quotes are fishy.
+        let libtest_args = if self.host.contains("musl") {
+            ["'-Ctarget-feature=-crt-static'"].as_slice()
+        } else {
+            &[]
+        };
 
         let _guard =
-            builder.msg(test_kind, compiler.stage, "rustdoc-json-types", compiler.host, target);
-        let _time = util::timeit(&builder);
-
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
+            builder.msg(builder.kind, compiler.stage, "rustdoc-json-types", compiler.host, target);
+        run_cargo_test(
+            cargo,
+            libtest_args,
+            &[INTERNER.intern_str("rustdoc-json-types")],
+            "rustdoc-json-types",
+            compiler,
+            target,
+            builder,
+        );
     }
 }
 
@@ -2598,13 +2499,15 @@ impl Step for Bootstrap {
         check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/"));
         try_run(builder, &mut check_bootstrap);
 
+        let host = builder.config.build;
+        let compiler = builder.compiler(0, host);
         let mut cmd = Command::new(&builder.initial_cargo);
         cmd.arg("test")
             .current_dir(builder.src.join("src/bootstrap"))
             .env("RUSTFLAGS", "-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
             .env("RUSTC_BOOTSTRAP", "1")
-            .env("RUSTDOC", builder.rustdoc(builder.compiler(0, builder.build.build)))
+            .env("RUSTDOC", builder.rustdoc(compiler))
             .env("RUSTC", &builder.initial_rustc);
         if let Some(flags) = option_env!("RUSTFLAGS") {
             // Use the same rustc flags for testing as for "normal" compilation,
@@ -2612,24 +2515,9 @@ impl Step for Bootstrap {
             // https://github.com/rust-lang/rust/issues/49215
             cmd.env("RUSTFLAGS", flags);
         }
-        if !builder.fail_fast {
-            cmd.arg("--no-fail-fast");
-        }
-        match builder.doc_tests {
-            DocTests::Only => {
-                cmd.arg("--doc");
-            }
-            DocTests::No => {
-                cmd.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
-            }
-            DocTests::Yes => {}
-        }
-
-        cmd.arg("--").args(&builder.config.cmd.test_args());
         // rustbuild tests are racy on directory creation so just run them one at a time.
         // Since there's not many this shouldn't be a problem.
-        cmd.arg("--test-threads=1");
-        add_flags_and_try_run_tests(builder, &mut cmd);
+        run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", compiler, host, builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -2686,43 +2574,6 @@ impl Step for TierCheck {
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct ReplacePlaceholderTest;
-
-impl Step for ReplacePlaceholderTest {
-    type Output = ();
-    const ONLY_HOSTS: bool = true;
-    const DEFAULT: bool = true;
-
-    /// Ensure the version placeholder replacement tool builds
-    fn run(self, builder: &Builder<'_>) {
-        builder.info("build check for version replacement placeholder");
-
-        // Test the version placeholder replacement tool itself.
-        let bootstrap_host = builder.config.build;
-        let compiler = builder.compiler(0, bootstrap_host);
-        let cargo = tool::prepare_tool_cargo(
-            builder,
-            compiler,
-            Mode::ToolBootstrap,
-            bootstrap_host,
-            "test",
-            "src/tools/replace-version-placeholder",
-            SourceType::InTree,
-            &[],
-        );
-        add_flags_and_try_run_tests(builder, &mut cargo.into());
-    }
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/tools/replace-version-placeholder")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(Self);
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct LintDocs {
     pub compiler: Compiler,
     pub target: TargetSelection,
@@ -2779,7 +2630,7 @@ impl Step for RustInstaller {
             SourceType::InTree,
             &[],
         );
-        try_run(builder, &mut cargo.into());
+        run_cargo_test(cargo, &[], &[], "installer", compiler, bootstrap_host, builder);
 
         // We currently don't support running the test.sh script outside linux(?) environments.
         // Eventually this should likely migrate to #[test]s in rust-installer proper rather than a
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 9418cf0a7ed..39f6369b4d3 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -141,7 +141,7 @@ pub fn prepare_tool_cargo(
     mode: Mode,
     target: TargetSelection,
     command: &'static str,
-    path: &'static str,
+    path: &str,
     source_type: SourceType,
     extra_features: &[String],
 ) -> CargoCommand {
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index 45db3bb9b00..fd57b079644 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -374,3 +374,41 @@ warning: this URL is not a hyperlink
 
 warning: 2 warnings emitted
 ```
+
+## `unescaped_backticks`
+
+This lint is **allowed by default**. It detects backticks (\`) that are not escaped.
+This usually means broken inline code. For example:
+
+```rust
+#![warn(rustdoc::unescaped_backticks)]
+
+/// `add(a, b) is the same as `add(b, a)`.
+pub fn add(a: i32, b: i32) -> i32 { a + b }
+```
+
+Which will give:
+
+```text
+warning: unescaped backtick
+ --> src/lib.rs:3:41
+  |
+3 | /// `add(a, b) is the same as `add(b, a)`.
+  |                                         ^
+  |
+note: the lint level is defined here
+ --> src/lib.rs:1:9
+  |
+1 | #![warn(rustdoc::unescaped_backticks)]
+  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: a previous inline code might be longer than expected
+  |
+3 | /// `add(a, b)` is the same as `add(b, a)`.
+  |               +
+help: if you meant to use a literal backtick, escape it
+  |
+3 | /// `add(a, b) is the same as `add(b, a)\`.
+  |                                         +
+
+warning: 1 warning emitted
+```
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a5f08fdac11..d90d0aecb93 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1155,10 +1155,10 @@ fn render_assoc_items_inner(
     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
     if !non_trait.is_empty() {
         let mut tmp_buf = Buffer::html();
-        let (render_mode, id) = match what {
+        let (render_mode, id, class_html) = match what {
             AssocItemRender::All => {
                 write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
-                (RenderMode::Normal, "implementations-list".to_owned())
+                (RenderMode::Normal, "implementations-list".to_owned(), "")
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
                 let id =
@@ -1175,7 +1175,11 @@ fn render_assoc_items_inner(
                     ),
                     &id,
                 );
-                (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
+                (
+                    RenderMode::ForDeref { mut_: deref_mut_ },
+                    cx.derive_id(id),
+                    r#" class="impl-items""#,
+                )
             }
         };
         let mut impls_buf = Buffer::html();
@@ -1199,7 +1203,7 @@ fn render_assoc_items_inner(
         }
         if !impls_buf.is_empty() {
             write!(w, "{}", tmp_buf.into_inner()).unwrap();
-            write!(w, "<div id=\"{}\">", id).unwrap();
+            write!(w, "<div id=\"{id}\"{class_html}>").unwrap();
             write!(w, "{}", impls_buf.into_inner()).unwrap();
             w.write_str("</div>").unwrap();
         }
@@ -1788,12 +1792,14 @@ fn render_impl(
                 .into_string()
             );
         }
+        if !default_impl_items.is_empty() || !impl_items.is_empty() {
+            w.write_str("<div class=\"impl-items\">");
+            close_tags.insert_str(0, "</div>");
+        }
     }
     if !default_impl_items.is_empty() || !impl_items.is_empty() {
-        w.write_str("<div class=\"impl-items\">");
         w.push_buffer(default_impl_items);
         w.push_buffer(impl_items);
-        close_tags.insert_str(0, "</div>");
     }
     w.write_str(&close_tags);
 }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index c15afca2261..60754130d99 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -7,14 +7,15 @@
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
+#![feature(impl_trait_in_assoc_type)]
+#![feature(iter_intersperse)]
+#![feature(lazy_cell)]
 #![feature(let_chains)]
-#![feature(test)]
 #![feature(never_type)]
-#![feature(lazy_cell)]
-#![feature(type_ascription)]
-#![feature(iter_intersperse)]
+#![feature(round_char_boundary)]
+#![feature(test)]
 #![feature(type_alias_impl_trait)]
-#![feature(impl_trait_in_assoc_type)]
+#![feature(type_ascription)]
 #![recursion_limit = "256"]
 #![warn(rustc::internal)]
 #![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index 6d289eb996d..749c1ff51bf 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -174,6 +174,17 @@ declare_rustdoc_lint! {
    "codeblock could not be parsed as valid Rust or is empty"
 }
 
+declare_rustdoc_lint! {
+   /// The `unescaped_backticks` lint detects unescaped backticks (\`), which usually
+   /// mean broken inline code. This is a `rustdoc` only lint, see the documentation
+   /// in the [rustdoc book].
+   ///
+   /// [rustdoc book]: ../../../rustdoc/lints.html#unescaped_backticks
+   UNESCAPED_BACKTICKS,
+   Allow,
+   "detects unescaped backticks in doc comments"
+}
+
 pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
     vec![
         BROKEN_INTRA_DOC_LINKS,
@@ -185,6 +196,7 @@ pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
         INVALID_HTML_TAGS,
         BARE_URLS,
         MISSING_CRATE_LEVEL_DOCS,
+        UNESCAPED_BACKTICKS,
     ]
 });
 
diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs
index 97031c4f028..e653207b9b6 100644
--- a/src/librustdoc/passes/lint.rs
+++ b/src/librustdoc/passes/lint.rs
@@ -4,6 +4,7 @@
 mod bare_urls;
 mod check_code_block_syntax;
 mod html_tags;
+mod unescaped_backticks;
 
 use super::Pass;
 use crate::clean::*;
@@ -27,6 +28,7 @@ impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> {
         bare_urls::visit_item(self.cx, item);
         check_code_block_syntax::visit_item(self.cx, item);
         html_tags::visit_item(self.cx, item);
+        unescaped_backticks::visit_item(self.cx, item);
 
         self.visit_item_recur(item)
     }
diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs
new file mode 100644
index 00000000000..33cef82a60c
--- /dev/null
+++ b/src/librustdoc/passes/lint/unescaped_backticks.rs
@@ -0,0 +1,416 @@
+//! Detects unescaped backticks (\`) in doc comments.
+
+use crate::clean::Item;
+use crate::core::DocContext;
+use crate::html::markdown::main_body_opts;
+use crate::passes::source_span_for_markdown_range;
+use pulldown_cmark::{BrokenLink, Event, Parser};
+use rustc_errors::DiagnosticBuilder;
+use rustc_lint_defs::Applicability;
+use std::ops::Range;
+
+pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
+    let tcx = cx.tcx;
+    let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else {
+        // If non-local, no need to check anything.
+        return;
+    };
+
+    let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
+    if dox.is_empty() {
+        return;
+    }
+
+    let link_names = item.link_names(&cx.cache);
+    let mut replacer = |broken_link: BrokenLink<'_>| {
+        link_names
+            .iter()
+            .find(|link| *link.original_text == *broken_link.reference)
+            .map(|link| ((*link.href).into(), (*link.new_text).into()))
+    };
+    let parser = Parser::new_with_broken_link_callback(&dox, main_body_opts(), Some(&mut replacer))
+        .into_offset_iter();
+
+    let mut element_stack = Vec::new();
+
+    let mut prev_text_end = 0;
+    for (event, event_range) in parser {
+        match event {
+            Event::Start(_) => {
+                element_stack.push(Element::new(event_range));
+            }
+            Event::End(_) => {
+                let element = element_stack.pop().unwrap();
+
+                let Some(backtick_index) = element.backtick_index else {
+                    continue;
+                };
+
+                // If we can't get a span of the backtick, because it is in a `#[doc = ""]` attribute,
+                // use the span of the entire attribute as a fallback.
+                let span = source_span_for_markdown_range(
+                    tcx,
+                    &dox,
+                    &(backtick_index..backtick_index + 1),
+                    &item.attrs,
+                )
+                .unwrap_or_else(|| item.attr_span(tcx));
+
+                cx.tcx.struct_span_lint_hir(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| {
+                    let mut help_emitted = false;
+
+                    match element.prev_code_guess {
+                        PrevCodeGuess::None => {}
+                        PrevCodeGuess::Start { guess, .. } => {
+                            // "foo` `bar`" -> "`foo` `bar`"
+                            if let Some(suggest_index) = clamp_start(guess, &element.suggestible_ranges)
+                                && can_suggest_backtick(&dox, suggest_index)
+                            {
+                                suggest_insertion(cx, item, &dox, lint, suggest_index, '`', "the opening backtick of a previous inline code may be missing");
+                                help_emitted = true;
+                            }
+                        }
+                        PrevCodeGuess::End { guess, .. } => {
+                            // "`foo `bar`" -> "`foo` `bar`"
+                            // Don't `clamp_end` here, because the suggestion is guaranteed to be inside
+                            // an inline code node and we intentionally "break" the inline code here.
+                            let suggest_index = guess;
+                            if can_suggest_backtick(&dox, suggest_index) {
+                                suggest_insertion(cx, item, &dox, lint, suggest_index, '`', "a previous inline code might be longer than expected");
+                                help_emitted = true;
+                            }
+                        }
+                    }
+
+                    if !element.prev_code_guess.is_confident() {
+                        // "`foo` bar`" -> "`foo` `bar`"
+                        if let Some(guess) = guess_start_of_code(&dox, element.element_range.start..backtick_index)
+                            && let Some(suggest_index) = clamp_start(guess, &element.suggestible_ranges)
+                            && can_suggest_backtick(&dox, suggest_index)
+                        {
+                            suggest_insertion(cx, item, &dox, lint, suggest_index, '`', "the opening backtick of an inline code may be missing");
+                            help_emitted = true;
+                        }
+
+                        // "`foo` `bar" -> "`foo` `bar`"
+                        // Don't suggest closing backtick after single trailing char,
+                        // if we already suggested opening backtick. For example:
+                        // "foo`." -> "`foo`." or "foo`s" -> "`foo`s".
+                        if let Some(guess) = guess_end_of_code(&dox, backtick_index + 1..element.element_range.end)
+                            && let Some(suggest_index) = clamp_end(guess, &element.suggestible_ranges)
+                            && can_suggest_backtick(&dox, suggest_index)
+                            && (!help_emitted || suggest_index - backtick_index > 2)
+                        {
+                            suggest_insertion(cx, item, &dox, lint, suggest_index, '`', "the closing backtick of an inline code may be missing");
+                            help_emitted = true;
+                        }
+                    }
+
+                    if !help_emitted {
+                        lint.help("the opening or closing backtick of an inline code may be missing");
+                    }
+
+                    suggest_insertion(cx, item, &dox, lint, backtick_index, '\\', "if you meant to use a literal backtick, escape it");
+
+                    lint
+                });
+            }
+            Event::Code(_) => {
+                let element = element_stack
+                    .last_mut()
+                    .expect("expected inline code node to be inside of an element");
+                assert!(
+                    event_range.start >= element.element_range.start
+                        && event_range.end <= element.element_range.end
+                );
+
+                // This inline code might be longer than it's supposed to be.
+                // Only check single backtick inline code for now.
+                if !element.prev_code_guess.is_confident()
+                    && dox.as_bytes().get(event_range.start) == Some(&b'`')
+                    && dox.as_bytes().get(event_range.start + 1) != Some(&b'`')
+                {
+                    let range_inside = event_range.start + 1..event_range.end - 1;
+                    let text_inside = &dox[range_inside.clone()];
+
+                    let is_confident = text_inside.starts_with(char::is_whitespace)
+                        || text_inside.ends_with(char::is_whitespace);
+
+                    if let Some(guess) = guess_end_of_code(&dox, range_inside) {
+                        // Find earlier end of code.
+                        element.prev_code_guess = PrevCodeGuess::End { guess, is_confident };
+                    } else {
+                        // Find alternate start of code.
+                        let range_before = element.element_range.start..event_range.start;
+                        if let Some(guess) = guess_start_of_code(&dox, range_before) {
+                            element.prev_code_guess = PrevCodeGuess::Start { guess, is_confident };
+                        }
+                    }
+                }
+            }
+            Event::Text(text) => {
+                let element = element_stack
+                    .last_mut()
+                    .expect("expected inline text node to be inside of an element");
+                assert!(
+                    event_range.start >= element.element_range.start
+                        && event_range.end <= element.element_range.end
+                );
+
+                // The first char is escaped if the prev char is \ and not part of a text node.
+                let is_escaped = prev_text_end < event_range.start
+                    && dox.as_bytes()[event_range.start - 1] == b'\\';
+
+                // Don't lint backslash-escaped (\`) or html-escaped (&#96;) backticks.
+                if *text == *"`" && !is_escaped && *text == dox[event_range.clone()] {
+                    // We found a stray backtick.
+                    assert!(
+                        element.backtick_index.is_none(),
+                        "expected at most one unescaped backtick per element",
+                    );
+                    element.backtick_index = Some(event_range.start);
+                }
+
+                prev_text_end = event_range.end;
+
+                if is_escaped {
+                    // Ensure that we suggest "`\x" and not "\`x".
+                    element.suggestible_ranges.push(event_range.start - 1..event_range.end);
+                } else {
+                    element.suggestible_ranges.push(event_range);
+                }
+            }
+            _ => {}
+        }
+    }
+}
+
+/// A previous inline code node, that looks wrong.
+///
+/// `guess` is the position, where we want to suggest a \` and the guess `is_confident` if an
+/// inline code starts or ends with a whitespace.
+#[derive(Debug)]
+enum PrevCodeGuess {
+    None,
+
+    /// Missing \` at start.
+    ///
+    /// ```markdown
+    /// foo` `bar`
+    /// ```
+    Start {
+        guess: usize,
+        is_confident: bool,
+    },
+
+    /// Missing \` at end.
+    ///
+    /// ```markdown
+    /// `foo `bar`
+    /// ```
+    End {
+        guess: usize,
+        is_confident: bool,
+    },
+}
+
+impl PrevCodeGuess {
+    fn is_confident(&self) -> bool {
+        match *self {
+            PrevCodeGuess::None => false,
+            PrevCodeGuess::Start { is_confident, .. } | PrevCodeGuess::End { is_confident, .. } => {
+                is_confident
+            }
+        }
+    }
+}
+
+/// A markdown [tagged element], which may or may not contain an unescaped backtick.
+///
+/// [tagged element]: https://docs.rs/pulldown-cmark/0.9/pulldown_cmark/enum.Tag.html
+#[derive(Debug)]
+struct Element {
+    /// The full range (span) of the element in the doc string.
+    element_range: Range<usize>,
+
+    /// The ranges where we're allowed to put backticks.
+    /// This is used to prevent breaking markdown elements like links or lists.
+    suggestible_ranges: Vec<Range<usize>>,
+
+    /// The unescaped backtick.
+    backtick_index: Option<usize>,
+
+    /// Suggest a different start or end of an inline code.
+    prev_code_guess: PrevCodeGuess,
+}
+
+impl Element {
+    const fn new(element_range: Range<usize>) -> Self {
+        Self {
+            element_range,
+            suggestible_ranges: Vec::new(),
+            backtick_index: None,
+            prev_code_guess: PrevCodeGuess::None,
+        }
+    }
+}
+
+/// Given a potentially unclosed inline code, attempt to find the start.
+fn guess_start_of_code(dox: &str, range: Range<usize>) -> Option<usize> {
+    assert!(dox.as_bytes()[range.end] == b'`');
+
+    let mut braces = 0;
+    let mut guess = 0;
+    for (idx, ch) in dox[range.clone()].char_indices().rev() {
+        match ch {
+            ')' | ']' | '}' => braces += 1,
+            '(' | '[' | '{' => {
+                if braces == 0 {
+                    guess = idx + 1;
+                    break;
+                }
+                braces -= 1;
+            }
+            ch if ch.is_whitespace() && braces == 0 => {
+                guess = idx + 1;
+                break;
+            }
+            _ => (),
+        }
+    }
+
+    guess += range.start;
+
+    // Don't suggest empty inline code or duplicate backticks.
+    can_suggest_backtick(dox, guess).then_some(guess)
+}
+
+/// Given a potentially unclosed inline code, attempt to find the end.
+fn guess_end_of_code(dox: &str, range: Range<usize>) -> Option<usize> {
+    // Punctuation that should be outside of the inline code.
+    const TRAILING_PUNCTUATION: &[u8] = b".,";
+
+    assert!(dox.as_bytes()[range.start - 1] == b'`');
+
+    let text = dox[range.clone()].trim_end();
+    let mut braces = 0;
+    let mut guess = text.len();
+    for (idx, ch) in text.char_indices() {
+        match ch {
+            '(' | '[' | '{' => braces += 1,
+            ')' | ']' | '}' => {
+                if braces == 0 {
+                    guess = idx;
+                    break;
+                }
+                braces -= 1;
+            }
+            ch if ch.is_whitespace() && braces == 0 => {
+                guess = idx;
+                break;
+            }
+            _ => (),
+        }
+    }
+
+    // Strip a single trailing punctuation.
+    if guess >= 1
+        && TRAILING_PUNCTUATION.contains(&text.as_bytes()[guess - 1])
+        && (guess < 2 || !TRAILING_PUNCTUATION.contains(&text.as_bytes()[guess - 2]))
+    {
+        guess -= 1;
+    }
+
+    guess += range.start;
+
+    // Don't suggest empty inline code or duplicate backticks.
+    can_suggest_backtick(dox, guess).then_some(guess)
+}
+
+/// Returns whether inserting a backtick at `dox[index]` will not produce double backticks.
+fn can_suggest_backtick(dox: &str, index: usize) -> bool {
+    (index == 0 || dox.as_bytes()[index - 1] != b'`')
+        && (index == dox.len() || dox.as_bytes()[index] != b'`')
+}
+
+/// Increase the index until it is inside or one past the end of one of the ranges.
+///
+/// The ranges must be sorted for this to work correctly.
+fn clamp_start(index: usize, ranges: &[Range<usize>]) -> Option<usize> {
+    for range in ranges {
+        if range.start >= index {
+            return Some(range.start);
+        }
+        if index <= range.end {
+            return Some(index);
+        }
+    }
+    None
+}
+
+/// Decrease the index until it is inside or one past the end of one of the ranges.
+///
+/// The ranges must be sorted for this to work correctly.
+fn clamp_end(index: usize, ranges: &[Range<usize>]) -> Option<usize> {
+    for range in ranges.iter().rev() {
+        if range.end <= index {
+            return Some(range.end);
+        }
+        if index >= range.start {
+            return Some(index);
+        }
+    }
+    None
+}
+
+/// Try to emit a span suggestion and fall back to help messages if we can't find a suitable span.
+///
+/// This helps finding backticks in huge macro-generated docs.
+fn suggest_insertion(
+    cx: &DocContext<'_>,
+    item: &Item,
+    dox: &str,
+    lint: &mut DiagnosticBuilder<'_, ()>,
+    insert_index: usize,
+    suggestion: char,
+    message: &str,
+) {
+    /// Maximum bytes of context to show around the insertion.
+    const CONTEXT_MAX_LEN: usize = 80;
+
+    if let Some(span) =
+        source_span_for_markdown_range(cx.tcx, &dox, &(insert_index..insert_index), &item.attrs)
+    {
+        lint.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
+    } else {
+        let line_start = dox[..insert_index].rfind('\n').map_or(0, |idx| idx + 1);
+        let line_end = dox[insert_index..].find('\n').map_or(dox.len(), |idx| idx + insert_index);
+
+        let context_before_max_len = if insert_index - line_start < CONTEXT_MAX_LEN / 2 {
+            insert_index - line_start
+        } else if line_end - insert_index < CONTEXT_MAX_LEN / 2 {
+            CONTEXT_MAX_LEN - (line_end - insert_index)
+        } else {
+            CONTEXT_MAX_LEN / 2
+        };
+        let context_after_max_len = CONTEXT_MAX_LEN - context_before_max_len;
+
+        let (prefix, context_start) = if insert_index - line_start <= context_before_max_len {
+            ("", line_start)
+        } else {
+            ("...", dox.ceil_char_boundary(insert_index - context_before_max_len))
+        };
+        let (suffix, context_end) = if line_end - insert_index <= context_after_max_len {
+            ("", line_end)
+        } else {
+            ("...", dox.floor_char_boundary(insert_index + context_after_max_len))
+        };
+
+        let context_full = &dox[context_start..context_end].trim_end();
+        let context_before = &dox[context_start..insert_index];
+        let context_after = &dox[insert_index..context_end].trim_end();
+        lint.help(format!(
+            "{message}\n change: {prefix}{context_full}{suffix}\nto this: {prefix}{context_before}{suggestion}{context_after}{suffix}"
+        ));
+    }
+}
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 01da5981015..8cc935e54d1 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -90,6 +90,9 @@ pub struct TestProps {
     pub unset_rustc_env: Vec<String>,
     // Environment settings to use during execution
     pub exec_env: Vec<(String, String)>,
+    // Environment variables to unset prior to execution.
+    // Variables are unset before applying 'exec_env'
+    pub unset_exec_env: Vec<String>,
     // Build documentation for all specified aux-builds as well
     pub build_aux_docs: bool,
     // Flag to force a crate to be built with the host architecture
@@ -198,6 +201,7 @@ mod directives {
     pub const AUX_CRATE: &'static str = "aux-crate";
     pub const EXEC_ENV: &'static str = "exec-env";
     pub const RUSTC_ENV: &'static str = "rustc-env";
+    pub const UNSET_EXEC_ENV: &'static str = "unset-exec-env";
     pub const UNSET_RUSTC_ENV: &'static str = "unset-rustc-env";
     pub const FORBID_OUTPUT: &'static str = "forbid-output";
     pub const CHECK_TEST_LINE_NUMBERS_MATCH: &'static str = "check-test-line-numbers-match";
@@ -231,6 +235,7 @@ impl TestProps {
             rustc_env: vec![],
             unset_rustc_env: vec![],
             exec_env: vec![],
+            unset_exec_env: vec![],
             build_aux_docs: false,
             force_host: false,
             check_stdout: false,
@@ -384,6 +389,12 @@ impl TestProps {
                 );
                 config.push_name_value_directive(
                     ln,
+                    UNSET_EXEC_ENV,
+                    &mut self.unset_exec_env,
+                    |r| r,
+                );
+                config.push_name_value_directive(
+                    ln,
                     RUSTC_ENV,
                     &mut self.rustc_env,
                     Config::parse_env,
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index a9694d4d52c..86a749b935d 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -165,11 +165,15 @@ pub(super) fn parse_cfg_name_directive<'a>(
         message: "when the architecture is part of the Thumb family"
     }
 
+    // Technically the locally built compiler uses the "dev" channel rather than the "nightly"
+    // channel, even though most people don't know or won't care about it. To avoid confusion, we
+    // treat the "dev" channel as the "nightly" channel when processing the directive.
     condition! {
-        name: &config.channel,
+        name: if config.channel == "dev" { "nightly" } else { &config.channel },
         allowed_names: &["stable", "beta", "nightly"],
         message: "when the release channel is {name}",
     }
+
     condition! {
         name: "cross-compile",
         condition: config.target != config.host,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index e03a73c4e71..0fd9f3ae3f4 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1614,8 +1614,13 @@ impl<'test> TestCx<'test> {
                 test_client
                     .args(&["run", &support_libs.len().to_string(), &prog])
                     .args(support_libs)
-                    .args(args)
-                    .envs(env.clone());
+                    .args(args);
+
+                for key in &self.props.unset_exec_env {
+                    test_client.env_remove(key);
+                }
+                test_client.envs(env.clone());
+
                 self.compose_and_run(
                     test_client,
                     self.config.run_lib_path.to_str().unwrap(),
@@ -1627,7 +1632,13 @@ impl<'test> TestCx<'test> {
                 let aux_dir = self.aux_output_dir_name();
                 let ProcArgs { prog, args } = self.make_run_args();
                 let mut wr_run = Command::new("wr-run");
-                wr_run.args(&[&prog]).args(args).envs(env.clone());
+                wr_run.args(&[&prog]).args(args);
+
+                for key in &self.props.unset_exec_env {
+                    wr_run.env_remove(key);
+                }
+                wr_run.envs(env.clone());
+
                 self.compose_and_run(
                     wr_run,
                     self.config.run_lib_path.to_str().unwrap(),
@@ -1639,7 +1650,13 @@ impl<'test> TestCx<'test> {
                 let aux_dir = self.aux_output_dir_name();
                 let ProcArgs { prog, args } = self.make_run_args();
                 let mut program = Command::new(&prog);
-                program.args(args).current_dir(&self.output_base_dir()).envs(env.clone());
+                program.args(args).current_dir(&self.output_base_dir());
+
+                for key in &self.props.unset_exec_env {
+                    program.env_remove(key);
+                }
+                program.envs(env.clone());
+
                 self.compose_and_run(
                     program,
                     self.config.run_lib_path.to_str().unwrap(),
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 411cbc760e0..baef4bb0140 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -283,7 +283,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
 const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "ahash",
     "anyhow",
-    "arrayvec",
     "autocfg",
     "bumpalo",
     "bitflags",
@@ -303,7 +302,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "crc32fast",
     "fallible-iterator",
     "fxhash",
-    "getrandom",
     "gimli",
     "hashbrown",
     "indexmap",
@@ -321,19 +319,11 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "stable_deref_trait",
     "target-lexicon",
     "version_check",
-    "wasi",
     "wasmtime-jit-icache-coherence",
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-x86_64-pc-windows-gnu",
     "windows-sys",
-    "windows_aarch64_gnullvm",
-    "windows_aarch64_msvc",
-    "windows_i686_gnu",
-    "windows_i686_msvc",
-    "windows_x86_64_gnu",
-    "windows_x86_64_gnullvm",
-    "windows_x86_64_msvc",
 ];
 
 /// Dependency checks.
diff --git a/tests/codegen/issues/issue-103840.rs b/tests/codegen/issues/issue-103840.rs
index f19d7031bb3..da64692d27d 100644
--- a/tests/codegen/issues/issue-103840.rs
+++ b/tests/codegen/issues/issue-103840.rs
@@ -1,4 +1,5 @@
 // compile-flags: -O
+// min-llvm-version: 16.0
 #![crate_type = "lib"]
 
 pub fn foo(t: &mut Vec<usize>) {
diff --git a/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs
index d54ac9e33bc..2ee4d7cca0e 100644
--- a/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs
+++ b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs
@@ -19,4 +19,5 @@ pub fn outer_function(x: S, y: S) -> usize {
 // CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]]
 // CHECK-NOT: [[load:%.*]] = load ptr, ptr
 // CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]])
-// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[spill]], ptr {{align .*}} %x
+// CHECK: [[inner:%.*]] = getelementptr inbounds %"{{.*}}", ptr [[spill]]
+// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[inner]], ptr {{align .*}} %x
diff --git a/tests/codegen/issues/issue-86106.rs b/tests/codegen/issues/issue-86106.rs
index 9ccbcb24f56..c0be7fab2f3 100644
--- a/tests/codegen/issues/issue-86106.rs
+++ b/tests/codegen/issues/issue-86106.rs
@@ -1,4 +1,5 @@
 // min-llvm-version: 15.0
+// only-64bit llvm appears to use stores instead of memset on 32bit
 // compile-flags: -C opt-level=3 -Z merge-functions=disabled
 
 // The below two functions ensure that both `String::new()` and `"".to_string()`
@@ -9,12 +10,9 @@
 // CHECK-LABEL: define void @string_new
 #[no_mangle]
 pub fn string_new() -> String {
-    // CHECK-NOT: load i8
-    // CHECK: store i{{32|64}}
+    // CHECK: store ptr inttoptr
     // CHECK-NEXT: getelementptr
-    // CHECK-NEXT: store ptr
-    // CHECK-NEXT: getelementptr
-    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: call void @llvm.memset
     // CHECK-NEXT: ret void
     String::new()
 }
@@ -22,12 +20,9 @@ pub fn string_new() -> String {
 // CHECK-LABEL: define void @empty_to_string
 #[no_mangle]
 pub fn empty_to_string() -> String {
-    // CHECK-NOT: load i8
-    // CHECK: store i{{32|64}}
-    // CHECK-NEXT: getelementptr
-    // CHECK-NEXT: store ptr
+    // CHECK: store ptr inttoptr
     // CHECK-NEXT: getelementptr
-    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: call void @llvm.memset
     // CHECK-NEXT: ret void
     "".to_string()
 }
@@ -38,12 +33,9 @@ pub fn empty_to_string() -> String {
 // CHECK-LABEL: @empty_vec
 #[no_mangle]
 pub fn empty_vec() -> Vec<u8> {
-    // CHECK: store i{{32|64}}
-    // CHECK-NOT: load i8
+    // CHECK: store ptr inttoptr
     // CHECK-NEXT: getelementptr
-    // CHECK-NEXT: store ptr
-    // CHECK-NEXT: getelementptr
-    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: call void @llvm.memset
     // CHECK-NEXT: ret void
     vec![]
 }
@@ -51,12 +43,9 @@ pub fn empty_vec() -> Vec<u8> {
 // CHECK-LABEL: @empty_vec_clone
 #[no_mangle]
 pub fn empty_vec_clone() -> Vec<u8> {
-    // CHECK: store i{{32|64}}
-    // CHECK-NOT: load i8
-    // CHECK-NEXT: getelementptr
-    // CHECK-NEXT: store ptr
+    // CHECK: store ptr inttoptr
     // CHECK-NEXT: getelementptr
-    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: call void @llvm.memset
     // CHECK-NEXT: ret void
     vec![].clone()
 }
diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
index d98f75e7502..46b450a4e47 100644
--- a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
+++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
@@ -22,9 +22,9 @@
       }
   
       bb0: {
-+         _9 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
 +         _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
 +         _8 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
++         _9 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
           StorageLive(_1);                 // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
           _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
diff --git a/tests/run-make/core-no-oom-handling/Makefile b/tests/run-make/core-no-oom-handling/Makefile
new file mode 100644
index 00000000000..28c5261ff85
--- /dev/null
+++ b/tests/run-make/core-no-oom-handling/Makefile
@@ -0,0 +1,6 @@
+include ../tools.mk
+
+FAKEROOT=$(TMPDIR)/fakeroot
+
+all:
+	$(RUSTC) --edition=2021 -Dwarnings --crate-type=rlib ../../../library/core/src/lib.rs --sysroot=$(FAKEROOT) --cfg no_global_oom_handling
diff --git a/tests/rustdoc-ui/unescaped_backticks.rs b/tests/rustdoc-ui/unescaped_backticks.rs
new file mode 100644
index 00000000000..f1ad7c8d4c7
--- /dev/null
+++ b/tests/rustdoc-ui/unescaped_backticks.rs
@@ -0,0 +1,342 @@
+#![deny(rustdoc::unescaped_backticks)]
+#![allow(rustdoc::broken_intra_doc_links)]
+#![allow(rustdoc::invalid_html_tags)]
+
+///
+pub fn empty() {}
+
+#[doc = ""]
+pub fn empty2() {}
+
+/// `
+//~^ ERROR unescaped backtick
+pub fn single() {}
+
+/// \`
+pub fn escaped() {}
+
+/// \\`
+//~^ ERROR unescaped backtick
+pub fn not_escaped() {}
+
+/// \\\`
+pub fn not_not_escaped() {}
+
+/// [`link1]
+//~^ ERROR unescaped backtick
+pub fn link1() {}
+
+/// [link2`]
+//~^ ERROR unescaped backtick
+pub fn link2() {}
+
+/// [`link_long](link_long)
+//~^ ERROR unescaped backtick
+pub fn link_long() {}
+
+/// [`broken-link]
+//~^ ERROR unescaped backtick
+pub fn broken_link() {}
+
+/// <xx:`>
+pub fn url() {}
+
+/// <x:`>
+//~^ ERROR unescaped backtick
+pub fn not_url() {}
+
+/// <h1>`</h1>
+pub fn html_tag() {}
+
+/// &#96;
+pub fn html_escape() {}
+
+/// 🦀`🦀
+//~^ ERROR unescaped backtick
+pub fn unicode() {}
+
+/// `foo(
+//~^ ERROR unescaped backtick
+///
+/// paragraph
+pub fn paragraph() {}
+
+/// `foo `bar`
+//~^ ERROR unescaped backtick
+///
+/// paragraph
+pub fn paragraph2() {}
+
+/// `foo(
+//~^ ERROR unescaped backtick
+/// not paragraph
+pub fn not_paragraph() {}
+
+/// Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`.
+//~^ ERROR unescaped backtick
+///
+/// You could use this function to add 42 to a number `n` (add(n, 42)`),
+/// or even to add a number `n` to 42 (`add(42, b)`)!
+//~^ ERROR unescaped backtick
+pub fn add1(a: i32, b: i32) -> i32 { a + b }
+
+/// Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`.
+//~^ ERROR unescaped backtick
+///
+/// You could use this function to add 42 to a number `n` (`add(n, 42)),
+/// or even to add a number `n` to 42 (`add(42, n)`)!
+//~^ ERROR unescaped backtick
+pub fn add2(a: i32, b: i32) -> i32 { a + b }
+
+/// Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`.
+//~^ ERROR unescaped backtick
+///
+/// You could use this function to add 42 to a number `n` (`add(n, 42)`),
+/// or even to add a number `n` to 42 (add(42, n)`)!
+//~^ ERROR unescaped backtick
+pub fn add3(a: i32, b: i32) -> i32 { a + b }
+
+/// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a).
+//~^ ERROR unescaped backtick
+///
+/// You could use this function to add 42 to a number `n` (`add(n, 42)),
+/// or even to add a number `n` to 42 (`add(42, n)`)!
+//~^ ERROR unescaped backtick
+pub fn add4(a: i32, b: i32) -> i32 { a + b }
+
+#[doc = "`"]
+//~^ ERROR unescaped backtick
+pub fn attr() {}
+
+#[doc = concat!("\\", "`")]
+pub fn attr_escaped() {}
+
+#[doc = concat!("\\\\", "`")]
+//~^ ERROR unescaped backtick
+pub fn attr_not_escaped() {}
+
+#[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."]
+//~^ ERROR unescaped backtick
+pub fn attr_add1(a: i32, b: i32) -> i32 { a + b }
+
+#[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."]
+//~^ ERROR unescaped backtick
+pub fn attr_add2(a: i32, b: i32) -> i32 { a + b }
+
+#[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."]
+//~^ ERROR unescaped backtick
+pub fn attr_add3(a: i32, b: i32) -> i32 { a + b }
+
+#[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."]
+//~^ ERROR unescaped backtick
+pub fn attr_add4(a: i32, b: i32) -> i32 { a + b }
+
+/// ``double backticks``
+/// `foo
+//~^ ERROR unescaped backtick
+pub fn double_backticks() {}
+
+/// # `(heading
+//~^ ERROR unescaped backtick
+/// ## heading2)`
+//~^ ERROR unescaped backtick
+///
+/// multi `(
+//~^ ERROR unescaped backtick
+/// line
+/// ) heading
+/// =
+///
+/// para)`(graph
+//~^ ERROR unescaped backtick
+///
+/// para)`(graph2
+//~^ ERROR unescaped backtick
+///
+/// 1. foo)`
+//~^ ERROR unescaped backtick
+/// 2. `(bar
+//~^ ERROR unescaped backtick
+/// * baz)`
+//~^ ERROR unescaped backtick
+/// * `(quux
+//~^ ERROR unescaped backtick
+///
+/// `#![this_is_actually_an_image(and(not), an = "attribute")]
+//~^ ERROR unescaped backtick
+///
+/// #![this_is_actually_an_image(and(not), an = "attribute")]`
+//~^ ERROR unescaped backtick
+///
+/// [this_is_actually_an_image(and(not), an = "attribute")]: `.png
+///
+/// | `table( | )head` |
+//~^ ERROR unescaped backtick
+//~| ERROR unescaped backtick
+/// |---------|--------|
+/// | table`( | )`body |
+//~^ ERROR unescaped backtick
+//~| ERROR unescaped backtick
+pub fn complicated_markdown() {}
+
+/// The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
+/// attribute only works on functions - there is no way to insert custom MIR into the middle of
+/// another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
+/// docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
+/// if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
+//~^ ERROR unescaped backtick
+/// "runtime", phase = "optimized")] if you don't.
+pub mod mir {}
+
+pub mod rustc {
+    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to
+    //~^ ERROR unescaped backtick
+    /// ensure it gets used.
+    pub fn ty_error_with_message() {}
+
+    pub struct WhereClause {
+        /// `true` if we ate a `where` token: this can happen
+        /// if we parsed no predicates (e.g. `struct Foo where {}
+        /// This allows us to accurately pretty-print
+        /// in `nt_to_tokenstream`
+        //~^ ERROR unescaped backtick
+        pub has_where_token: bool,
+    }
+
+    /// A symbol is an interned or gensymed string. The use of `newtype_index!` means
+    /// that `Option<Symbol>` only takes up 4 bytes, because `newtype_index! reserves
+    //~^ ERROR unescaped backtick
+    /// the last 256 values for tagging purposes.
+    pub struct Symbol();
+
+    /// It is equivalent to `OpenOptions::new()` but allows you to write more
+    /// readable code. Instead of `OpenOptions::new().read(true).open("foo.txt")`
+    /// you can write `File::with_options().read(true).open("foo.txt"). This
+    /// also avoids the need to import `OpenOptions`.
+    //~^ ERROR unescaped backtick
+    pub fn with_options() {}
+
+    /// Subtracts `set from `row`. `set` can be either `BitSet` or
+    /// `HybridBitSet`. Has no effect if `row` does not exist.
+    //~^ ERROR unescaped backtick
+    ///
+    /// Returns true if the row was changed.
+    pub fn subtract_row() {}
+
+    pub mod assert_module_sources {
+        //! The reason that we use `cfg=...` and not `#[cfg_attr]` is so that
+        //! the HIR doesn't change as a result of the annotations, which might
+        //! perturb the reuse results.
+        //!
+        //! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]
+        //~^ ERROR unescaped backtick
+        //! allows for doing a more fine-grained check to see if pre- or post-lto data
+        //! was re-used.
+
+        /// `cfg=...
+        //~^ ERROR unescaped backtick
+        pub fn foo() {}
+
+        /// `cfg=... and not `#[cfg_attr]`
+        //~^ ERROR unescaped backtick
+        pub fn bar() {}
+    }
+
+    /// Conceptually, this is like a `Vec<Vec<RWU>>`. But the number of
+    /// RWU`s can get very large, so it uses a more compact representation.
+    //~^ ERROR unescaped backtick
+    pub struct RWUTable {}
+
+    /// Like [Self::canonicalize_query], but preserves distinct universes. For
+    /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
+    /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
+    /// in `U2`.
+    //~^ ERROR unescaped backtick
+    ///
+    /// This is used for Chalk integration.
+    pub fn canonicalize_query_preserving_universes() {}
+
+    /// Note that we used to return `Error` here, but that was quite
+    /// dubious -- the premise was that an error would *eventually* be
+    /// reported, when the obligation was processed. But in general once
+    /// you see an `Error` you are supposed to be able to assume that an
+    /// error *has been* reported, so that you can take whatever heuristic
+    /// paths you want to take. To make things worse, it was possible for
+    /// cycles to arise, where you basically had a setup like `<MyType<$0>
+    /// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as
+    /// Trait>::Foo> to `[type error]` would lead to an obligation of
+    /// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report
+    /// an error for this obligation, but we legitimately should not,
+    /// because it contains `[type error]`. Yuck! (See issue #29857 for
+    //~^ ERROR unescaped backtick
+    /// one case where this arose.)
+    pub fn normalize_to_error() {}
+
+    /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait`
+    /// is `EvaluatedToOk`; this is because they were only considered
+    /// ok on the premise that if `A: AutoTrait` held, but we indeed
+    /// encountered a problem (later on) with `A: AutoTrait. So we
+    /// currently set a flag on the stack node for `B: AutoTrait` (as
+    /// well as the second instance of `A: AutoTrait`) to suppress
+    //~^ ERROR unescaped backtick
+    /// caching.
+    pub struct TraitObligationStack;
+
+    /// Extend `scc` so that it can outlive some placeholder region
+    /// from a universe it can't name; at present, the only way for
+    /// this to be true is if `scc` outlives `'static`. This is
+    /// actually stricter than necessary: ideally, we'd support bounds
+    /// like `for<'a: 'b`>` that might then allow us to approximate
+    /// `'a` with `'b` and not `'static`. But it will have to do for
+    //~^ ERROR unescaped backtick
+    /// now.
+    pub fn add_incompatible_universe(){}
+}
+
+/// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+/// which returns an `Option<Dispatch>`. If all [`Dispatch`] clones that point
+/// at the `Subscriber` have been dropped, [`WeakDispatch::upgrade`] will return
+/// `None`. Otherwise, it will return `Some(Dispatch)`.
+//~^ ERROR unescaped backtick
+///
+/// Returns some reference to this `[`Subscriber`] value if it is of type `T`,
+/// or `None` if it isn't.
+//~^ ERROR unescaped backtick
+///
+/// Called before the filtered [`Layer]'s [`on_event`], to determine if
+/// `on_event` should be called.
+//~^ ERROR unescaped backtick
+///
+/// Therefore, if the `Filter will change the value returned by this
+/// method, it is responsible for ensuring that
+/// [`rebuild_interest_cache`][rebuild] is called after the value of the max
+//~^ ERROR unescaped backtick
+/// level changes.
+pub mod tracing {}
+
+macro_rules! id {
+    ($($tt:tt)*) => { $($tt)* }
+}
+
+id! {
+    /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+    //~^ ERROR unescaped backtick
+    //~| ERROR unescaped backtick
+    //~| ERROR unescaped backtick
+    //~| ERROR unescaped backtick
+    /// which returns an `Option<Dispatch>`. If all [`Dispatch`] clones that point
+    /// at the `Subscriber` have been dropped, [`WeakDispatch::upgrade`] will return
+    /// `None`. Otherwise, it will return `Some(Dispatch)`.
+    ///
+    /// Returns some reference to this `[`Subscriber`] value if it is of type `T`,
+    /// or `None` if it isn't.
+    ///
+    /// Called before the filtered [`Layer]'s [`on_event`], to determine if
+    /// `on_event` should be called.
+    ///
+    /// Therefore, if the `Filter will change the value returned by this
+    /// method, it is responsible for ensuring that
+    /// [`rebuild_interest_cache`][rebuild] is called after the value of the max
+    /// level changes.
+    pub mod tracing_macro {}
+}
diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr
new file mode 100644
index 00000000000..e629dbc34e9
--- /dev/null
+++ b/tests/rustdoc-ui/unescaped_backticks.stderr
@@ -0,0 +1,959 @@
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:186:70
+   |
+LL | /// if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
+   |                                                                      ^
+   |
+note: the lint level is defined here
+  --> $DIR/unescaped_backticks.rs:1:9
+   |
+LL | #![deny(rustdoc::unescaped_backticks)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// "runtime", phase = "optimized")]` if you don't.
+   |                                     +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// if you want your MIR to be modified by the full MIR pipeline, or \`#![custom_mir(dialect =
+   |                                                                      +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:231:13
+   |
+LL |         //! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]
+   |             ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL |         //! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]`
+   |                                                                                         +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |         //! \`#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]
+   |             +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:236:13
+   |
+LL |         /// `cfg=...
+   |             ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL |         /// `cfg=...`
+   |                     +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |         /// \`cfg=...
+   |             +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:240:42
+   |
+LL |         /// `cfg=... and not `#[cfg_attr]`
+   |                                          ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL |         /// `cfg=...` and not `#[cfg_attr]`
+   |                     +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |         /// `cfg=... and not `#[cfg_attr]\`
+   |                                          +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:192:91
+   |
+LL |     /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to
+   |                                                                                           ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL |     /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to
+   |                                                                                               +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given \`msg to
+   |                                                                                           +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:201:34
+   |
+LL |         /// in `nt_to_tokenstream`
+   |                                  ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL |         /// if we parsed no predicates (e.g. `struct` Foo where {}
+   |                                                     +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |         /// in `nt_to_tokenstream\`
+   |                                  +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:207:62
+   |
+LL |     /// that `Option<Symbol>` only takes up 4 bytes, because `newtype_index! reserves
+   |                                                              ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL |     /// that `Option<Symbol>` only takes up 4 bytes, because `newtype_index!` reserves
+   |                                                                             +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// that `Option<Symbol>` only takes up 4 bytes, because \`newtype_index! reserves
+   |                                                              +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:215:52
+   |
+LL |     /// also avoids the need to import `OpenOptions`.
+   |                                                    ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL |     /// you can write `File::with_options().read(true).open("foo.txt")`. This
+   |                                                                       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// also avoids the need to import `OpenOptions\`.
+   |                                                    +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:220:46
+   |
+LL |     /// `HybridBitSet`. Has no effect if `row` does not exist.
+   |                                              ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL |     /// Subtracts `set` from `row`. `set` can be either `BitSet` or
+   |                       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// `HybridBitSet`. Has no effect if `row\` does not exist.
+   |                                              +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:246:12
+   |
+LL |     /// RWU`s can get very large, so it uses a more compact representation.
+   |            ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL |     /// `RWU`s can get very large, so it uses a more compact representation.
+   |         +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// RWU\`s can get very large, so it uses a more compact representation.
+   |            +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:253:15
+   |
+LL |     /// in `U2`.
+   |               ^
+   |
+help: the opening backtick of a previous inline code may be missing
+   |
+LL |     /// `'?1` is in `U3` would be canonicalized to have `?0` in `U1` and `'?1`
+   |                                                         +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// in `U2\`.
+   |               +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:270:42
+   |
+LL |     /// because it contains `[type error]`. Yuck! (See issue #29857 for
+   |                                          ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL |     /// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0>` as
+   |                                                              +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// because it contains `[type error]\`. Yuck! (See issue #29857 for
+   |                                          +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:280:53
+   |
+LL |     /// well as the second instance of `A: AutoTrait`) to suppress
+   |                                                     ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL |     /// encountered a problem (later on) with `A:` AutoTrait. So we
+   |                                                  +
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// well as the second instance of `A: AutoTrait\`) to suppress
+   |                                                     +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:290:40
+   |
+LL |     /// `'a` with `'b` and not `'static`. But it will have to do for
+   |                                        ^
+   |
+   = help: the opening or closing backtick of an inline code may be missing
+help: if you meant to use a literal backtick, escape it
+   |
+LL |     /// `'a` with `'b` and not `'static\`. But it will have to do for
+   |                                        +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:299:54
+   |
+LL | /// `None`. Otherwise, it will return `Some(Dispatch)`.
+   |                                                      ^
+   |
+help: the opening backtick of a previous inline code may be missing
+   |
+LL | /// The `Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+   |         +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// `None`. Otherwise, it will return `Some(Dispatch)\`.
+   |                                                      +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:303:13
+   |
+LL | /// or `None` if it isn't.
+   |             ^
+   |
+   = help: the opening or closing backtick of an inline code may be missing
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// or `None\` if it isn't.
+   |             +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:307:14
+   |
+LL | /// `on_event` should be called.
+   |              ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL | /// Called before the filtered [`Layer`]'s [`on_event`], to determine if
+   |                                       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// `on_event\` should be called.
+   |              +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:312:29
+   |
+LL | /// [`rebuild_interest_cache`][rebuild] is called after the value of the max
+   |                             ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL | /// Therefore, if the `Filter` will change the value returned by this
+   |                              +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// [`rebuild_interest_cache\`][rebuild] is called after the value of the max
+   |                             +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:322:5
+   |
+LL | /     /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     /// [`rebuild_interest_cache`][rebuild] is called after the value of the max
+LL | |     /// level changes.
+   | |______________________^
+   |
+   = help: the opening backtick of a previous inline code may be missing
+            change: The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+           to this: The `Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+   = help: if you meant to use a literal backtick, escape it
+            change: `None`. Otherwise, it will return `Some(Dispatch)`.
+           to this: `None`. Otherwise, it will return `Some(Dispatch)\`.
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:322:5
+   |
+LL | /     /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     /// [`rebuild_interest_cache`][rebuild] is called after the value of the max
+LL | |     /// level changes.
+   | |______________________^
+   |
+   = help: the opening or closing backtick of an inline code may be missing
+   = help: if you meant to use a literal backtick, escape it
+            change: or `None` if it isn't.
+           to this: or `None\` if it isn't.
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:322:5
+   |
+LL | /     /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     /// [`rebuild_interest_cache`][rebuild] is called after the value of the max
+LL | |     /// level changes.
+   | |______________________^
+   |
+   = help: a previous inline code might be longer than expected
+            change: Called before the filtered [`Layer]'s [`on_event`], to determine if
+           to this: Called before the filtered [`Layer`]'s [`on_event`], to determine if
+   = help: if you meant to use a literal backtick, escape it
+            change: `on_event` should be called.
+           to this: `on_event\` should be called.
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:322:5
+   |
+LL | /     /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     /// [`rebuild_interest_cache`][rebuild] is called after the value of the max
+LL | |     /// level changes.
+   | |______________________^
+   |
+   = help: a previous inline code might be longer than expected
+            change: Therefore, if the `Filter will change the value returned by this
+           to this: Therefore, if the `Filter` will change the value returned by this
+   = help: if you meant to use a literal backtick, escape it
+            change: [`rebuild_interest_cache`][rebuild] is called after the value of the max
+           to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:11:5
+   |
+LL | /// `
+   |     ^
+   |
+   = help: the opening or closing backtick of an inline code may be missing
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// \`
+   |     +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:18:7
+   |
+LL | /// \`
+   |       ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// `\`
+   |     +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// \\`
+   |       +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:25:6
+   |
+LL | /// [`link1]
+   |      ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// [`link1`]
+   |            +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// [\`link1]
+   |      +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:29:11
+   |
+LL | /// [link2`]
+   |           ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// [`link2`]
+   |      +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// [link2\`]
+   |           +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:33:6
+   |
+LL | /// [`link_long](link_long)
+   |      ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// [`link_long`](link_long)
+   |                +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// [\`link_long](link_long)
+   |      +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:37:6
+   |
+LL | /// [`broken-link]
+   |      ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// [`broken-link`]
+   |                  +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// [\`broken-link]
+   |      +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:44:8
+   |
+LL | /// <x:`>
+   |        ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// `<x:`>
+   |     +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// <x:\`>
+   |        +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:54:6
+   |
+LL | /// 🦀`🦀
+   |       ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// `🦀`🦀
+   |     +
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// 🦀`🦀`
+   |          +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// 🦀\`🦀
+   |       +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:58:5
+   |
+LL | /// `foo(
+   |     ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// `foo(`
+   |          +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// \`foo(
+   |     +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:64:14
+   |
+LL | /// `foo `bar`
+   |              ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL | /// `foo` `bar`
+   |         +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// `foo `bar\`
+   |              +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:70:5
+   |
+LL | /// `foo(
+   |     ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// not paragraph`
+   |                  +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// \`foo(
+   |     +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:75:83
+   |
+LL | /// Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`.
+   |                                                                                   ^
+   |
+help: the opening backtick of a previous inline code may be missing
+   |
+LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)`.
+   |                                               +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// Addition is commutative, which means that add(a, b)` is the same as `add(b, a)\`.
+   |                                                                                   +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:79:51
+   |
+LL | /// or even to add a number `n` to 42 (`add(42, b)`)!
+   |                                                   ^
+   |
+help: the opening backtick of a previous inline code may be missing
+   |
+LL | /// You could use this function to add 42 to a number `n` (`add(n, 42)`),
+   |                                                            +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// or even to add a number `n` to 42 (`add(42, b)\`)!
+   |                                                   +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:83:83
+   |
+LL | /// Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`.
+   |                                                                                   ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)`.
+   |                                                         +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// Addition is commutative, which means that `add(a, b) is the same as `add(b, a)\`.
+   |                                                                                   +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:87:51
+   |
+LL | /// or even to add a number `n` to 42 (`add(42, n)`)!
+   |                                                   ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL | /// You could use this function to add 42 to a number `n` (`add(n, 42)`),
+   |                                                                       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// or even to add a number `n` to 42 (`add(42, n)\`)!
+   |                                                   +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:91:83
+   |
+LL | /// Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`.
+   |                                                                                   ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)`.
+   |                                                                          +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// Addition is commutative, which means that `add(a, b)` is the same as add(b, a)\`.
+   |                                                                                   +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:95:50
+   |
+LL | /// or even to add a number `n` to 42 (add(42, n)`)!
+   |                                                  ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// or even to add a number `n` to 42 (`add(42, n)`)!
+   |                                        +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// or even to add a number `n` to 42 (add(42, n)\`)!
+   |                                                  +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:99:74
+   |
+LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a).
+   |                                                                          ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)`.
+   |                                                                                    +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// Addition is commutative, which means that `add(a, b)` is the same as \`add(b, a).
+   |                                                                          +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:103:51
+   |
+LL | /// or even to add a number `n` to 42 (`add(42, n)`)!
+   |                                                   ^
+   |
+help: a previous inline code might be longer than expected
+   |
+LL | /// You could use this function to add 42 to a number `n` (`add(n, 42)`),
+   |                                                                       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// or even to add a number `n` to 42 (`add(42, n)\`)!
+   |                                                   +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:107:1
+   |
+LL | #[doc = "`"]
+   | ^^^^^^^^^^^^
+   |
+   = help: the opening or closing backtick of an inline code may be missing
+   = help: if you meant to use a literal backtick, escape it
+            change: `
+           to this: \`
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:114:1
+   |
+LL | #[doc = concat!("\\", "`")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the opening backtick of an inline code may be missing
+            change: \`
+           to this: `\`
+   = help: if you meant to use a literal backtick, escape it
+            change: \`
+           to this: \\`
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:118:1
+   |
+LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the opening backtick of a previous inline code may be missing
+            change: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`.
+           to this: Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)`.
+   = help: if you meant to use a literal backtick, escape it
+            change: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`.
+           to this: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)\`.
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:122:1
+   |
+LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: a previous inline code might be longer than expected
+            change: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`.
+           to this: Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)`.
+   = help: if you meant to use a literal backtick, escape it
+            change: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`.
+           to this: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)\`.
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:126:1
+   |
+LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the opening backtick of an inline code may be missing
+            change: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`.
+           to this: Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)`.
+   = help: if you meant to use a literal backtick, escape it
+            change: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`.
+           to this: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)\`.
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:130:1
+   |
+LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: the closing backtick of an inline code may be missing
+            change: Addition is commutative, which means that `add(a, b)` is the same as `add(b, a).
+           to this: Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)`.
+   = help: if you meant to use a literal backtick, escape it
+            change: Addition is commutative, which means that `add(a, b)` is the same as `add(b, a).
+           to this: Addition is commutative, which means that `add(a, b)` is the same as \`add(b, a).
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:135:5
+   |
+LL | /// `foo
+   |     ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// `foo`
+   |         +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// \`foo
+   |     +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:139:7
+   |
+LL | /// # `(heading
+   |       ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// # `(heading`
+   |                +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// # \`(heading
+   |       +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:141:17
+   |
+LL | /// ## heading2)`
+   |                 ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// ## `heading2)`
+   |        +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// ## heading2)\`
+   |                 +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:144:11
+   |
+LL | /// multi `(
+   |           ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// )` heading
+   |      +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// multi \`(
+   |           +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:150:10
+   |
+LL | /// para)`(graph
+   |          ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// `para)`(graph
+   |     +
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// para)`(graph`
+   |                 +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// para)\`(graph
+   |          +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:153:10
+   |
+LL | /// para)`(graph2
+   |          ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// `para)`(graph2
+   |     +
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// para)`(graph2`
+   |                  +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// para)\`(graph2
+   |          +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:156:12
+   |
+LL | /// 1. foo)`
+   |            ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// 1. `foo)`
+   |        +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// 1. foo)\`
+   |            +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:158:8
+   |
+LL | /// 2. `(bar
+   |        ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// 2. `(bar`
+   |             +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// 2. \`(bar
+   |        +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:160:11
+   |
+LL | /// * baz)`
+   |           ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// * `baz)`
+   |       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// * baz)\`
+   |           +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:162:7
+   |
+LL | /// * `(quux
+   |       ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// * `(quux`
+   |             +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// * \`(quux
+   |       +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:165:5
+   |
+LL | /// `#![this_is_actually_an_image(and(not), an = "attribute")]
+   |     ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// `#`![this_is_actually_an_image(and(not), an = "attribute")]
+   |       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// \`#![this_is_actually_an_image(and(not), an = "attribute")]
+   |     +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:168:62
+   |
+LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]`
+   |                                                              ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// `#![this_is_actually_an_image(and(not), an = "attribute")]`
+   |     +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]\`
+   |                                                              +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:173:7
+   |
+LL | /// | `table( | )head` |
+   |       ^
+   |
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// | `table(` | )head` |
+   |              +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// | \`table( | )head` |
+   |       +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:173:22
+   |
+LL | /// | `table( | )head` |
+   |                      ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// | `table( | `)head` |
+   |                 +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// | `table( | )head\` |
+   |                      +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:177:12
+   |
+LL | /// | table`( | )`body |
+   |            ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// | `table`( | )`body |
+   |       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// | table\`( | )`body |
+   |            +
+
+error: unescaped backtick
+  --> $DIR/unescaped_backticks.rs:177:18
+   |
+LL | /// | table`( | )`body |
+   |                  ^
+   |
+help: the opening backtick of an inline code may be missing
+   |
+LL | /// | table`( | `)`body |
+   |                 +
+help: the closing backtick of an inline code may be missing
+   |
+LL | /// | table`( | )`body` |
+   |                       +
+help: if you meant to use a literal backtick, escape it
+   |
+LL | /// | table`( | )\`body |
+   |                  +
+
+error: aborting due to 63 previous errors
+
diff --git a/tests/rustdoc/deref-const-fn.rs b/tests/rustdoc/deref/deref-const-fn.rs
index 8ecca6d12d2..8ecca6d12d2 100644
--- a/tests/rustdoc/deref-const-fn.rs
+++ b/tests/rustdoc/deref/deref-const-fn.rs
diff --git a/tests/rustdoc/deref/deref-multiple-impl-blocks.rs b/tests/rustdoc/deref/deref-multiple-impl-blocks.rs
new file mode 100644
index 00000000000..fa3607c5fc1
--- /dev/null
+++ b/tests/rustdoc/deref/deref-multiple-impl-blocks.rs
@@ -0,0 +1,43 @@
+#![crate_name="foo"]
+
+use std::ops::{Deref, DerefMut};
+
+// @has foo/struct.Vec.html
+// @count - '//h2[@id="deref-methods-Slice"]' 1
+// @count - '//div[@id="deref-methods-Slice-1"]' 1
+// @count - '//div[@id="deref-methods-Slice-1"][@class="impl-items"]' 1
+// @count - '//div[@id="deref-methods-Slice-1"]/div[@class="impl-items"]' 0
+pub struct Vec;
+
+pub struct Slice;
+
+impl Deref for Vec {
+    type Target = Slice;
+    fn deref(&self) -> &Slice {
+        &Slice
+    }
+}
+
+impl DerefMut for Vec {
+    fn deref_mut(&mut self) -> &mut Slice {
+        &mut Slice
+    }
+}
+
+impl Slice {
+    pub fn sort_floats(&mut self) {
+        todo!();
+    }
+}
+
+impl Slice {
+    pub fn sort(&mut self) {
+        todo!();
+    }
+}
+
+impl Slice {
+    pub fn len(&self) {
+        todo!();
+    }
+}
diff --git a/tests/rustdoc/deref-mut-methods.rs b/tests/rustdoc/deref/deref-mut-methods.rs
index fdf8434224f..fdf8434224f 100644
--- a/tests/rustdoc/deref-mut-methods.rs
+++ b/tests/rustdoc/deref/deref-mut-methods.rs
diff --git a/tests/rustdoc/deref-recursive-pathbuf.rs b/tests/rustdoc/deref/deref-recursive-pathbuf.rs
index be2b42b5ac6..be2b42b5ac6 100644
--- a/tests/rustdoc/deref-recursive-pathbuf.rs
+++ b/tests/rustdoc/deref/deref-recursive-pathbuf.rs
diff --git a/tests/rustdoc/deref-recursive.rs b/tests/rustdoc/deref/deref-recursive.rs
index 0436f2f86f5..0436f2f86f5 100644
--- a/tests/rustdoc/deref-recursive.rs
+++ b/tests/rustdoc/deref/deref-recursive.rs
diff --git a/tests/rustdoc/deref-slice-core.rs b/tests/rustdoc/deref/deref-slice-core.rs
index cccf273a820..cccf273a820 100644
--- a/tests/rustdoc/deref-slice-core.rs
+++ b/tests/rustdoc/deref/deref-slice-core.rs
diff --git a/tests/rustdoc/deref-to-primitive.rs b/tests/rustdoc/deref/deref-to-primitive.rs
index 527de780d48..527de780d48 100644
--- a/tests/rustdoc/deref-to-primitive.rs
+++ b/tests/rustdoc/deref/deref-to-primitive.rs
diff --git a/tests/rustdoc/deref-typedef.rs b/tests/rustdoc/deref/deref-typedef.rs
index 32424d13eb8..32424d13eb8 100644
--- a/tests/rustdoc/deref-typedef.rs
+++ b/tests/rustdoc/deref/deref-typedef.rs
diff --git a/tests/rustdoc/escape-deref-methods.rs b/tests/rustdoc/deref/escape-deref-methods.rs
index 66919d73eeb..66919d73eeb 100644
--- a/tests/rustdoc/escape-deref-methods.rs
+++ b/tests/rustdoc/deref/escape-deref-methods.rs
diff --git a/tests/rustdoc/issue-100679-sidebar-links-deref.rs b/tests/rustdoc/deref/issue-100679-sidebar-links-deref.rs
index f09d2320609..f09d2320609 100644
--- a/tests/rustdoc/issue-100679-sidebar-links-deref.rs
+++ b/tests/rustdoc/deref/issue-100679-sidebar-links-deref.rs
diff --git a/tests/rustdoc/recursive-deref-sidebar.rs b/tests/rustdoc/deref/recursive-deref-sidebar.rs
index 619f40eff89..619f40eff89 100644
--- a/tests/rustdoc/recursive-deref-sidebar.rs
+++ b/tests/rustdoc/deref/recursive-deref-sidebar.rs
diff --git a/tests/rustdoc/recursive-deref.rs b/tests/rustdoc/deref/recursive-deref.rs
index aa38485c445..aa38485c445 100644
--- a/tests/rustdoc/recursive-deref.rs
+++ b/tests/rustdoc/deref/recursive-deref.rs
diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
index eaf3e4b61e3..c0fbb0204b3 100644
--- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
+++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
@@ -2,38 +2,34 @@ print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2]`:
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Suspend0`: 3077 bytes
-print-type-size         local `.__awaitee`: 3077 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         local `.__awaitee`: 3077 bytes
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
 print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]`: 3077 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
-print-type-size     variant `Unresumed`: 2051 bytes
-print-type-size         padding: 1026 bytes
-print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size     variant `Unresumed`: 1025 bytes
+print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Suspend0`: 2052 bytes
-print-type-size         local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
-print-type-size         local `..generator_field4`: 1 bytes
+print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         padding: 1 bytes
-print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `..generator_field4`: 1 bytes
 print-type-size         local `.__awaitee`: 1 bytes
 print-type-size     variant `Suspend1`: 3076 bytes
-print-type-size         padding: 1024 bytes
+print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         padding: 1026 bytes
 print-type-size         local `..generator_field4`: 1 bytes, alignment: 1 bytes
-print-type-size         padding: 1 bytes
-print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
 print-type-size         local `.__awaitee`: 1025 bytes
 print-type-size     variant `Suspend2`: 2052 bytes
-print-type-size         local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
-print-type-size         local `..generator_field4`: 1 bytes
+print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         padding: 1 bytes
-print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `..generator_field4`: 1 bytes
 print-type-size         local `.__awaitee`: 1 bytes
-print-type-size     variant `Returned`: 2051 bytes
-print-type-size         padding: 1026 bytes
-print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
-print-type-size     variant `Panicked`: 2051 bytes
-print-type-size         padding: 1026 bytes
-print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size     variant `Returned`: 1025 bytes
+print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 1025 bytes
+print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 3077 bytes
 print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
@@ -43,11 +39,11 @@ print-type-size         field `.value`: 3077 bytes
 print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]`: 1025 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 1024 bytes
-print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 1024 bytes
 print-type-size     variant `Returned`: 1024 bytes
-print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 1024 bytes
 print-type-size     variant `Panicked`: 1024 bytes
-print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 1024 bytes
 print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 1025 bytes
 print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout
index 91db4b1531f..b5e95ddd710 100644
--- a/tests/ui/async-await/future-sizes/large-arg.stdout
+++ b/tests/ui/async-await/future-sizes/large-arg.stdout
@@ -2,20 +2,20 @@ print-type-size type: `[async fn body@$DIR/large-arg.rs:6:21: 8:2]`: 3076 bytes,
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Suspend0`: 3075 bytes
-print-type-size         local `.__awaitee`: 3075 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         local `.__awaitee`: 3075 bytes
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
 print-type-size type: `[async fn body@$DIR/large-arg.rs:10:30: 12:2]`: 3075 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Suspend0`: 3074 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size         local `.__awaitee`: 2050 bytes
 print-type-size     variant `Returned`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Panicked`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:10:30: 12:2]>`: 3075 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 3075 bytes
 print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:10:30: 12:2]>`: 3075 bytes, alignment: 1 bytes
@@ -25,14 +25,14 @@ print-type-size         field `.value`: 3075 bytes
 print-type-size type: `[async fn body@$DIR/large-arg.rs:13:26: 15:2]`: 2050 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Suspend0`: 2049 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size         local `.__awaitee`: 1025 bytes
 print-type-size     variant `Returned`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Panicked`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:13:26: 15:2]>`: 2050 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 2050 bytes
 print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:13:26: 15:2]>`: 2050 bytes, alignment: 1 bytes
@@ -42,11 +42,11 @@ print-type-size         field `.value`: 2050 bytes
 print-type-size type: `[async fn body@$DIR/large-arg.rs:16:26: 18:2]`: 1025 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Returned`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Panicked`: 1024 bytes
-print-type-size         upvar `.t`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.t`: 1024 bytes
 print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/large-arg.rs:16:26: 18:2]>`: 1025 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 1025 bytes
 print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/large-arg.rs:16:26: 18:2]>`: 1025 bytes, alignment: 1 bytes
diff --git a/tests/ui/async-await/in-trait/nested-rpit.rs b/tests/ui/async-await/in-trait/nested-rpit.rs
index 41d72ebb4d4..9cdc23bbc78 100644
--- a/tests/ui/async-await/in-trait/nested-rpit.rs
+++ b/tests/ui/async-await/in-trait/nested-rpit.rs
@@ -1,7 +1,5 @@
 // edition: 2021
-// known-bug: #105197
-// failure-status:101
-// dont-check-compiler-stderr
+// check-pass
 
 #![feature(async_fn_in_trait)]
 #![feature(return_position_impl_trait_in_trait)]
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs
new file mode 100644
index 00000000000..0ecbca5c13b
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs
@@ -0,0 +1,48 @@
+// edition: 2021
+// known-bug: #110963
+
+#![feature(return_type_notation)]
+#![feature(async_fn_in_trait)]
+
+trait HealthCheck {
+    async fn check<'a: 'a>(&'a mut self) -> bool;
+}
+
+async fn do_health_check_par<HC>(hc: HC)
+where
+    HC: HealthCheck<check(): Send> + Send + 'static,
+{
+    spawn(async move {
+        let mut hc = hc;
+        if !hc.check().await {
+            log_health_check_failure().await;
+        }
+    });
+}
+
+async fn log_health_check_failure() {}
+
+fn main() {}
+
+// Fake tokio spawn
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+fn spawn<F>(future: F) -> JoinHandle
+where
+    F: Future + Send + 'static,
+    F::Output: Send + 'static,
+{
+    loop {}
+}
+
+struct JoinHandle;
+
+impl Future for JoinHandle {
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        loop {}
+    }
+}
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr
new file mode 100644
index 00000000000..b4a3924d8da
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr
@@ -0,0 +1,45 @@
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-110963-early.rs:4:12
+   |
+LL | #![feature(return_type_notation)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-110963-early.rs:5:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+
+error: higher-ranked lifetime error
+  --> $DIR/issue-110963-early.rs:15:5
+   |
+LL | /     spawn(async move {
+LL | |         let mut hc = hc;
+LL | |         if !hc.check().await {
+LL | |             log_health_check_failure().await;
+LL | |         }
+LL | |     });
+   | |______^
+   |
+   = note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send`
+
+error: higher-ranked lifetime error
+  --> $DIR/issue-110963-early.rs:15:5
+   |
+LL | /     spawn(async move {
+LL | |         let mut hc = hc;
+LL | |         if !hc.check().await {
+LL | |             log_health_check_failure().await;
+LL | |         }
+LL | |     });
+   | |______^
+   |
+   = note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send`
+
+error: aborting due to 2 previous errors; 2 warnings emitted
+
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs
new file mode 100644
index 00000000000..2a35922eaa1
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs
@@ -0,0 +1,50 @@
+// edition: 2021
+// check-pass
+
+#![feature(return_type_notation)]
+//~^ WARN the feature `return_type_notation` is incomplete
+#![feature(async_fn_in_trait)]
+//~^ WARN the feature `async_fn_in_trait` is incomplete
+
+trait HealthCheck {
+    async fn check(&mut self) -> bool;
+}
+
+async fn do_health_check_par<HC>(hc: HC)
+where
+    HC: HealthCheck<check(): Send> + Send + 'static,
+{
+    spawn(async move {
+        let mut hc = hc;
+        if !hc.check().await {
+            log_health_check_failure().await;
+        }
+    });
+}
+
+async fn log_health_check_failure() {}
+
+fn main() {}
+
+// Fake tokio spawn
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+fn spawn<F>(future: F) -> JoinHandle
+where
+    F: Future + Send + 'static,
+    F::Output: Send + 'static,
+{
+    loop {}
+}
+
+struct JoinHandle;
+
+impl Future for JoinHandle {
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        loop {}
+    }
+}
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.stderr b/tests/ui/async-await/return-type-notation/issue-110963-late.stderr
new file mode 100644
index 00000000000..36ef3ad0a4c
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/issue-110963-late.stderr
@@ -0,0 +1,19 @@
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-110963-late.rs:4:12
+   |
+LL | #![feature(return_type_notation)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-110963-late.rs:6:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/binding/issue-53114-safety-checks.stderr b/tests/ui/binding/issue-53114-safety-checks.stderr
index 41318d0a38a..349c4639a9e 100644
--- a/tests/ui/binding/issue-53114-safety-checks.stderr
+++ b/tests/ui/binding/issue-53114-safety-checks.stderr
@@ -4,7 +4,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let _ = &p.b;
    |             ^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -13,7 +14,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let (_,) = (&p.b,);
    |                 ^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -22,7 +24,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let _: _ = &p.b;
    |                ^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -31,7 +34,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let (_,): _ = (&p.b,);
    |                    ^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -40,7 +44,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     match &p.b  { _ => { } }
    |           ^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -49,7 +54,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     match (&p.b,)  { (_,) => { } }
    |            ^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
index 9c2c434572a..8c44229bceb 100644
--- a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
+++ b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
@@ -4,7 +4,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         println!("{}", foo.x);
    |                        ^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
index a0f8dd097c7..a93b561e5be 100644
--- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
@@ -465,7 +465,7 @@ LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchec
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 10 00 00 00 00 00 00                         │ ........
+               00 00 00 00 00 10 00 00                         │ ........
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -476,7 +476,7 @@ LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unche
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               09 00 00 00 03 00 00 00                         │ ........
+               03 00 00 00 09 00 00 00                         │ ........
            }
 
 error[E0080]: it is undefined behavior to use this value
diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
index 9706f3ec2e0..a32d4863a38 100644
--- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
@@ -465,7 +465,7 @@ LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchec
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
+               00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 │ ................
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -476,7 +476,7 @@ LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unche
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................
+               03 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00 │ ................
            }
 
 error[E0080]: it is undefined behavior to use this value
diff --git a/tests/ui/feature-gates/test-listing-format-json.rs b/tests/ui/feature-gates/test-listing-format-json.rs
new file mode 100644
index 00000000000..2dd0e10b521
--- /dev/null
+++ b/tests/ui/feature-gates/test-listing-format-json.rs
@@ -0,0 +1,18 @@
+// no-prefer-dynamic
+// compile-flags: --test
+// run-flags: --list --format json -Zunstable-options
+// run-fail
+// check-run-results
+// ignore-nightly
+// unset-exec-env:RUSTC_BOOTSTRAP
+
+#![cfg(test)]
+#[test]
+fn m_test() {}
+
+#[test]
+#[ignore = "not yet implemented"]
+fn z_test() {}
+
+#[test]
+fn a_test() {}
diff --git a/tests/ui/feature-gates/test-listing-format-json.run.stderr b/tests/ui/feature-gates/test-listing-format-json.run.stderr
new file mode 100644
index 00000000000..e81cb81f32c
--- /dev/null
+++ b/tests/ui/feature-gates/test-listing-format-json.run.stderr
@@ -0,0 +1 @@
+error: the option `Z` is only accepted on the nightly compiler
diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
index 20d4c418e87..8c7c915350f 100644
--- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
+++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
@@ -370,23 +370,23 @@ error: layout_of(NicheFirst) = Layout {
                pref: $PREF_ALIGN,
            },
            abi: ScalarPair(
-               Union {
+               Initialized {
                    value: Int(
                        I8,
                        false,
                    ),
+                   valid_range: 0..=4,
                },
-               Initialized {
+               Union {
                    value: Int(
                        I8,
                        false,
                    ),
-                   valid_range: 0..=4,
                },
            ),
            fields: Arbitrary {
                offsets: [
-                   Size(1 bytes),
+                   Size(0 bytes),
                ],
                memory_index: [
                    0,
@@ -394,7 +394,7 @@ error: layout_of(NicheFirst) = Layout {
            },
            largest_niche: Some(
                Niche {
-                   offset: Size(1 bytes),
+                   offset: Size(0 bytes),
                    value: Int(
                        I8,
                        false,
@@ -429,29 +429,29 @@ error: layout_of(NicheFirst) = Layout {
                                    I8,
                                    false,
                                ),
-                               valid_range: 0..=255,
+                               valid_range: 0..=2,
                            },
                            Initialized {
                                value: Int(
                                    I8,
                                    false,
                                ),
-                               valid_range: 0..=2,
+                               valid_range: 0..=255,
                            },
                        ),
                        fields: Arbitrary {
                            offsets: [
-                               Size(1 bytes),
                                Size(0 bytes),
+                               Size(1 bytes),
                            ],
                            memory_index: [
-                               1,
                                0,
+                               1,
                            ],
                        },
                        largest_niche: Some(
                            Niche {
-                               offset: Size(1 bytes),
+                               offset: Size(0 bytes),
                                value: Int(
                                    I8,
                                    false,
@@ -514,23 +514,23 @@ error: layout_of(NicheSecond) = Layout {
                pref: $PREF_ALIGN,
            },
            abi: ScalarPair(
-               Union {
+               Initialized {
                    value: Int(
                        I8,
                        false,
                    ),
+                   valid_range: 0..=4,
                },
-               Initialized {
+               Union {
                    value: Int(
                        I8,
                        false,
                    ),
-                   valid_range: 0..=4,
                },
            ),
            fields: Arbitrary {
                offsets: [
-                   Size(1 bytes),
+                   Size(0 bytes),
                ],
                memory_index: [
                    0,
@@ -538,7 +538,7 @@ error: layout_of(NicheSecond) = Layout {
            },
            largest_niche: Some(
                Niche {
-                   offset: Size(1 bytes),
+                   offset: Size(0 bytes),
                    value: Int(
                        I8,
                        false,
@@ -573,29 +573,29 @@ error: layout_of(NicheSecond) = Layout {
                                    I8,
                                    false,
                                ),
-                               valid_range: 0..=255,
+                               valid_range: 0..=2,
                            },
                            Initialized {
                                value: Int(
                                    I8,
                                    false,
                                ),
-                               valid_range: 0..=2,
+                               valid_range: 0..=255,
                            },
                        ),
                        fields: Arbitrary {
                            offsets: [
-                               Size(0 bytes),
                                Size(1 bytes),
+                               Size(0 bytes),
                            ],
                            memory_index: [
-                               0,
                                1,
+                               0,
                            ],
                        },
                        largest_niche: Some(
                            Niche {
-                               offset: Size(1 bytes),
+                               offset: Size(0 bytes),
                                value: Int(
                                    I8,
                                    false,
diff --git a/tests/ui/lint/unaligned_references.stderr b/tests/ui/lint/unaligned_references.stderr
index 775dcac678e..5f9cecadbff 100644
--- a/tests/ui/lint/unaligned_references.stderr
+++ b/tests/ui/lint/unaligned_references.stderr
@@ -4,7 +4,8 @@ error[E0793]: reference to packed field is unaligned
 LL |             &self.x;
    |             ^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -13,7 +14,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _ = &good.ptr;
    |                 ^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -22,7 +24,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _ = &good.data;
    |                 ^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -31,7 +34,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _ = &good.data as *const _;
    |                 ^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -40,7 +44,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _: *const _ = &good.data;
    |                           ^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -49,7 +54,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _ = good.data.clone();
    |                 ^^^^^^^^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -58,7 +64,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _ = &good.data2[0];
    |                 ^^^^^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -67,7 +74,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _ = &packed2.x;
    |                 ^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -76,7 +84,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _ref = &m1.1.a;
    |                    ^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -85,7 +94,8 @@ error[E0793]: reference to packed field is unaligned
 LL |         let _ref = &m2.1.a;
    |                    ^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: aborting due to 10 previous errors
diff --git a/tests/ui/lint/unaligned_references_external_macro.stderr b/tests/ui/lint/unaligned_references_external_macro.stderr
index 5b08f433e32..94a95c1d8fd 100644
--- a/tests/ui/lint/unaligned_references_external_macro.stderr
+++ b/tests/ui/lint/unaligned_references_external_macro.stderr
@@ -9,7 +9,8 @@ LL | |     }
 LL | | }
    | |_^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
    = note: this error originates in the macro `unaligned_references_external_crate::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/native-library-link-flags/msvc-non-utf8-output.rs b/tests/ui/native-library-link-flags/msvc-non-utf8-output.rs
new file mode 100644
index 00000000000..3fb2842d694
--- /dev/null
+++ b/tests/ui/native-library-link-flags/msvc-non-utf8-output.rs
@@ -0,0 +1,6 @@
+// build-fail
+// compile-flags:-C link-arg=märchenhaft
+// only-msvc
+// error-pattern:= note: LINK : fatal error LNK1181:
+// normalize-stderr-test "(\s*\|\n)\s*= note: .*\n" -> "$1"
+pub fn main() {}
diff --git a/tests/ui/native-library-link-flags/msvc-non-utf8-output.stderr b/tests/ui/native-library-link-flags/msvc-non-utf8-output.stderr
new file mode 100644
index 00000000000..f843aad782c
--- /dev/null
+++ b/tests/ui/native-library-link-flags/msvc-non-utf8-output.stderr
@@ -0,0 +1,7 @@
+error: linking with `link.exe` failed: exit code: 1181
+   |
+   = note: LINK : fatal error LNK1181: cannot open input file 'märchenhaft.obj'
+           
+
+error: aborting due to previous error
+
diff --git a/tests/ui/packed/issue-27060.stderr b/tests/ui/packed/issue-27060.stderr
index b4753284f72..4dc31a28386 100644
--- a/tests/ui/packed/issue-27060.stderr
+++ b/tests/ui/packed/issue-27060.stderr
@@ -4,7 +4,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let _ = &good.data;
    |             ^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -13,7 +14,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let _ = &good.data2[0];
    |             ^^^^^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -22,7 +24,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let _ = &good.data;
    |             ^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -31,7 +34,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let _ = &good.data2[0];
    |             ^^^^^^^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/packed/packed-struct-borrow-element-64bit.stderr b/tests/ui/packed/packed-struct-borrow-element-64bit.stderr
index 32943b0f07b..57630a4b470 100644
--- a/tests/ui/packed/packed-struct-borrow-element-64bit.stderr
+++ b/tests/ui/packed/packed-struct-borrow-element-64bit.stderr
@@ -4,7 +4,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let brw = &foo.baz;
    |               ^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: aborting due to previous error
diff --git a/tests/ui/packed/packed-struct-borrow-element.stderr b/tests/ui/packed/packed-struct-borrow-element.stderr
index 29d867fc5b9..c1f749d6fbb 100644
--- a/tests/ui/packed/packed-struct-borrow-element.stderr
+++ b/tests/ui/packed/packed-struct-borrow-element.stderr
@@ -4,7 +4,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let brw = &foo.baz;
    |               ^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
@@ -13,7 +14,8 @@ error[E0793]: reference to packed field is unaligned
 LL |     let brw = &foo.baz;
    |               ^^^^^^^^
    |
-   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout
index 8fe936efc89..1c6887412be 100644
--- a/tests/ui/print_type_sizes/async.stdout
+++ b/tests/ui/print_type_sizes/async.stdout
@@ -1,15 +1,15 @@
 print-type-size type: `[async fn body@$DIR/async.rs:8:36: 11:2]`: 16386 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 8192 bytes
-print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 8192 bytes
 print-type-size     variant `Suspend0`: 16385 bytes
-print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 8192 bytes
 print-type-size         local `.arg`: 8192 bytes
 print-type-size         local `.__awaitee`: 1 bytes
 print-type-size     variant `Returned`: 8192 bytes
-print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 8192 bytes
 print-type-size     variant `Panicked`: 8192 bytes
-print-type-size         upvar `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.arg`: 8192 bytes
 print-type-size type: `std::mem::ManuallyDrop<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
 print-type-size     field `.value`: 8192 bytes
 print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
diff --git a/tests/ui/print_type_sizes/generator.stdout b/tests/ui/print_type_sizes/generator.stdout
index 7c58d6ce5ff..2dcadde9ec2 100644
--- a/tests/ui/print_type_sizes/generator.stdout
+++ b/tests/ui/print_type_sizes/generator.stdout
@@ -1,10 +1,10 @@
 print-type-size type: `[generator@$DIR/generator.rs:10:5: 10:14]`: 8193 bytes, alignment: 1 bytes
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 8192 bytes
-print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.array`: 8192 bytes
 print-type-size     variant `Suspend0`: 8192 bytes
-print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.array`: 8192 bytes
 print-type-size     variant `Returned`: 8192 bytes
-print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.array`: 8192 bytes
 print-type-size     variant `Panicked`: 8192 bytes
-print-type-size         upvar `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         upvar `.array`: 8192 bytes
diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs
index 63e2f3150c0..406e5c8441e 100644
--- a/tests/ui/structs-enums/type-sizes.rs
+++ b/tests/ui/structs-enums/type-sizes.rs
@@ -4,9 +4,14 @@
 #![allow(dead_code)]
 #![feature(never_type)]
 #![feature(pointer_is_aligned)]
+#![feature(ptr_from_ref)]
+#![feature(strict_provenance)]
 
 use std::mem::size_of;
-use std::num::NonZeroU8;
+use std::num::{NonZeroU8, NonZeroU16};
+use std::ptr;
+use std::ptr::NonNull;
+use std::borrow::Cow;
 
 struct t {a: u8, b: i8}
 struct u {a: u8, b: i8, c: u8}
@@ -181,6 +186,41 @@ struct Reorder2 {
     ary: [u8; 6],
 }
 
+// We want the niche in the front, which means we can't treat the array as quasi-aligned more than
+// 4 bytes even though we also want to place it at an 8-aligned offset where possible.
+// So the ideal layout would look like: (char, u32, [u8; 8], u8)
+// The current layout algorithm does (char, [u8; 8], u32, u8)
+#[repr(align(8))]
+struct ReorderWithNiche {
+    a: u32,
+    b: char,
+    c: u8,
+    ary: [u8; 8]
+}
+
+#[repr(C)]
+struct EndNiche8([u8; 7], bool);
+
+#[repr(C)]
+struct MiddleNiche4(u8, u8, bool, u8);
+
+struct ReorderEndNiche {
+    a: EndNiche8,
+    b: MiddleNiche4,
+}
+
+
+// standins for std types which we want to be laid out in a reasonable way
+struct RawVecDummy {
+    ptr: NonNull<u8>,
+    cap: usize,
+}
+
+struct VecDummy {
+    r: RawVecDummy,
+    len: usize,
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -270,4 +310,29 @@ pub fn main() {
     let v = Reorder2 {a: 0, b: 0, ary: [0; 6]};
     assert_eq!(size_of::<Reorder2>(), 10);
     assert!((&v.ary).as_ptr().is_aligned_to(2), "[u8; 6] should group with align-2 fields");
+
+    let v = VecDummy { r: RawVecDummy { ptr: NonNull::dangling(), cap: 0 }, len: 1 };
+    assert_eq!(ptr::from_ref(&v), ptr::from_ref(&v.r.ptr).cast(),
+               "sort niches to the front where possible");
+
+    // Ideal layouts: (bool, u8, NonZeroU16) or (NonZeroU16, u8, bool)
+    // Currently the layout algorithm will choose the latter because it doesn't attempt
+    // to aggregate multiple smaller fields to move a niche before a higher-alignment one.
+    let b = BoolInTheMiddle( NonZeroU16::new(1).unwrap(), true, 0);
+    assert!(ptr::from_ref(&b.1).addr() > ptr::from_ref(&b.2).addr());
+
+    assert_eq!(size_of::<Cow<'static, str>>(), size_of::<String>());
+
+    let v = ReorderWithNiche {a: 0, b: ' ', c: 0, ary: [0; 8]};
+    assert!((&v.ary).as_ptr().is_aligned_to(4),
+            "here [u8; 8] should group with _at least_ align-4 fields");
+    assert_eq!(ptr::from_ref(&v), ptr::from_ref(&v.b).cast(),
+               "sort niches to the front where possible");
+
+    // Neither field has a niche at the beginning so the layout algorithm should try move niches to
+    // the end which means the 8-sized field shouldn't be alignment-promoted before the 4-sized one.
+    let v = ReorderEndNiche { a: EndNiche8([0; 7], false), b: MiddleNiche4(0, 0, false, 0) };
+    assert!(ptr::from_ref(&v.a).addr() > ptr::from_ref(&v.b).addr());
+
+
 }
diff --git a/tests/ui/test-attrs/tests-listing-format-json.rs b/tests/ui/test-attrs/tests-listing-format-json.rs
index 18f1521eeeb..5afc2746fe4 100644
--- a/tests/ui/test-attrs/tests-listing-format-json.rs
+++ b/tests/ui/test-attrs/tests-listing-format-json.rs
@@ -3,6 +3,7 @@
 // run-flags: --list --format json -Zunstable-options
 // run-pass
 // check-run-results
+// only-nightly
 // normalize-stdout-test: "fake-test-src-base/test-attrs/" -> "$$DIR/"
 // normalize-stdout-test: "fake-test-src-base\\test-attrs\\" -> "$$DIR/"
 
diff --git a/tests/ui/test-attrs/tests-listing-format-json.run.stdout b/tests/ui/test-attrs/tests-listing-format-json.run.stdout
index b4131e97c34..33cc939b59f 100644
--- a/tests/ui/test-attrs/tests-listing-format-json.run.stdout
+++ b/tests/ui/test-attrs/tests-listing-format-json.run.stdout
@@ -1,5 +1,5 @@
 { "type": "suite", "event": "discovery" }
-{ "type": "test", "event": "discovered", "name": "a_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 20, "start_col": 4, "end_line": 20, "end_col": 10 }
-{ "type": "test", "event": "discovered", "name": "m_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 13, "start_col": 4, "end_line": 13, "end_col": 10 }
-{ "type": "test", "event": "discovered", "name": "z_test", "ignore": true, "ignore_message": "not yet implemented", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 17, "start_col": 4, "end_line": 17, "end_col": 10 }
+{ "type": "test", "event": "discovered", "name": "a_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 21, "start_col": 4, "end_line": 21, "end_col": 10 }
+{ "type": "test", "event": "discovered", "name": "m_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 14, "start_col": 4, "end_line": 14, "end_col": 10 }
+{ "type": "test", "event": "discovered", "name": "z_test", "ignore": true, "ignore_message": "not yet implemented", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 18, "start_col": 4, "end_line": 18, "end_col": 10 }
 { "type": "suite", "event": "completed", "tests": 3, "benchmarks": 0, "total": 3, "ignored": 1 }
diff --git a/tests/ui/traits/new-solver/exponential-trait-goals.rs b/tests/ui/traits/new-solver/exponential-trait-goals.rs
new file mode 100644
index 00000000000..b37f09ee185
--- /dev/null
+++ b/tests/ui/traits/new-solver/exponential-trait-goals.rs
@@ -0,0 +1,20 @@
+// compile-flags: -Ztrait-solver=next
+
+trait Trait {}
+
+struct W<T>(T);
+
+impl<T, U> Trait for W<(W<T>, W<U>)>
+where
+    W<T>: Trait,
+    W<U>: Trait,
+{
+}
+
+fn impls<T: Trait>() {}
+
+fn main() {
+    impls::<W<_>>();
+    //~^ ERROR type annotations needed
+    //~| ERROR overflow evaluating the requirement `W<_>: Trait`
+}
diff --git a/tests/ui/traits/new-solver/exponential-trait-goals.stderr b/tests/ui/traits/new-solver/exponential-trait-goals.stderr
new file mode 100644
index 00000000000..28a99cbbca6
--- /dev/null
+++ b/tests/ui/traits/new-solver/exponential-trait-goals.stderr
@@ -0,0 +1,23 @@
+error[E0282]: type annotations needed
+  --> $DIR/exponential-trait-goals.rs:17:5
+   |
+LL |     impls::<W<_>>();
+   |     ^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls`
+
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
+  --> $DIR/exponential-trait-goals.rs:17:5
+   |
+LL |     impls::<W<_>>();
+   |     ^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`exponential_trait_goals`)
+note: required by a bound in `impls`
+  --> $DIR/exponential-trait-goals.rs:14:13
+   |
+LL | fn impls<T: Trait>() {}
+   |             ^^^^^ required by this bound in `impls`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0275, E0282.
+For more information about an error, try `rustc --explain E0275`.