Rollup merge of #112045 - Sp00ph:update_current_impl, r=Amanieu

Followup to #111973

I somehow forgot to update the comment on `select_nth_unstable_by_key` in #111973, so this PR fixes that.

r? `@Amanieu`
diff --git a/Cargo.lock b/Cargo.lock
index 0369442..443e6d0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4380,6 +4380,15 @@
 ]
 
 [[package]]
+name = "rustdoc-gui-test"
+version = "0.1.0"
+dependencies = [
+ "compiletest",
+ "getopts",
+ "walkdir",
+]
+
+[[package]]
 name = "rustdoc-json-types"
 version = "0.1.0"
 dependencies = [
@@ -4972,22 +4981,22 @@
 
 [[package]]
 name = "thiserror"
-version = "1.0.38"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.38"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.102",
+ "syn 2.0.8",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 53331e2..8eb378a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -40,6 +40,7 @@
   "src/tools/generate-copyright",
   "src/tools/suggest-tests",
   "src/tools/generate-windows-sys",
+  "src/tools/rustdoc-gui-test",
 ]
 
 exclude = [
diff --git a/RELEASES.md b/RELEASES.md
index 85266a1..fa95df6 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,139 @@
+Version 1.70.0 (2023-06-01)
+==========================
+
+<a id="1.70.0-Language"></a>
+
+Language
+--------
+- [Relax ordering rules for `asm!` operands](https://github.com/rust-lang/rust/pull/105798/)
+- [Properly allow macro expanded `format_args` invocations to uses captures](https://github.com/rust-lang/rust/pull/106505/)
+- [Lint ambiguous glob re-exports](https://github.com/rust-lang/rust/pull/107880/)
+- [Perform const and unsafe checking for expressions in `let _ = expr` position.](https://github.com/rust-lang/rust/pull/102256/)
+
+<a id="1.70.0-Compiler"></a>
+
+Compiler
+--------
+- [Extend -Cdebuginfo with new options and named aliases](https://github.com/rust-lang/rust/pull/109808/)
+  This provides a smaller version of debuginfo for cases that only need line number information
+  (`-Cdebuginfo=line-tables-only`), which may eventually become the default for `-Cdebuginfo=1`.
+- [Make `unused_allocation` lint against `Box::new` too](https://github.com/rust-lang/rust/pull/104363/)
+- [Detect uninhabited types early in const eval](https://github.com/rust-lang/rust/pull/109435/)
+- [Switch to LLD as default linker for {arm,thumb}v4t-none-eabi](https://github.com/rust-lang/rust/pull/109721/)
+- [Add tier 3 target `loongarch64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/96971)
+- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/), 
+- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112)
+  This catches undefined behavior at runtime, and may cause existing code to fail.
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+<a id="1.70.0-Libraries"></a>
+
+Libraries
+---------
+- [Document NonZeroXxx layout guarantees](https://github.com/rust-lang/rust/pull/94786/)
+- [Windows: make `Command` prefer non-verbatim paths](https://github.com/rust-lang/rust/pull/96391/)
+- [Implement Default for some alloc/core iterators](https://github.com/rust-lang/rust/pull/99929/)
+- [Fix handling of trailing bare CR in str::lines](https://github.com/rust-lang/rust/pull/100311/)
+- [allow negative numeric literals in `concat!`](https://github.com/rust-lang/rust/pull/106844/)
+- [Add documentation about the memory layout of `Cell`](https://github.com/rust-lang/rust/pull/106921/)
+- [Use `partial_cmp` to implement tuple `lt`/`le`/`ge`/`gt`](https://github.com/rust-lang/rust/pull/108157/)
+- [Stabilize `atomic_as_ptr`](https://github.com/rust-lang/rust/pull/108419/)
+- [Stabilize `nonnull_slice_from_raw_parts`](https://github.com/rust-lang/rust/pull/97506/)
+- [Partial stabilization of `once_cell`](https://github.com/rust-lang/rust/pull/105587/)
+- [Stabilize `nonzero_min_max`](https://github.com/rust-lang/rust/pull/106633/)
+- [Flatten/inline format_args!() and (string and int) literal arguments into format_args!()](https://github.com/rust-lang/rust/pull/106824/)
+- [Stabilize movbe target feature](https://github.com/rust-lang/rust/pull/107711/)
+- [don't splice from files into pipes in io::copy](https://github.com/rust-lang/rust/pull/108283/)
+- [Add a builtin unstable `FnPtr` trait that is implemented for all function pointers](https://github.com/rust-lang/rust/pull/108080/)
+  This extends `Debug`, `Pointer`, `Hash`, `PartialEq`, `Eq`, `PartialOrd`, and `Ord`
+  implementations for function pointers with all ABIs.
+
+<a id="1.70.0-Stabilized-APIs"></a>
+
+Stabilized APIs
+---------------
+
+- [`NonZero*::MIN/MAX`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html#associatedconstant.MIN)
+- [`BinaryHeap::retain`](https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.retain)
+- [`Default for std::collections::binary_heap::IntoIter`](https://doc.rust-lang.org/stable/std/collections/binary_heap/struct.IntoIter.html)
+- [`Default for std::collections::btree_map::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoIter.html)
+- [`Default for std::collections::btree_map::{IntoKeys, Keys}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html)
+- [`Default for std::collections::btree_map::{IntoValues, Values}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html)
+- [`Default for std::collections::btree_map::Range`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.Range.html)
+- [`Default for std::collections::btree_set::{IntoIter, Iter}`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.IntoIter.html)
+- [`Default for std::collections::btree_set::Range`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.Range.html)
+- [`Default for std::collections::linked_list::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/alloc/collections/linked_list/struct.IntoIter.html)
+- [`Default for std::vec::IntoIter`](https://doc.rust-lang.org/stable/alloc/vec/struct.IntoIter.html#impl-Default-for-IntoIter%3CT,+A%3E)
+- [`Default for std::iter::Chain`](https://doc.rust-lang.org/stable/std/iter/struct.Chain.html)
+- [`Default for std::iter::Cloned`](https://doc.rust-lang.org/stable/std/iter/struct.Cloned.html)
+- [`Default for std::iter::Copied`](https://doc.rust-lang.org/stable/std/iter/struct.Copied.html)
+- [`Default for std::iter::Enumerate`](https://doc.rust-lang.org/stable/std/iter/struct.Enumerate.html)
+- [`Default for std::iter::Flatten`](https://doc.rust-lang.org/stable/std/iter/struct.Flatten.html)
+- [`Default for std::iter::Fuse`](https://doc.rust-lang.org/stable/std/iter/struct.Fuse.html)
+- [`Default for std::iter::Rev`](https://doc.rust-lang.org/stable/std/iter/struct.Rev.html)
+- [`Default for std::slice::Iter`](https://doc.rust-lang.org/stable/std/slice/struct.Iter.html)
+- [`Default for std::slice::IterMut`](https://doc.rust-lang.org/stable/std/slice/struct.IterMut.html)
+- [`Rc::into_inner`](https://doc.rust-lang.org/stable/alloc/rc/struct.Rc.html#method.into_inner)
+- [`Arc::into_inner`](https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html#method.into_inner)
+- [`std::cell::OnceCell`](https://doc.rust-lang.org/stable/std/cell/struct.OnceCell.html)
+- [`Option::is_some_and`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.is_some_and)
+- [`NonNull::slice_from_raw_parts`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.slice_from_raw_parts)
+- [`Result::is_ok_and`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.is_ok_and)
+- [`Result::is_err_and`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.is_err_and)
+- [`std::sync::atomic::Atomic*::as_ptr`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicU8.html#method.as_ptr)
+- [`std::io::IsTerminal`](https://doc.rust-lang.org/stable/std/io/trait.IsTerminal.html)
+- [`std::os::linux::net::SocketAddrExt`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.SocketAddrExt.html)
+- [`std::os::unix::net::UnixDatagram::bind_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.bind_addr)
+- [`std::os::unix::net::UnixDatagram::connect_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.connect_addr)
+- [`std::os::unix::net::UnixDatagram::send_to_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.send_to_addr)
+- [`std::os::unix::net::UnixListener::bind_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixListener.html#method.bind_addr)
+- [`std::path::Path::as_mut_os_str`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.as_mut_os_str)
+- [`std::sync::OnceLock`](https://doc.rust-lang.org/stable/std/sync/struct.OnceLock.html)
+
+<a id="1.70.0-Cargo"></a>
+
+Cargo
+-----
+
+- [Add `CARGO_PKG_README`](https://github.com/rust-lang/cargo/pull/11645/)
+- [Make `sparse` the default protocol for crates.io](https://github.com/rust-lang/cargo/pull/11791/)
+- [Accurately show status when downgrading dependencies](https://github.com/rust-lang/cargo/pull/11839/)
+- [Use registry.default for login/logout](https://github.com/rust-lang/cargo/pull/11949/)
+- [Stabilize `cargo logout`](https://github.com/rust-lang/cargo/pull/11950/)
+
+<a id="1.70.0-Misc"></a>
+
+Misc
+----
+
+- [Stabilize rustdoc `--test-run-directory`](https://github.com/rust-lang/rust/pull/103682/)
+
+<a id="1.70.0-Compatibility-Notes"></a>
+
+Compatibility Notes
+-------------------
+
+- [Prevent stable `libtest` from supporting `-Zunstable-options`](https://github.com/rust-lang/rust/pull/109044/)
+- [Perform const and unsafe checking for expressions in `let _ = expr` position.](https://github.com/rust-lang/rust/pull/102256/)
+- [WebAssembly targets enable `sign-ext` and `mutable-globals` features in codegen](https://github.com/rust-lang/rust/issues/109807)
+  This may cause incompatibility with older execution environments.
+- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112)
+  This catches undefined behavior at runtime, and may cause existing code to fail.
+
+<a id="1.70.0-Internal-Changes"></a>
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Upgrade to LLVM 16](https://github.com/rust-lang/rust/pull/109474/)
+- [Use SipHash-1-3 instead of SipHash-2-4 for StableHasher](https://github.com/rust-lang/rust/pull/107925/)
+
 Version 1.69.0 (2023-04-20)
 ==========================
 
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 7ef39f8..6646fa9 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -11,6 +11,7 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_macros::HashStable_Generic;
 use rustc_span::symbol::{kw, sym};
+#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
 use std::borrow::Cow;
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 21b2a3c..f63a9bf 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -1,144 +1,29 @@
-ast_lowering_generic_type_with_parentheses =
-    parenthesized type parameters may only be used with a `Fn` trait
-    .label = only `Fn` traits may use parentheses
-
-ast_lowering_use_angle_brackets = use angle brackets instead
-
-ast_lowering_invalid_abi =
-    invalid ABI: found `{$abi}`
-    .label = invalid ABI
-    .note = invoke `{$command}` for a full list of supported calling conventions.
-
-ast_lowering_invalid_abi_suggestion = did you mean
-
-ast_lowering_assoc_ty_parentheses =
-    parenthesized generic arguments cannot be used in associated type constraints
-
-ast_lowering_remove_parentheses = remove these parentheses
-
-ast_lowering_misplaced_impl_trait =
-    `impl Trait` only allowed in function and inherent method return types, not in {$position}
-
-ast_lowering_misplaced_assoc_ty_binding =
-    associated type bounds are only allowed in where clauses and function signatures, not in {$position}
-
-ast_lowering_underscore_expr_lhs_assign =
-    in expressions, `_` can only be used on the left-hand side of an assignment
-    .label = `_` not allowed here
-
-ast_lowering_base_expression_double_dot =
-    base expression required after `..`
-    .label = add a base expression here
-
-ast_lowering_await_only_in_async_fn_and_blocks =
-    `await` is only allowed inside `async` functions and blocks
-    .label = only allowed inside `async` functions and blocks
-
-ast_lowering_this_not_async = this is not `async`
-
-ast_lowering_generator_too_many_parameters =
-    too many parameters for a generator (expected 0 or 1 parameters)
-
-ast_lowering_closure_cannot_be_static = closures cannot be static
-
-ast_lowering_async_non_move_closure_not_supported =
-    `async` non-`move` closures with parameters are not currently supported
-    .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure
-
-ast_lowering_functional_record_update_destructuring_assignment =
-    functional record updates are not allowed in destructuring assignments
-    .suggestion = consider removing the trailing pattern
-
-ast_lowering_async_generators_not_supported =
-    `async` generators are not yet supported
-
-ast_lowering_inline_asm_unsupported_target =
-    inline assembly is unsupported on this target
-
-ast_lowering_att_syntax_only_x86 =
-    the `att_syntax` option is only supported on x86
-
 ast_lowering_abi_specified_multiple_times =
     `{$prev_name}` ABI specified multiple times
     .label = previously specified here
     .note = these ABIs are equivalent on the current target
 
-ast_lowering_clobber_abi_not_supported =
-    `clobber_abi` is not supported on this target
-
-ast_lowering_invalid_abi_clobber_abi =
-    invalid ABI for `clobber_abi`
-    .note = the following ABIs are supported on this target: {$supported_abis}
-
-ast_lowering_invalid_register =
-    invalid register `{$reg}`: {$error}
-
-ast_lowering_invalid_register_class =
-    invalid register class `{$reg_class}`: {$error}
-
-ast_lowering_invalid_asm_template_modifier_reg_class =
-    invalid asm template modifier for this register class
-
-ast_lowering_argument = argument
-
-ast_lowering_template_modifier = template modifier
-
-ast_lowering_support_modifiers =
-    the `{$class_name}` register class supports the following template modifiers: {$modifiers}
-
-ast_lowering_does_not_support_modifiers =
-    the `{$class_name}` register class does not support template modifiers
-
-ast_lowering_invalid_asm_template_modifier_const =
-    asm template modifiers are not allowed for `const` arguments
-
-ast_lowering_invalid_asm_template_modifier_sym =
-    asm template modifiers are not allowed for `sym` arguments
-
-ast_lowering_register_class_only_clobber =
-    register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
-
-ast_lowering_register_conflict =
-    register `{$reg1_name}` conflicts with register `{$reg2_name}`
-    .help = use `lateout` instead of `out` to avoid conflict
-
-ast_lowering_register1 = register `{$reg1_name}`
-
-ast_lowering_register2 = register `{$reg2_name}`
-
-ast_lowering_sub_tuple_binding =
-    `{$ident_name} @` is not allowed in a {$ctx}
-    .label = this is only allowed in slice patterns
-    .help = remove this and bind each tuple field independently
-
-ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields
-
-ast_lowering_extra_double_dot =
-    `..` can only be used once per {$ctx} pattern
-    .label = can only be used once per {$ctx} pattern
-
-ast_lowering_previously_used_here = previously used here
-
-ast_lowering_misplaced_double_dot =
-    `..` patterns are not allowed here
-    .note = only allowed in tuple, tuple struct, and slice patterns
-
-ast_lowering_misplaced_relax_trait_bound =
-    `?Trait` bounds are only permitted at the point where a type parameter is declared
-
-ast_lowering_not_supported_for_lifetime_binder_async_closure =
-    `for<...>` binders on `async` closures are not currently supported
-
 ast_lowering_arbitrary_expression_in_pattern =
     arbitrary expressions aren't allowed in patterns
 
-ast_lowering_inclusive_range_with_no_end = inclusive range with no end
+ast_lowering_argument = argument
 
-ast_lowering_trait_fn_async =
-    functions in traits cannot be declared `async`
-    .label = `async` because of this
-    .note = `async` trait functions are not currently supported
-    .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
+ast_lowering_assoc_ty_parentheses =
+    parenthesized generic arguments cannot be used in associated type constraints
+
+ast_lowering_async_generators_not_supported =
+    `async` generators are not yet supported
+
+ast_lowering_async_non_move_closure_not_supported =
+    `async` non-`move` closures with parameters are not currently supported
+    .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure
+
+ast_lowering_att_syntax_only_x86 =
+    the `att_syntax` option is only supported on x86
+
+ast_lowering_await_only_in_async_fn_and_blocks =
+    `await` is only allowed inside `async` functions and blocks
+    .label = only allowed inside `async` functions and blocks
 
 ast_lowering_bad_return_type_notation_inputs =
     argument types not allowed with return type notation
@@ -151,3 +36,118 @@
 ast_lowering_bad_return_type_notation_output =
     return type not allowed with return type notation
     .suggestion = remove the return type
+
+ast_lowering_base_expression_double_dot =
+    base expression required after `..`
+    .label = add a base expression here
+
+ast_lowering_clobber_abi_not_supported =
+    `clobber_abi` is not supported on this target
+
+ast_lowering_closure_cannot_be_static = closures cannot be static
+
+ast_lowering_does_not_support_modifiers =
+    the `{$class_name}` register class does not support template modifiers
+
+ast_lowering_extra_double_dot =
+    `..` can only be used once per {$ctx} pattern
+    .label = can only be used once per {$ctx} pattern
+
+ast_lowering_functional_record_update_destructuring_assignment =
+    functional record updates are not allowed in destructuring assignments
+    .suggestion = consider removing the trailing pattern
+
+ast_lowering_generator_too_many_parameters =
+    too many parameters for a generator (expected 0 or 1 parameters)
+
+ast_lowering_generic_type_with_parentheses =
+    parenthesized type parameters may only be used with a `Fn` trait
+    .label = only `Fn` traits may use parentheses
+
+ast_lowering_inclusive_range_with_no_end = inclusive range with no end
+
+ast_lowering_inline_asm_unsupported_target =
+    inline assembly is unsupported on this target
+
+ast_lowering_invalid_abi =
+    invalid ABI: found `{$abi}`
+    .label = invalid ABI
+    .note = invoke `{$command}` for a full list of supported calling conventions.
+
+ast_lowering_invalid_abi_clobber_abi =
+    invalid ABI for `clobber_abi`
+    .note = the following ABIs are supported on this target: {$supported_abis}
+
+ast_lowering_invalid_abi_suggestion = did you mean
+
+ast_lowering_invalid_asm_template_modifier_const =
+    asm template modifiers are not allowed for `const` arguments
+
+ast_lowering_invalid_asm_template_modifier_reg_class =
+    invalid asm template modifier for this register class
+
+ast_lowering_invalid_asm_template_modifier_sym =
+    asm template modifiers are not allowed for `sym` arguments
+
+ast_lowering_invalid_register =
+    invalid register `{$reg}`: {$error}
+
+ast_lowering_invalid_register_class =
+    invalid register class `{$reg_class}`: {$error}
+
+ast_lowering_misplaced_assoc_ty_binding =
+    associated type bounds are only allowed in where clauses and function signatures, not in {$position}
+
+ast_lowering_misplaced_double_dot =
+    `..` patterns are not allowed here
+    .note = only allowed in tuple, tuple struct, and slice patterns
+
+ast_lowering_misplaced_impl_trait =
+    `impl Trait` only allowed in function and inherent method return types, not in {$position}
+
+ast_lowering_misplaced_relax_trait_bound =
+    `?Trait` bounds are only permitted at the point where a type parameter is declared
+
+ast_lowering_not_supported_for_lifetime_binder_async_closure =
+    `for<...>` binders on `async` closures are not currently supported
+
+ast_lowering_previously_used_here = previously used here
+
+ast_lowering_register1 = register `{$reg1_name}`
+
+ast_lowering_register2 = register `{$reg2_name}`
+
+ast_lowering_register_class_only_clobber =
+    register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
+
+ast_lowering_register_conflict =
+    register `{$reg1_name}` conflicts with register `{$reg2_name}`
+    .help = use `lateout` instead of `out` to avoid conflict
+
+ast_lowering_remove_parentheses = remove these parentheses
+
+ast_lowering_sub_tuple_binding =
+    `{$ident_name} @` is not allowed in a {$ctx}
+    .label = this is only allowed in slice patterns
+    .help = remove this and bind each tuple field independently
+
+ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields
+
+ast_lowering_support_modifiers =
+    the `{$class_name}` register class supports the following template modifiers: {$modifiers}
+
+ast_lowering_template_modifier = template modifier
+
+ast_lowering_this_not_async = this is not `async`
+
+ast_lowering_trait_fn_async =
+    functions in traits cannot be declared `async`
+    .label = `async` because of this
+    .note = `async` trait functions are not currently supported
+    .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+ast_lowering_underscore_expr_lhs_assign =
+    in expressions, `_` can only be used on the left-hand side of an assignment
+    .label = `_` not allowed here
+
+ast_lowering_use_angle_brackets = use angle brackets instead
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 2f41378..2f0ac0c 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -1,48 +1,95 @@
-ast_passes_forbidden_let =
-    `let` expressions are not supported here
-    .note = only supported directly in conditions of `if` and `while` expressions
-    .not_supported_or = `||` operators are not supported in let chain expressions
-    .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains
+ast_passes_assoc_const_without_body =
+    associated constant in `impl` without body
+    .suggestion = provide a definition for the constant
 
-ast_passes_forbidden_let_stable =
-    expected expression, found statement (`let`)
-    .note = variable declaration using `let` is a statement
+ast_passes_assoc_fn_without_body =
+    associated function in `impl` without body
+    .suggestion = provide a definition for the function
+
+ast_passes_assoc_type_without_body =
+    associated type in `impl` without body
+    .suggestion = provide a definition for the type
+
+ast_passes_at_least_one_trait = at least one trait must be specified
+
+ast_passes_auto_generic = auto traits cannot have generic parameters
+    .label = auto trait cannot have generic parameters
+    .suggestion = remove the parameters
+
+ast_passes_auto_items = auto traits cannot have associated items
+    .label = {ast_passes_auto_items}
+    .suggestion = remove these associated items
+
+ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
+    .label = {ast_passes_auto_super_lifetime}
+    .suggestion = remove the super traits or lifetime bounds
+
+ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic
+
+ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
+    .cannot_have = cannot have a body
+    .invalid = the invalid body
+    .existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body
+
+ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
+
+ast_passes_const_and_async = functions cannot be both `const` and `async`
+    .const = `const` because of this
+    .async = `async` because of this
+    .label = {""}
+
+ast_passes_const_without_body =
+    free constant item without body
+    .suggestion = provide a definition for the constant
+
+ast_passes_constraint_on_negative_bound =
+    associated type constraints not allowed on negative bounds
 
 ast_passes_deprecated_where_clause_location =
     where clause not allowed here
 
-ast_passes_keyword_lifetime =
-    lifetimes cannot use keyword names
+ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
+    .label = not supported
+    .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
+    .suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax
+    .note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
 
-ast_passes_invalid_label =
-    invalid label name `{$name}`
+ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
 
-ast_passes_visibility_not_permitted =
-    visibility qualifiers are not permitted here
-    .enum_variant = enum variants and their fields always share the visibility of the enum they are in
-    .trait_impl = trait items always share the visibility of their trait
-    .individual_impl_items = place qualifiers on individual impl items instead
-    .individual_foreign_items = place qualifiers on individual foreign items instead
+ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
+    .label = in this `extern` block
+    .suggestion = remove the qualifiers
 
-ast_passes_trait_fn_const =
-    functions in traits cannot be declared const
-    .label = functions in traits cannot be const
+ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
+    .label = in this `extern` block
+    .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
 
-ast_passes_forbidden_lifetime_bound =
-    lifetime bounds cannot be used in this context
+ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
 
-ast_passes_forbidden_non_lifetime_param =
-    only lifetime parameters can be used in this context
+ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr}
+    .suggestion = remove the {$remove_descr}
+    .label = `extern` block begins here
 
-ast_passes_fn_param_too_many =
-    function can not have more than {$max_num_args} arguments
+ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
 
-ast_passes_fn_param_c_var_args_only =
-    C-variadic function must be declared with at least one named argument
+ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
+    .suggestion = remove the attribute
+    .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
+
+ast_passes_fieldless_union = unions cannot have zero fields
+
+ast_passes_fn_body_extern = incorrect function inside `extern` block
+    .cannot_have = cannot have a body
+    .suggestion = remove the invalid body
+    .help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
+    .label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body
 
 ast_passes_fn_param_c_var_args_not_last =
     `...` must be the last argument of a C-variadic function
 
+ast_passes_fn_param_c_var_args_only =
+    C-variadic function must be declared with at least one named argument
+
 ast_passes_fn_param_doc_comment =
     documentation comments cannot be applied to function parameters
     .label = doc comments are not allowed here
@@ -55,88 +102,32 @@
     .label = not semantically valid as function parameter
     .note = associated functions are those in `impl` or `trait` definitions
 
-ast_passes_forbidden_default =
-    `default` is only allowed on items in trait impls
-    .label = `default` because of this
-
-ast_passes_assoc_const_without_body =
-    associated constant in `impl` without body
-    .suggestion = provide a definition for the constant
-
-ast_passes_assoc_fn_without_body =
-    associated function in `impl` without body
-    .suggestion = provide a definition for the function
-
-ast_passes_assoc_type_without_body =
-    associated type in `impl` without body
-    .suggestion = provide a definition for the type
-
-ast_passes_const_without_body =
-    free constant item without body
-    .suggestion = provide a definition for the constant
-
-ast_passes_static_without_body =
-    free static item without body
-    .suggestion = provide a definition for the static
-
-ast_passes_ty_alias_without_body =
-    free type alias without body
-    .suggestion = provide a definition for the type
+ast_passes_fn_param_too_many =
+    function can not have more than {$max_num_args} arguments
 
 ast_passes_fn_without_body =
     free function without a body
     .suggestion = provide a definition for the function
 
-ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
+ast_passes_forbidden_default =
+    `default` is only allowed on items in trait impls
+    .label = `default` because of this
 
-ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
+ast_passes_forbidden_let =
+    `let` expressions are not supported here
+    .note = only supported directly in conditions of `if` and `while` expressions
+    .not_supported_or = `||` operators are not supported in let chain expressions
+    .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains
 
-ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr}
-    .suggestion = remove the {$remove_descr}
-    .label = `extern` block begins here
+ast_passes_forbidden_let_stable =
+    expected expression, found statement (`let`)
+    .note = variable declaration using `let` is a statement
 
-ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+ast_passes_forbidden_lifetime_bound =
+    lifetime bounds cannot be used in this context
 
-ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
-    .cannot_have = cannot have a body
-    .invalid = the invalid body
-    .existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body
-
-ast_passes_fn_body_extern = incorrect function inside `extern` block
-    .cannot_have = cannot have a body
-    .suggestion = remove the invalid body
-    .help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
-    .label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body
-
-ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
-    .label = in this `extern` block
-    .suggestion = remove the qualifiers
-
-ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
-    .label = in this `extern` block
-    .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
-
-ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic
-
-ast_passes_item_underscore = `{$kind}` items in this context need a name
-    .label = `_` is not a valid name for this `{$kind}` item
-
-ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
-
-ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
-    .help = consider using the `#[path]` attribute to specify filesystem path
-
-ast_passes_auto_generic = auto traits cannot have generic parameters
-    .label = auto trait cannot have generic parameters
-    .suggestion = remove the parameters
-
-ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
-    .label = {ast_passes_auto_super_lifetime}
-    .suggestion = remove the super traits or lifetime bounds
-
-ast_passes_auto_items = auto traits cannot have associated items
-    .label = {ast_passes_auto_items}
-    .suggestion = remove these associated items
+ast_passes_forbidden_non_lifetime_param =
+    only lifetime parameters can be used in this context
 
 ast_passes_generic_before_constraints = generic arguments must come before the first constraint
     .constraints = {$constraint_len ->
@@ -156,88 +147,97 @@
     *[other] arguments
     }
 
-ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types
-
-ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
+ast_passes_generic_default_trailing = generic parameters with a default must be trailing
 
 ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
 
-ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
-    .outer = outer `impl Trait`
-    .inner = nested `impl Trait` here
-
-ast_passes_at_least_one_trait = at least one trait must be specified
-
-ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
-
-ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
-    .suggestion = reorder the parameters: lifetimes, then consts and types
-
-ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
-    .help = use `auto trait Trait {"{}"}` instead
-
-ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
-    .negative = negative because of this
-    .unsafe = unsafe because of this
+ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
+    .help = remove one of these features
 
 ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
     .because = {$annotation} because of this
     .type = inherent impl for this type
     .only_trait = only trait implementations may be annotated with {$annotation}
 
-ast_passes_unsafe_item = {$kind} cannot be declared unsafe
+ast_passes_invalid_label =
+    invalid label name `{$name}`
 
-ast_passes_fieldless_union = unions cannot have zero fields
+ast_passes_item_underscore = `{$kind}` items in this context need a name
+    .label = `_` is not a valid name for this `{$kind}` item
 
-ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
-    .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+ast_passes_keyword_lifetime =
+    lifetimes cannot use keyword names
 
-ast_passes_generic_default_trailing = generic parameters with a default must be trailing
+ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
+    .help = consider using the `#[path]` attribute to specify filesystem path
+
+ast_passes_negative_bound_not_supported =
+    negative bounds are not supported
+
+ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
+    .outer = outer `impl Trait`
+    .inner = nested `impl Trait` here
 
 ast_passes_nested_lifetimes = nested quantification of lifetimes
 
+ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
+
+ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
+    .help = use `auto trait Trait {"{}"}` instead
+
+ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
+
+ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
+
 ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
     .note = traits are `?{$path_str}` by default
 
-ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
+ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
+    .suggestion = reorder the parameters: lifetimes, then consts and types
+
+ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
+    .label = pattern not allowed in function without body
+
+ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types
+
+ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
+    .label = pattern not allowed in foreign function
+
+ast_passes_show_span = {$msg}
+
+ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
+
+ast_passes_static_without_body =
+    free static item without body
+    .suggestion = provide a definition for the static
 
 ast_passes_tilde_const_disallowed = `~const` is not allowed here
     .trait = trait objects cannot have `~const` trait bounds
     .closure = closures cannot have `~const` trait bounds
     .function = this function is not `const`, so it cannot have `~const` trait bounds
 
-ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
+ast_passes_trait_fn_const =
+    functions in traits cannot be declared const
+    .label = functions in traits cannot be const
 
-ast_passes_const_and_async = functions cannot be both `const` and `async`
-    .const = `const` because of this
-    .async = `async` because of this
-    .label = {""}
+ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
 
-ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
-    .label = pattern not allowed in foreign function
+ast_passes_ty_alias_without_body =
+    free type alias without body
+    .suggestion = provide a definition for the type
 
-ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
-    .label = pattern not allowed in function without body
+ast_passes_unsafe_item = {$kind} cannot be declared unsafe
 
-ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
-    .label = not supported
-    .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
-    .suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax
-    .note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
+    .negative = negative because of this
+    .unsafe = unsafe because of this
 
-ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
+ast_passes_visibility_not_permitted =
+    visibility qualifiers are not permitted here
+    .enum_variant = enum variants and their fields always share the visibility of the enum they are in
+    .trait_impl = trait items always share the visibility of their trait
+    .individual_impl_items = place qualifiers on individual impl items instead
+    .individual_foreign_items = place qualifiers on individual foreign items instead
 
-ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
-    .suggestion = remove the attribute
-    .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
-
-ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
-    .help = remove one of these features
-
-ast_passes_show_span = {$msg}
-
-ast_passes_negative_bound_not_supported =
-    negative bounds are not supported
-
-ast_passes_constraint_on_negative_bound =
-    associated type constraints not allowed on negative bounds
+ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
+    .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index a7f8c99..e6cbbaf 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -1,85 +1,3 @@
-attr_expected_one_cfg_pattern =
-    expected 1 cfg-pattern
-
-attr_invalid_predicate =
-    invalid predicate `{$predicate}`
-
-attr_multiple_item =
-    multiple '{$item}' items
-
-attr_incorrect_meta_item =
-    incorrect meta item
-
-attr_unknown_meta_item =
-    unknown meta item '{$item}'
-    .label = expected one of {$expected}
-
-attr_missing_since =
-    missing 'since'
-
-attr_missing_note =
-    missing 'note'
-
-attr_multiple_stability_levels =
-    multiple stability levels
-
-attr_invalid_issue_string =
-    `issue` must be a non-zero numeric string or "none"
-    .must_not_be_zero = `issue` must not be "0", use "none" instead
-    .empty = cannot parse integer from empty string
-    .invalid_digit = invalid digit found in string
-    .pos_overflow = number too large to fit in target type
-    .neg_overflow = number too small to fit in target type
-
-attr_missing_feature =
-    missing 'feature'
-
-attr_non_ident_feature =
-    'feature' is not an identifier
-
-attr_missing_issue =
-    missing 'issue'
-
-attr_incorrect_repr_format_packed_one_or_zero_arg =
-    incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
-
-attr_invalid_repr_hint_no_paren =
-    invalid representation hint: `{$name}` does not take a parenthesized argument list
-
-attr_invalid_repr_hint_no_value =
-    invalid representation hint: `{$name}` does not take a value
-
-attr_unsupported_literal_generic =
-    unsupported literal
-attr_unsupported_literal_cfg_string =
-    literal in `cfg` predicate value must be a string
-attr_unsupported_literal_deprecated_string =
-    literal in `deprecated` value must be a string
-attr_unsupported_literal_deprecated_kv_pair =
-    item in `deprecated` must be a key/value pair
-attr_unsupported_literal_suggestion =
-    consider removing the prefix
-
-attr_invalid_repr_align_need_arg =
-    invalid `repr(align)` attribute: `align` needs an argument
-    .suggestion = supply an argument here
-
-attr_invalid_repr_generic =
-    invalid `repr({$repr_arg})` attribute: {$error_part}
-
-attr_incorrect_repr_format_align_one_arg =
-    incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
-
-attr_incorrect_repr_format_generic =
-    incorrect `repr({$repr_arg})` attribute format
-    .suggestion = use parentheses instead
-
-attr_rustc_promotable_pairing =
-    `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
-
-attr_rustc_allowed_unstable_pairing =
-    `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
-
 attr_cfg_predicate_identifier =
     `cfg` predicate key must be an identifier
 
@@ -88,6 +6,9 @@
     .help = add `#![feature(deprecated_suggestion)]` to the crate root
     .note = see #94785 for more details
 
+attr_expected_one_cfg_pattern =
+    expected 1 cfg-pattern
+
 attr_expected_single_version_literal =
     expected single version literal
 
@@ -100,8 +21,87 @@
 attr_expects_features =
     `{$name}` expects feature names
 
+attr_incorrect_meta_item =
+    incorrect meta item
+
+attr_incorrect_repr_format_align_one_arg =
+    incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
+
+attr_incorrect_repr_format_generic =
+    incorrect `repr({$repr_arg})` attribute format
+    .suggestion = use parentheses instead
+
+attr_incorrect_repr_format_packed_one_or_zero_arg =
+    incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
+
+attr_invalid_issue_string =
+    `issue` must be a non-zero numeric string or "none"
+    .must_not_be_zero = `issue` must not be "0", use "none" instead
+    .empty = cannot parse integer from empty string
+    .invalid_digit = invalid digit found in string
+    .pos_overflow = number too large to fit in target type
+    .neg_overflow = number too small to fit in target type
+
+attr_invalid_predicate =
+    invalid predicate `{$predicate}`
+
+attr_invalid_repr_align_need_arg =
+    invalid `repr(align)` attribute: `align` needs an argument
+    .suggestion = supply an argument here
+
+attr_invalid_repr_generic =
+    invalid `repr({$repr_arg})` attribute: {$error_part}
+
+attr_invalid_repr_hint_no_paren =
+    invalid representation hint: `{$name}` does not take a parenthesized argument list
+
+attr_invalid_repr_hint_no_value =
+    invalid representation hint: `{$name}` does not take a value
+
+attr_missing_feature =
+    missing 'feature'
+
+attr_missing_issue =
+    missing 'issue'
+
+attr_missing_note =
+    missing 'note'
+
+attr_missing_since =
+    missing 'since'
+
+attr_multiple_item =
+    multiple '{$item}' items
+
+attr_multiple_stability_levels =
+    multiple stability levels
+
+attr_non_ident_feature =
+    'feature' is not an identifier
+
+attr_rustc_allowed_unstable_pairing =
+    `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
+
+attr_rustc_promotable_pairing =
+    `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
+
 attr_soft_no_args =
     `soft` should not have any arguments
 
+attr_unknown_meta_item =
+    unknown meta item '{$item}'
+    .label = expected one of {$expected}
+
 attr_unknown_version_literal =
     unknown version literal format, assuming it refers to a future version
+
+attr_unsupported_literal_cfg_string =
+    literal in `cfg` predicate value must be a string
+attr_unsupported_literal_deprecated_kv_pair =
+    item in `deprecated` must be a key/value pair
+attr_unsupported_literal_deprecated_string =
+    literal in `deprecated` value must be a string
+attr_unsupported_literal_generic =
+    unsupported literal
+attr_unsupported_literal_suggestion =
+    consider removing the prefix
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index 4a616dc..67fdb67 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -1,150 +1,23 @@
-borrowck_move_unsized =
-    cannot move a value of type `{$ty}`
-    .label = the size of `{$ty}` cannot be statically determined
-
-borrowck_higher_ranked_lifetime_error =
-    higher-ranked lifetime error
-
-borrowck_could_not_prove =
-    could not prove `{$predicate}`
-
-borrowck_could_not_normalize =
-    could not normalize `{$value}`
-
-borrowck_higher_ranked_subtype_error =
-    higher-ranked subtype error
-
-borrowck_generic_does_not_live_long_enough =
-    `{$kind}` does not live long enough
-
-borrowck_move_borrowed =
-    cannot move out of `{$desc}` because it is borrowed
-
-borrowck_var_does_not_need_mut =
-    variable does not need to be mutable
-    .suggestion = remove this `mut`
-
-borrowck_var_cannot_escape_closure =
-    captured variable cannot escape `FnMut` closure body
-    .note = `FnMut` closures only have access to their captured variables while they are executing...
-    .cannot_escape = ...therefore, they cannot allow references to captured variables to escape
-
-borrowck_var_here_defined = variable defined here
-
-borrowck_var_here_captured = variable captured here
-
-borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
-
-borrowck_returned_closure_escaped =
-    returns a closure that contains a reference to a captured variable, which then escapes the closure body
-
-borrowck_returned_async_block_escaped =
-    returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
-
-borrowck_returned_ref_escaped =
-    returns a reference to a captured variable which escapes the closure body
-
-borrowck_lifetime_constraints_error =
-    lifetime may not live long enough
-
-borrowck_returned_lifetime_wrong =
-    {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`
-
-borrowck_returned_lifetime_short =
-    {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`
-
-borrowck_used_impl_require_static =
-    the used `impl` has a `'static` requirement
-
-borrowck_borrow_due_to_use_generator =
-    borrow occurs due to use in generator
-
-borrowck_use_due_to_use_generator =
-    use occurs due to use in generator
+borrowck_assign_due_to_use_closure =
+    assignment occurs due to use in closure
 
 borrowck_assign_due_to_use_generator =
     assign occurs due to use in generator
 
+borrowck_assign_part_due_to_use_closure =
+    assignment to part occurs due to use in closure
+
 borrowck_assign_part_due_to_use_generator =
     assign to part occurs due to use in generator
 
 borrowck_borrow_due_to_use_closure =
     borrow occurs due to use in closure
 
-borrowck_use_due_to_use_closure =
-    use occurs due to use in closure
-
-borrowck_assign_due_to_use_closure =
-    assignment occurs due to use in closure
-
-borrowck_assign_part_due_to_use_closure =
-    assignment to part occurs due to use in closure
-
-borrowck_capture_immute =
-    capture is immutable because of use here
-
-borrowck_capture_mut =
-    capture is mutable because of use here
-
-borrowck_capture_move =
-    capture is moved because of use here
-
-borrowck_var_borrow_by_use_place_in_generator =
-    {$is_single_var ->
-        *[true] borrow occurs
-        [false] borrows occur
-    } due to use of {$place} in generator
-
-borrowck_var_borrow_by_use_place_in_closure =
-    {$is_single_var ->
-        *[true] borrow occurs
-        [false] borrows occur
-    } due to use of {$place} in closure
-
-borrowck_var_borrow_by_use_in_generator =
+borrowck_borrow_due_to_use_generator =
     borrow occurs due to use in generator
 
-borrowck_var_borrow_by_use_in_closure =
-    borrow occurs due to use in closure
-
-borrowck_var_move_by_use_place_in_generator =
-    move occurs due to use of {$place} in generator
-
-borrowck_var_move_by_use_place_in_closure =
-    move occurs due to use of {$place} in closure
-
-borrowck_var_move_by_use_in_generator =
-    move occurs due to use in generator
-
-borrowck_var_move_by_use_in_closure =
-    move occurs due to use in closure
-
-borrowck_partial_var_move_by_use_in_generator =
-    variable {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to use in generator
-
-borrowck_partial_var_move_by_use_in_closure =
-    variable {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to use in closure
-
-borrowck_var_first_borrow_by_use_place_in_generator =
-    first borrow occurs due to use of {$place} in generator
-
-borrowck_var_first_borrow_by_use_place_in_closure =
-    first borrow occurs due to use of {$place} in closure
-
-borrowck_var_second_borrow_by_use_place_in_generator =
-    second borrow occurs due to use of {$place} in generator
-
-borrowck_var_second_borrow_by_use_place_in_closure =
-    second borrow occurs due to use of {$place} in closure
-
-borrowck_var_mutable_borrow_by_use_place_in_closure =
-    mutable borrow occurs due to use of {$place} in closure
+borrowck_calling_operator_moves_lhs =
+    calling this operator moves the left-hand side
 
 borrowck_cannot_move_when_borrowed =
     cannot move out of {$place ->
@@ -160,11 +33,67 @@
         *[other] {$value_place}
     } occurs here
 
-borrowck_opaque_type_non_generic_param =
-    expected generic {$kind} parameter, found `{$ty}`
-    .label = {STREQ($ty, "'static") ->
-        [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
-        *[other] this generic parameter must be used with a generic {$kind} parameter
+borrowck_capture_immute =
+    capture is immutable because of use here
+
+borrowck_capture_move =
+    capture is moved because of use here
+
+borrowck_capture_mut =
+    capture is mutable because of use here
+
+borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
+
+borrowck_closure_invoked_twice =
+    closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment
+
+borrowck_closure_moved_twice =
+    closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment
+
+borrowck_consider_borrow_type_contents =
+    help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
+
+borrowck_could_not_normalize =
+    could not normalize `{$value}`
+
+borrowck_could_not_prove =
+    could not prove `{$predicate}`
+
+borrowck_func_take_self_moved_place =
+    `{$func}` takes ownership of the receiver `self`, which moves {$place_name}
+
+borrowck_generic_does_not_live_long_enough =
+    `{$kind}` does not live long enough
+
+borrowck_higher_ranked_lifetime_error =
+    higher-ranked lifetime error
+
+borrowck_higher_ranked_subtype_error =
+    higher-ranked subtype error
+
+borrowck_lifetime_constraints_error =
+    lifetime may not live long enough
+
+borrowck_move_borrowed =
+    cannot move out of `{$desc}` because it is borrowed
+
+borrowck_move_out_place_here =
+    {$place} is moved here
+
+borrowck_move_unsized =
+    cannot move a value of type `{$ty}`
+    .label = the size of `{$ty}` cannot be statically determined
+
+borrowck_moved_a_fn_once_in_call =
+    this value implements `FnOnce`, which causes it to be moved when called
+
+borrowck_moved_due_to_await =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to this {$is_loop_message ->
+        [true] await, in previous iteration of loop
+        *[false] await
     }
 
 borrowck_moved_due_to_call =
@@ -176,15 +105,6 @@
         *[false] call
     }
 
-borrowck_moved_due_to_usage_in_operator =
-    {$place_name} {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to usage in {$is_loop_message ->
-        [true] operator, in previous iteration of loop
-        *[false] operator
-    }
-
 borrowck_moved_due_to_implicit_into_iter_call =
     {$place_name} {$is_partial ->
         [true] partially moved
@@ -203,13 +123,74 @@
         *[false] call
     }
 
-borrowck_moved_due_to_await =
+borrowck_moved_due_to_usage_in_operator =
     {$place_name} {$is_partial ->
         [true] partially moved
         *[false] moved
-    } due to this {$is_loop_message ->
-        [true] await, in previous iteration of loop
-        *[false] await
+    } due to usage in {$is_loop_message ->
+        [true] operator, in previous iteration of loop
+        *[false] operator
+    }
+
+borrowck_opaque_type_non_generic_param =
+    expected generic {$kind} parameter, found `{$ty}`
+    .label = {STREQ($ty, "'static") ->
+        [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
+        *[other] this generic parameter must be used with a generic {$kind} parameter
+    }
+
+borrowck_partial_var_move_by_use_in_closure =
+    variable {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to use in closure
+
+borrowck_partial_var_move_by_use_in_generator =
+    variable {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to use in generator
+
+borrowck_returned_async_block_escaped =
+    returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
+
+borrowck_returned_closure_escaped =
+    returns a closure that contains a reference to a captured variable, which then escapes the closure body
+
+borrowck_returned_lifetime_short =
+    {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`
+
+borrowck_returned_lifetime_wrong =
+    {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`
+
+borrowck_returned_ref_escaped =
+    returns a reference to a captured variable which escapes the closure body
+
+borrowck_suggest_create_freash_reborrow =
+    consider reborrowing the `Pin` instead of moving it
+
+borrowck_suggest_iterate_over_slice =
+    consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
+
+borrowck_ty_no_impl_copy =
+    {$is_partial_move ->
+        [true] partial move
+        *[false] move
+    } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait
+
+borrowck_use_due_to_use_closure =
+    use occurs due to use in closure
+
+borrowck_use_due_to_use_generator =
+    use occurs due to use in generator
+
+borrowck_used_impl_require_static =
+    the used `impl` has a `'static` requirement
+
+borrowck_value_capture_here =
+    value captured {$is_within ->
+        [true] here by generator
+        *[false] here
     }
 
 borrowck_value_moved_here =
@@ -224,41 +205,60 @@
         *[false] {""}
     }
 
-borrowck_consider_borrow_type_contents =
-    help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
+borrowck_var_borrow_by_use_in_closure =
+    borrow occurs due to use in closure
 
-borrowck_moved_a_fn_once_in_call =
-    this value implements `FnOnce`, which causes it to be moved when called
+borrowck_var_borrow_by_use_in_generator =
+    borrow occurs due to use in generator
 
-borrowck_calling_operator_moves_lhs =
-    calling this operator moves the left-hand side
+borrowck_var_borrow_by_use_place_in_closure =
+    {$is_single_var ->
+        *[true] borrow occurs
+        [false] borrows occur
+    } due to use of {$place} in closure
 
-borrowck_func_take_self_moved_place =
-    `{$func}` takes ownership of the receiver `self`, which moves {$place_name}
+borrowck_var_borrow_by_use_place_in_generator =
+    {$is_single_var ->
+        *[true] borrow occurs
+        [false] borrows occur
+    } due to use of {$place} in generator
 
-borrowck_suggest_iterate_over_slice =
-    consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
+borrowck_var_cannot_escape_closure =
+    captured variable cannot escape `FnMut` closure body
+    .note = `FnMut` closures only have access to their captured variables while they are executing...
+    .cannot_escape = ...therefore, they cannot allow references to captured variables to escape
 
-borrowck_suggest_create_freash_reborrow =
-    consider reborrowing the `Pin` instead of moving it
+borrowck_var_does_not_need_mut =
+    variable does not need to be mutable
+    .suggestion = remove this `mut`
 
-borrowck_value_capture_here =
-    value captured {$is_within ->
-        [true] here by generator
-        *[false] here
-    }
+borrowck_var_first_borrow_by_use_place_in_closure =
+    first borrow occurs due to use of {$place} in closure
 
-borrowck_move_out_place_here =
-    {$place} is moved here
+borrowck_var_first_borrow_by_use_place_in_generator =
+    first borrow occurs due to use of {$place} in generator
 
-borrowck_closure_invoked_twice =
-    closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment
+borrowck_var_here_captured = variable captured here
 
-borrowck_closure_moved_twice =
-    closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment
+borrowck_var_here_defined = variable defined here
 
-borrowck_ty_no_impl_copy =
-    {$is_partial_move ->
-        [true] partial move
-        *[false] move
-    } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait
+borrowck_var_move_by_use_in_closure =
+    move occurs due to use in closure
+
+borrowck_var_move_by_use_in_generator =
+    move occurs due to use in generator
+
+borrowck_var_move_by_use_place_in_closure =
+    move occurs due to use of {$place} in closure
+
+borrowck_var_move_by_use_place_in_generator =
+    move occurs due to use of {$place} in generator
+
+borrowck_var_mutable_borrow_by_use_place_in_closure =
+    mutable borrow occurs due to use of {$place} in closure
+
+borrowck_var_second_borrow_by_use_place_in_closure =
+    second borrow occurs due to use of {$place} in closure
+
+borrowck_var_second_borrow_by_use_place_in_generator =
+    second borrow occurs due to use of {$place} in generator
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 04b8174..15d73ed 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1635,34 +1635,6 @@ pub(crate) fn describe_place_for_conflicting_borrow(
             })
     }
 
-    /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
-    ///
-    /// Depending on the origin of the StorageDeadOrDrop, this may be
-    /// reported as either a drop or an illegal mutation of a borrowed value.
-    /// The latter is preferred when the this is a drop triggered by a
-    /// reassignment, as it's more user friendly to report a problem with the
-    /// explicit assignment than the implicit drop.
-    #[instrument(level = "debug", skip(self))]
-    pub(crate) fn report_storage_dead_or_drop_of_borrowed(
-        &mut self,
-        location: Location,
-        place_span: (Place<'tcx>, Span),
-        borrow: &BorrowData<'tcx>,
-    ) {
-        // It's sufficient to check the last desugaring as Replace is the last
-        // one to be applied.
-        if let Some(DesugaringKind::Replace) = place_span.1.desugaring_kind() {
-            self.report_illegal_mutation_of_borrowed(location, place_span, borrow)
-        } else {
-            self.report_borrowed_value_does_not_live_long_enough(
-                location,
-                borrow,
-                place_span,
-                Some(WriteKind::StorageDeadOrDrop),
-            )
-        }
-    }
-
     /// This means that some data referenced by `borrow` needs to live
     /// past the point where the StorageDeadOrDrop of `place` occurs.
     /// This is usually interpreted as meaning that `place` has too
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 4bde372..d0e17bf 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -641,13 +641,8 @@ fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
             let Some(hir::Node::Item(item)) = node else { return; };
             let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
             let body = self.infcx.tcx.hir().body(body_id);
-            let mut assign_span = span;
-            // Drop desugaring is done at MIR build so it's not in the HIR
-            if let Some(DesugaringKind::Replace) = span.desugaring_kind() {
-                assign_span.remove_mark();
-            }
 
-            let mut v = V { assign_span, err, ty, suggested: false };
+            let mut v = V { assign_span: span, err, ty, suggested: false };
             v.visit_body(body);
             if !v.suggested {
                 err.help(format!(
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 036391d..b2ff25e 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -112,11 +112,13 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             TerminatorKind::SwitchInt { discr, targets: _ } => {
                 self.consume_operand(location, discr);
             }
-            TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
+            TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => {
+                let write_kind =
+                    if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
                 self.access_place(
                     location,
                     *drop_place,
-                    (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
+                    (AccessDepth::Drop, Write(write_kind)),
                     LocalMutationIsAllowed::Yes,
                 );
             }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 9277a26..a53ea10 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -685,17 +685,19 @@ fn visit_terminator_before_primary_effect(
             TerminatorKind::SwitchInt { discr, targets: _ } => {
                 self.consume_operand(loc, (discr, span), flow_state);
             }
-            TerminatorKind::Drop { place, target: _, unwind: _ } => {
+            TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
                 debug!(
                     "visit_terminator_drop \
                      loc: {:?} term: {:?} place: {:?} span: {:?}",
                     loc, term, place, span
                 );
 
+                let write_kind =
+                    if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
                 self.access_place(
                     loc,
                     (*place, span),
-                    (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
+                    (AccessDepth::Drop, Write(write_kind)),
                     LocalMutationIsAllowed::Yes,
                     flow_state,
                 );
@@ -885,6 +887,7 @@ enum ReadKind {
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum WriteKind {
     StorageDeadOrDrop,
+    Replace,
     MutableBorrow(BorrowKind),
     Mutate,
     Move,
@@ -1132,13 +1135,21 @@ fn check_access_for_conflict(
                             this.buffer_error(err);
                         }
                         WriteKind::StorageDeadOrDrop => this
-                            .report_storage_dead_or_drop_of_borrowed(location, place_span, borrow),
+                            .report_borrowed_value_does_not_live_long_enough(
+                                location,
+                                borrow,
+                                place_span,
+                                Some(WriteKind::StorageDeadOrDrop),
+                            ),
                         WriteKind::Mutate => {
                             this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
                         }
                         WriteKind::Move => {
                             this.report_move_out_while_borrowed(location, place_span, borrow)
                         }
+                        WriteKind::Replace => {
+                            this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
+                        }
                     }
                     Control::Break
                 }
@@ -1982,12 +1993,14 @@ fn check_access_permissions(
 
             Reservation(
                 WriteKind::Move
+                | WriteKind::Replace
                 | WriteKind::StorageDeadOrDrop
                 | WriteKind::MutableBorrow(BorrowKind::Shared)
                 | WriteKind::MutableBorrow(BorrowKind::Shallow),
             )
             | Write(
                 WriteKind::Move
+                | WriteKind::Replace
                 | WriteKind::StorageDeadOrDrop
                 | WriteKind::MutableBorrow(BorrowKind::Shared)
                 | WriteKind::MutableBorrow(BorrowKind::Shallow),
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 95dcc8d..f527eee 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -1,12 +1,12 @@
 use std::fmt;
 
+use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::canonical::Canonical;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
-use rustc_trait_selection::traits::query::{Fallible, NoSolution};
 use rustc_trait_selection::traits::ObligationCause;
 
 use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
@@ -30,14 +30,15 @@ pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
         locations: Locations,
         category: ConstraintCategory<'tcx>,
         op: Op,
-    ) -> Fallible<R>
+    ) -> Result<R, ErrorGuaranteed>
     where
         Op: type_op::TypeOp<'tcx, Output = R>,
         Op::ErrorInfo: ToUniverseInfo<'tcx>,
     {
         let old_universe = self.infcx.universe();
 
-        let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
+        let TypeOpOutput { output, constraints, error_info } =
+            op.fully_perform(self.infcx, locations.span(self.body))?;
 
         debug!(?output, ?constraints);
 
@@ -135,14 +136,11 @@ pub(super) fn prove_predicate(
     ) {
         let param_env = self.param_env;
         let predicate = predicate.to_predicate(self.tcx());
-        self.fully_perform_op(
+        let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             locations,
             category,
             param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
-        )
-        .unwrap_or_else(|NoSolution| {
-            span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
-        })
+        );
     }
 
     pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
@@ -163,15 +161,12 @@ pub(super) fn normalize_with_category<T>(
         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
     {
         let param_env = self.param_env;
-        self.fully_perform_op(
+        let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             location.to_locations(),
             category,
             param_env.and(type_op::normalize::Normalize::new(value)),
-        )
-        .unwrap_or_else(|NoSolution| {
-            span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
-            value
-        })
+        );
+        result.unwrap_or(value)
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -181,18 +176,11 @@ pub(super) fn ascribe_user_type(
         user_ty: ty::UserType<'tcx>,
         span: Span,
     ) {
-        self.fully_perform_op(
+        let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             Locations::All(span),
             ConstraintCategory::Boring,
             self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
-        )
-        .unwrap_or_else(|err| {
-            span_mirbug!(
-                self,
-                span,
-                "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
-            );
-        });
+        );
     }
 
     /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
@@ -219,7 +207,7 @@ pub(super) fn ascribe_user_type_skip_wf(
 
         let cause = ObligationCause::dummy_with_span(span);
         let param_env = self.param_env;
-        self.fully_perform_op(
+        let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             Locations::All(span),
             ConstraintCategory::Boring,
             type_op::custom::CustomTypeOp::new(
@@ -230,13 +218,6 @@ pub(super) fn ascribe_user_type_skip_wf(
                 },
                 "ascribe_user_type_skip_wf",
             ),
-        )
-        .unwrap_or_else(|err| {
-            span_mirbug!(
-                self,
-                span,
-                "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
-            );
-        });
+        );
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index bd01c0b..c8ec125 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -8,7 +8,7 @@
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
 use type_op::TypeOpOutput;
@@ -243,18 +243,11 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
             let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
                 .param_env
                 .and(type_op::normalize::Normalize::new(ty))
-                .fully_perform(self.infcx)
-                .unwrap_or_else(|_| {
-                    let guar = self
-                        .infcx
-                        .tcx
-                        .sess
-                        .delay_span_bug(span, format!("failed to normalize {:?}", ty));
-                    TypeOpOutput {
-                        output: self.infcx.tcx.ty_error(guar),
-                        constraints: None,
-                        error_info: None,
-                    }
+                .fully_perform(self.infcx, span)
+                .unwrap_or_else(|guar| TypeOpOutput {
+                    output: self.infcx.tcx.ty_error(guar),
+                    constraints: None,
+                    error_info: None,
                 });
             if let Some(c) = constraints_normalize {
                 constraints.push(c)
@@ -324,7 +317,7 @@ fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<&'tcx QueryRegionConstr
         let TypeOpOutput { output: bounds, constraints, .. } = self
             .param_env
             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
-            .fully_perform(self.infcx)
+            .fully_perform(self.infcx, DUMMY_SP)
             .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
         debug!(?bounds, ?constraints);
         self.add_outlives_bounds(bounds);
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 9731b10..eb02604 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -3,8 +3,9 @@
 use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
+use rustc_middle::traits::query::DropckOutlivesResult;
 use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
-use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
+use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 use std::rc::Rc;
@@ -568,10 +569,15 @@ fn compute_drop_data(
     ) -> DropData<'tcx> {
         debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
 
-        let param_env = typeck.param_env;
-        let TypeOpOutput { output, constraints, .. } =
-            param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap();
-
-        DropData { dropck_result: output, region_constraint_data: constraints }
+        match typeck
+            .param_env
+            .and(DropckOutlives::new(dropped_ty))
+            .fully_perform(typeck.infcx, DUMMY_SP)
+        {
+            Ok(TypeOpOutput { output, constraints, .. }) => {
+                DropData { dropck_result: output, region_constraint_data: constraints }
+            }
+            Err(_) => DropData { dropck_result: Default::default(), region_constraint_data: None },
+        }
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index cf204cf..51a84ce 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -10,6 +10,7 @@
 use hir::OpaqueTyOrigin;
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
@@ -26,6 +27,7 @@
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::*;
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
@@ -41,7 +43,7 @@
 use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
-use rustc_trait_selection::traits::query::Fallible;
+
 use rustc_trait_selection::traits::PredicateObligation;
 
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
@@ -216,24 +218,22 @@ pub(crate) fn type_check<'mir, 'tcx>(
     let opaque_type_values = opaque_type_values
         .into_iter()
         .map(|(opaque_type_key, decl)| {
-            checker
-                .fully_perform_op(
-                    Locations::All(body.span),
-                    ConstraintCategory::OpaqueType,
-                    CustomTypeOp::new(
-                        |ocx| {
-                            ocx.infcx.register_member_constraints(
-                                param_env,
-                                opaque_type_key,
-                                decl.hidden_type.ty,
-                                decl.hidden_type.span,
-                            );
-                            Ok(())
-                        },
-                        "opaque_type_map",
-                    ),
-                )
-                .unwrap();
+            let _: Result<_, ErrorGuaranteed> = checker.fully_perform_op(
+                Locations::All(body.span),
+                ConstraintCategory::OpaqueType,
+                CustomTypeOp::new(
+                    |ocx| {
+                        ocx.infcx.register_member_constraints(
+                            param_env,
+                            opaque_type_key,
+                            decl.hidden_type.ty,
+                            decl.hidden_type.span,
+                        );
+                        Ok(())
+                    },
+                    "opaque_type_map",
+                ),
+            );
             let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
             trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
             if hidden_type.has_non_region_infer() {
@@ -1134,7 +1134,7 @@ fn sub_types(
         sup: Ty<'tcx>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
-    ) -> Fallible<()> {
+    ) -> Result<(), NoSolution> {
         // Use this order of parameters because the sup type is usually the
         // "expected" type in diagnostics.
         self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
@@ -1147,7 +1147,7 @@ fn eq_types(
         found: Ty<'tcx>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
-    ) -> Fallible<()> {
+    ) -> Result<(), NoSolution> {
         self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
     }
 
@@ -1159,7 +1159,7 @@ fn relate_type_and_user_type(
         user_ty: &UserTypeProjection,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
-    ) -> Fallible<()> {
+    ) -> Result<(), NoSolution> {
         let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
         trace!(?annotated_type);
         let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
@@ -2755,11 +2755,20 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
     /// constraints in our `InferCtxt`
     type ErrorInfo = InstantiateOpaqueType<'tcx>;
 
-    fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
-        let (mut output, region_constraints) = scrape_region_constraints(infcx, |ocx| {
-            ocx.register_obligations(self.obligations.clone());
-            Ok(())
-        })?;
+    fn fully_perform(
+        mut self,
+        infcx: &InferCtxt<'tcx>,
+        span: Span,
+    ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
+        let (mut output, region_constraints) = scrape_region_constraints(
+            infcx,
+            |ocx| {
+                ocx.register_obligations(self.obligations.clone());
+                Ok(())
+            },
+            "InstantiateOpaqueType",
+            span,
+        )?;
         self.region_constraints = Some(region_constraints);
         output.error_info = Some(self);
         Ok(output)
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index dd1f89e..8c4bfb2 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,12 +1,13 @@
+use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_infer::traits::PredicateObligations;
 use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
-use rustc_trait_selection::traits::query::Fallible;
 
 use crate::constraints::OutlivesConstraint;
 use crate::diagnostics::UniverseInfo;
@@ -30,7 +31,7 @@ pub(super) fn relate_types(
         b: Ty<'tcx>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
-    ) -> Fallible<()> {
+    ) -> Result<(), NoSolution> {
         TypeRelating::new(
             self.infcx,
             NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)),
@@ -47,7 +48,7 @@ pub(super) fn eq_substs(
         b: ty::SubstsRef<'tcx>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
-    ) -> Fallible<()> {
+    ) -> Result<(), NoSolution> {
         TypeRelating::new(
             self.infcx,
             NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
@@ -185,7 +186,7 @@ fn forbid_inference_vars() -> bool {
     }
 
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
-        match self.type_checker.fully_perform_op(
+        let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
             self.locations,
             self.category,
             InstantiateOpaqueType {
@@ -194,16 +195,6 @@ fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
                 base_universe: None,
                 region_constraints: None,
             },
-        ) {
-            Ok(()) => {}
-            Err(_) => {
-                // It's a bit redundant to delay a bug here, but I'd rather
-                // delay more bugs than accidentally not delay a bug at all.
-                self.type_checker.tcx().sess.delay_span_bug(
-                    self.locations.span(self.type_checker.body),
-                    "errors selecting obligation during MIR typeck",
-                );
-            }
-        };
+        );
     }
 }
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 3b458b1..f00cd39 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -1,62 +1,101 @@
-builtin_macros_requires_cfg_pattern =
-    macro requires a cfg-pattern as an argument
-    .label = cfg-pattern required
-
-builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
-
 builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
 
+builtin_macros_asm_clobber_abi = clobber_abi
+builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs
+builtin_macros_asm_clobber_outputs = generic outputs
+
+builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
+    .label = previously here
+    .arg = duplicate argument
+
+builtin_macros_asm_expected_comma = expected token: `,`
+    .label = expected `,`
+
+builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
+    [true] options
+    *[false] clobber_abi, options
+    }, or additional template string
+
+builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
+
+builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
+
+builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
+
+builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option
+
+builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided
+    .label = this option was already provided
+    .suggestion = remove this option
+
+builtin_macros_asm_pos_after = positional arguments cannot follow named arguments or explicit register arguments
+    .pos = positional argument
+    .named = named argument
+    .explicit = explicit register argument
+
+builtin_macros_asm_pure_combine = the `pure` option must be combined with either `nomem` or `readonly`
+
+builtin_macros_asm_pure_no_output = asm with the `pure` option must have at least one output
+
+builtin_macros_asm_requires_template = requires at least a template string argument
+
+builtin_macros_asm_sym_no_path = expected a path for argument to `sym`
+
+builtin_macros_asm_underscore_input = _ cannot be used for input operands
+
+builtin_macros_assert_missing_comma = unexpected string literal
+    .suggestion = try adding a comma
+
 builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument
     .label = boolean expression required
 
 builtin_macros_assert_requires_expression = macro requires an expression as an argument
     .suggestion = try removing semicolon
 
-builtin_macros_assert_missing_comma = unexpected string literal
-    .suggestion = try adding a comma
+builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
+    .label = not applicable here
+    .label2 = not a `struct`, `enum` or `union`
 
-builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
-builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
-builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal
+builtin_macros_cannot_derive_union = this trait cannot be derived for unions
+
 builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments
 
 builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path is accessible or not
 
-builtin_macros_concat_bytestr = cannot concatenate a byte string literal
-
-builtin_macros_concat_missing_literal = expected a literal
-    .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
-
-builtin_macros_concat_bytes_missing_literal = expected a byte literal
-    .note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
-
-builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals
-    .byte_char = try using a byte character
-    .byte_str = try using a byte string
-    .number_array = try wrapping the number in an array
-
-builtin_macros_concat_bytes_oob = numeric literal is out of bounds
-
-builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8`
-
+builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal
+builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
+builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
 builtin_macros_concat_bytes_array = cannot concatenate doubly nested array
     .note = byte strings are treated as arrays of bytes
     .help = try flattening the array
 
 builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number
 
-builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments
-builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma
+builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals
+    .byte_char = try using a byte character
+    .byte_str = try using a byte string
+    .number_array = try wrapping the number in an array
+
+builtin_macros_concat_bytes_missing_literal = expected a byte literal
+    .note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8`
+
+builtin_macros_concat_bytes_oob = numeric literal is out of bounds
+
+builtin_macros_concat_bytestr = cannot concatenate a byte string literal
+
 builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
 
-builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
-    .label = not applicable here
-    .label2 = not a `struct`, `enum` or `union`
+builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments
+builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma
+builtin_macros_concat_missing_literal = expected a literal
+    .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
 
-builtin_macros_unexpected_lit = expected path to a trait, found literal
-    .label = not a trait
-    .str_lit = try using `#[derive({$sym})]`
-    .other = for example, write `#[derive(Debug)]` for `Debug`
+builtin_macros_default_arg = `#[default]` attribute does not accept a value
+    .suggestion = try using `#[default]`
+
+builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros
 
 builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments
     .suggestion = remove the arguments
@@ -64,66 +103,38 @@
 builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
     .suggestion = remove the value
 
-builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros
-
-builtin_macros_cannot_derive_union = this trait cannot be derived for unions
-
-builtin_macros_no_default_variant = no default declared
-    .help = make a unit variant default by placing `#[default]` above it
-    .suggestion = make `{$ident}` default
-
-builtin_macros_multiple_defaults = multiple declared defaults
-    .label = first default
-    .additional = additional default
-    .note = only one variant can be default
-    .suggestion = make `{$ident}` default
-
-builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
-    .help = consider a manual implementation of `Default`
-
-builtin_macros_non_exhaustive_default = default variant must be exhaustive
-    .label = declared `#[non_exhaustive]` here
-    .help = consider a manual implementation of `Default`
-
-builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
-    .note = only one `#[default]` attribute is needed
-    .label = `#[default]` used here
-    .label_again = `#[default]` used again here
-    .help = try removing {$only_one ->
-    [true] this
-    *[false] these
-    }
-
-builtin_macros_default_arg = `#[default]` attribute does not accept a value
-    .suggestion = try using `#[default]`
-
-builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
-
 builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
     .cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead
     .other = use `std::env::var("{$var}")` to read the variable at run time
 
-builtin_macros_format_requires_string = requires at least a format string argument
+builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
+
+builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
 
 builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
     .label1 = previously here
     .label2 = duplicate argument
 
+builtin_macros_format_no_arg_named = there is no argument named `{$name}`
+    .note = did you intend to capture a variable `{$name}` from the surrounding scope?
+    .note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
+
+builtin_macros_format_pos_mismatch = {$n} positional {$n ->
+    [one] argument
+    *[more] arguments
+    } in format string, but {$desc}
+
 builtin_macros_format_positional_after_named = positional arguments cannot follow named arguments
     .label = positional arguments must be before named arguments
     .named_args = named argument
 
+builtin_macros_format_requires_string = requires at least a format string argument
+
 builtin_macros_format_string_invalid = invalid format string: {$desc}
     .label = {$label1} in format string
     .note = {$note}
     .second_label = {$label}
 
-builtin_macros_sugg = consider using a positional formatting argument instead
-
-builtin_macros_format_no_arg_named = there is no argument named `{$name}`
-    .note = did you intend to capture a variable `{$name}` from the surrounding scope?
-    .note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
-
 builtin_macros_format_unknown_trait = unknown format trait `{$ty}`
     .note = the only appropriate formatting traits are:
                                             - ``, which uses the `Display` trait
@@ -145,60 +156,49 @@
 builtin_macros_format_unused_args = multiple unused formatting arguments
     .label = multiple missing formatting specifiers
 
-builtin_macros_format_pos_mismatch = {$n} positional {$n ->
-    [one] argument
-    *[more] arguments
-    } in format string, but {$desc}
+builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
 
-builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items
+builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
+    .note = only one `#[default]` attribute is needed
+    .label = `#[default]` used here
+    .label_again = `#[default]` used again here
+    .help = try removing {$only_one ->
+    [true] this
+    *[false] these
+    }
+
+builtin_macros_multiple_defaults = multiple declared defaults
+    .label = first default
+    .additional = additional default
+    .note = only one variant can be default
+    .suggestion = make `{$ident}` default
+
+builtin_macros_no_default_variant = no default declared
+    .help = make a unit variant default by placing `#[default]` above it
+    .suggestion = make `{$ident}` default
+
+builtin_macros_non_exhaustive_default = default variant must be exhaustive
+    .label = declared `#[non_exhaustive]` here
+    .help = consider a manual implementation of `Default`
+
+builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
+    .help = consider a manual implementation of `Default`
+
+builtin_macros_requires_cfg_pattern =
+    macro requires a cfg-pattern as an argument
+    .label = cfg-pattern required
+
+builtin_macros_sugg = consider using a positional formatting argument instead
 
 builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
     .label = `{$kind}` because of this
 
-builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
-
-builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
-
-builtin_macros_asm_pure_combine = the `pure` option must be combined with either `nomem` or `readonly`
-
-builtin_macros_asm_pure_no_output = asm with the `pure` option must have at least one output
-
-builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
-
-builtin_macros_asm_requires_template = requires at least a template string argument
-
-builtin_macros_asm_expected_comma = expected token: `,`
-    .label = expected `,`
-
-builtin_macros_asm_underscore_input = _ cannot be used for input operands
-
-builtin_macros_asm_sym_no_path = expected a path for argument to `sym`
-
-builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
-    [true] options
-    *[false] clobber_abi, options
-    }, or additional template string
-
-builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
-    .label = previously here
-    .arg = duplicate argument
-
-builtin_macros_asm_pos_after = positional arguments cannot follow named arguments or explicit register arguments
-    .pos = positional argument
-    .named = named argument
-    .explicit = explicit register argument
-
-builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option
-
-builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
-
-builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs
-builtin_macros_asm_clobber_abi = clobber_abi
-builtin_macros_asm_clobber_outputs = generic outputs
-
-builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided
-    .label = this option was already provided
-    .suggestion = remove this option
+builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items
 
 builtin_macros_test_runner_invalid = `test_runner` argument must be a path
 builtin_macros_test_runner_nargs = `#![test_runner(..)]` accepts exactly 1 argument
+
+builtin_macros_unexpected_lit = expected path to a trait, found literal
+    .label = not a trait
+    .str_lit = try using `#[derive({$sym})]`
+    .other = for example, write `#[derive(Debug)]` for `Debug`
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index ea830a0..b619e80 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -233,10 +233,19 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
             ExprKind::Cast(local_expr, _) => {
                 self.manage_cond_expr(local_expr);
             }
+            ExprKind::If(local_expr, _, _) => {
+                self.manage_cond_expr(local_expr);
+            }
             ExprKind::Index(prefix, suffix) => {
                 self.manage_cond_expr(prefix);
                 self.manage_cond_expr(suffix);
             }
+            ExprKind::Let(_, local_expr, _) => {
+                self.manage_cond_expr(local_expr);
+            }
+            ExprKind::Match(local_expr, _) => {
+                self.manage_cond_expr(local_expr);
+            }
             ExprKind::MethodCall(call) => {
                 for arg in &mut call.args {
                     self.manage_cond_expr(arg);
@@ -295,17 +304,14 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
             | ExprKind::Continue(_)
             | ExprKind::Err
             | ExprKind::Field(_, _)
-            | ExprKind::FormatArgs(_)
             | ExprKind::ForLoop(_, _, _, _)
-            | ExprKind::If(_, _, _)
+            | ExprKind::FormatArgs(_)
             | ExprKind::IncludedBytes(..)
             | ExprKind::InlineAsm(_)
-            | ExprKind::OffsetOf(_, _)
-            | ExprKind::Let(_, _, _)
             | ExprKind::Lit(_)
             | ExprKind::Loop(_, _, _)
             | ExprKind::MacCall(_)
-            | ExprKind::Match(_, _)
+            | ExprKind::OffsetOf(_, _)
             | ExprKind::Path(_, _)
             | ExprKind::Ret(_)
             | ExprKind::Try(_)
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 9c6a0fa..fcfa0b8 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -473,7 +473,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
             | TerminatorKind::GeneratorDrop => {
                 bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
             }
-            TerminatorKind::Drop { place, target, unwind: _ } => {
+            TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
                 let drop_place = codegen_place(fx, *place);
                 crate::abi::codegen_drop(fx, source_info, drop_place);
 
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 5eaa988..70cb6df 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -361,7 +361,7 @@ pub(crate) fn monomorphize<T>(&self, value: T) -> T
         self.instance.subst_mir_and_normalize_erasing_regions(
             self.tcx,
             ty::ParamEnv::reveal_all(),
-            ty::EarlyBinder(value),
+            ty::EarlyBinder::new(value),
         )
     }
 
diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl
index 0a94a08..97bc8ef 100644
--- a/compiler/rustc_codegen_gcc/messages.ftl
+++ b/compiler/rustc_codegen_gcc/messages.ftl
@@ -1,68 +1,68 @@
-codegen_gcc_unwinding_inline_asm =
-    GCC backend does not support unwinding from inline asm
-
-codegen_gcc_lto_not_supported =
-    LTO is not supported. You may get a linker error.
+codegen_gcc_invalid_minimum_alignment =
+    invalid minimum global alignment: {$err}
 
 codegen_gcc_invalid_monomorphization_basic_integer =
     invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
 
-codegen_gcc_invalid_monomorphization_invalid_float_vector =
-    invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}`
-
-codegen_gcc_invalid_monomorphization_not_float =
-    invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type
-
-codegen_gcc_invalid_monomorphization_unrecognized =
-    invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
-
 codegen_gcc_invalid_monomorphization_expected_signed_unsigned =
     invalid monomorphization of `{$name}` intrinsic: expected element type `{$elem_ty}` of vector type `{$vec_ty}` to be a signed or unsigned integer type
 
-codegen_gcc_invalid_monomorphization_unsupported_element =
-    invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}`
-
-codegen_gcc_invalid_monomorphization_invalid_bitmask =
-    invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
-
-codegen_gcc_invalid_monomorphization_simd_shuffle =
-    invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
-
 codegen_gcc_invalid_monomorphization_expected_simd =
     invalid monomorphization of `{$name}` intrinsic: expected SIMD {$expected_ty} type, found non-SIMD `{$found_ty}`
 
+codegen_gcc_invalid_monomorphization_inserted_type =
+    invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
+
+codegen_gcc_invalid_monomorphization_invalid_bitmask =
+    invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+
+codegen_gcc_invalid_monomorphization_invalid_float_vector =
+    invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}`
+
 codegen_gcc_invalid_monomorphization_mask_type =
     invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
 
+codegen_gcc_invalid_monomorphization_mismatched_lengths =
+    invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+
+codegen_gcc_invalid_monomorphization_not_float =
+    invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type
+
+codegen_gcc_invalid_monomorphization_return_element =
+    invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
+
+codegen_gcc_invalid_monomorphization_return_integer_type =
+    invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
+
 codegen_gcc_invalid_monomorphization_return_length =
     invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
 
 codegen_gcc_invalid_monomorphization_return_length_input_type =
     invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
 
-codegen_gcc_invalid_monomorphization_return_element =
-    invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
-
 codegen_gcc_invalid_monomorphization_return_type =
     invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
 
-codegen_gcc_invalid_monomorphization_inserted_type =
-    invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
+codegen_gcc_invalid_monomorphization_simd_shuffle =
+    invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
 
-codegen_gcc_invalid_monomorphization_return_integer_type =
-    invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
-
-codegen_gcc_invalid_monomorphization_mismatched_lengths =
-    invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+codegen_gcc_invalid_monomorphization_unrecognized =
+    invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
 
 codegen_gcc_invalid_monomorphization_unsupported_cast =
     invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
 
+codegen_gcc_invalid_monomorphization_unsupported_element =
+    invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}`
+
 codegen_gcc_invalid_monomorphization_unsupported_operation =
     invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
 
-codegen_gcc_invalid_minimum_alignment =
-    invalid minimum global alignment: {$err}
+codegen_gcc_lto_not_supported =
+    LTO is not supported. You may get a linker error.
 
 codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together
     .help = add the missing features in a `target_feature` attribute
+
+codegen_gcc_unwinding_inline_asm =
+    GCC backend does not support unwinding from inline asm
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index d776347..55622fd 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -1,3 +1,73 @@
+codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
+
+codegen_llvm_dlltool_fail_import_library =
+    Dlltool could not create import library: {$stdout}
+    {$stderr}
+
+codegen_llvm_dynamic_linking_with_lto =
+    cannot prefer dynamic linking when performing LTO
+    .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
+
+codegen_llvm_error_calling_dlltool =
+    Error calling dlltool '{$dlltool_path}': {$error}
+
+codegen_llvm_error_creating_import_library =
+    Error creating import library for {$lib_name}: {$error}
+
+codegen_llvm_error_writing_def_file =
+    Error writing .DEF file: {$error}
+
+codegen_llvm_from_llvm_diag = {$message}
+
+codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
+codegen_llvm_invalid_minimum_alignment =
+    invalid minimum global alignment: {$err}
+
+codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
+codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
+
+codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err})
+
+codegen_llvm_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs
+
+codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
+
+codegen_llvm_missing_features =
+    add the missing features in a `target_feature` attribute
+
+codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found
+codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err}
+
+codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module
+codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
+
+codegen_llvm_parse_target_machine_config =
+    failed to parse target machine config to target machine: {$error}
+
+codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context
+codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err}
+
+codegen_llvm_prepare_thin_lto_module = failed to prepare thin LTO module
+codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO module: {$llvm_err}
+
+codegen_llvm_run_passes = failed to run LLVM passes
+codegen_llvm_run_passes_with_llvm_err = failed to run LLVM passes: {$llvm_err}
+
+codegen_llvm_sanitizer_memtag_requires_mte =
+    `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
+
+codegen_llvm_serialize_module = failed to serialize module {$name}
+codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name}: {$llvm_err}
+
+codegen_llvm_symbol_already_defined =
+    symbol `{$symbol_name}` is already defined
+
+codegen_llvm_target_feature_disable_or_enable =
+    the target features {$features} must all be either enabled or disabled together
+
+codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
+codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
+
 codegen_llvm_unknown_ctarget_feature =
     unknown feature specified for `-Ctarget-feature`: `{$feature}`
     .note = it is still passed through to the codegen backend
@@ -8,83 +78,13 @@
     unknown feature specified for `-Ctarget-feature`: `{$feature}`
     .note = features must begin with a `+` to enable or `-` to disable it
 
-codegen_llvm_error_creating_import_library =
-    Error creating import library for {$lib_name}: {$error}
-
-codegen_llvm_symbol_already_defined =
-    symbol `{$symbol_name}` is already defined
-
-codegen_llvm_invalid_minimum_alignment =
-    invalid minimum global alignment: {$err}
-
-codegen_llvm_sanitizer_memtag_requires_mte =
-    `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
-
-codegen_llvm_error_writing_def_file =
-    Error writing .DEF file: {$error}
-
-codegen_llvm_error_calling_dlltool =
-    Error calling dlltool '{$dlltool_path}': {$error}
-
-codegen_llvm_dlltool_fail_import_library =
-    Dlltool could not create import library: {$stdout}
-    {$stderr}
-
-codegen_llvm_target_feature_disable_or_enable =
-    the target features {$features} must all be either enabled or disabled together
-
-codegen_llvm_missing_features =
-    add the missing features in a `target_feature` attribute
-
-codegen_llvm_dynamic_linking_with_lto =
-    cannot prefer dynamic linking when performing LTO
-    .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
-
-codegen_llvm_parse_target_machine_config =
-    failed to parse target machine config to target machine: {$error}
-
-codegen_llvm_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs
-
-codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
-
-codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err})
-
-codegen_llvm_write_output = could not write output to {$path}
-codegen_llvm_write_output_with_llvm_err = could not write output to {$path}: {$llvm_err}
-
-codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
-codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
-
-codegen_llvm_run_passes = failed to run LLVM passes
-codegen_llvm_run_passes_with_llvm_err = failed to run LLVM passes: {$llvm_err}
-
-codegen_llvm_serialize_module = failed to serialize module {$name}
-codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name}: {$llvm_err}
+codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
 
 codegen_llvm_write_ir = failed to write LLVM IR to {$path}
 codegen_llvm_write_ir_with_llvm_err = failed to write LLVM IR to {$path}: {$llvm_err}
 
-codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context
-codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err}
-
-codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
-codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
+codegen_llvm_write_output = could not write output to {$path}
+codegen_llvm_write_output_with_llvm_err = could not write output to {$path}: {$llvm_err}
 
 codegen_llvm_write_thinlto_key = error while writing ThinLTO key data: {$err}
 codegen_llvm_write_thinlto_key_with_llvm_err = error while writing ThinLTO key data: {$err}: {$llvm_err}
-
-codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found
-codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err}
-
-codegen_llvm_prepare_thin_lto_module = failed to prepare thin LTO module
-codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO module: {$llvm_err}
-
-codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module
-codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
-
-codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
-codegen_llvm_from_llvm_diag = {$message}
-
-codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
-
-codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 651d644..6d00464 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -88,6 +88,9 @@ pub fn sanitize_attrs<'ll>(
 
         attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
     }
+    if enabled.contains(SanitizerSet::SAFESTACK) {
+        attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx));
+    }
     attrs
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index 3fff112..6cb9e16 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -93,7 +93,7 @@ fn make_mir_scope<'ll, 'tcx>(
             let callee = cx.tcx.subst_and_normalize_erasing_regions(
                 instance.substs,
                 ty::ParamEnv::reveal_all(),
-                ty::EarlyBinder(callee),
+                ty::EarlyBinder::new(callee),
             );
             let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
             cx.dbg_scope_fn(callee, callee_fn_abi, None)
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index de93a64..6ef3418 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -196,6 +196,7 @@ pub enum AttributeKind {
     AllocSize = 37,
     AllocatedPointer = 38,
     AllocAlign = 39,
+    SanitizeSafeStack = 40,
 }
 
 /// LLVMIntPredicate
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 375fdec..9aa2b2e 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -1,80 +1,258 @@
-codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
-
-codegen_ssa_version_script_write_failure = failed to write version script: {$error}
-
-codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
-
-codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
-
-codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
-
 codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
 
-codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
+codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
+
+codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
+
+codegen_ssa_archive_build_failure =
+    failed to build archive: {$error}
+
+codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
+
+codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
 
 codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
 
 codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}
 
+codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
+
+codegen_ssa_erroneous_constant = erroneous constant encountered
+
+codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
+
+codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_convert_name = failed to convert name '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_mmap_file = failed to mmap file '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_open_file = failed to open file '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_parse_archive = failed to parse archive '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_read_entry = failed to read entry '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$error}
+
+codegen_ssa_failed_to_write = failed to write {$path}: {$error}
+
 codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
 
 codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
 
-codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
+codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
+    .note = an unsuffixed integer value, e.g., `1`, is expected
 
 codegen_ssa_incompatible_linking_modifiers = link modifiers combination `+bundle,+whole-archive` is unstable when generating rlibs
 
-codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
+codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
 
-codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
+codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
+    .note = the attribute requires exactly one argument
 
-codegen_ssa_rlib_missing_format = could not find formats for rlibs
+codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
 
-codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
+codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
 
-codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
+codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
 
-codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
+codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
+
+codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
+
+codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type
+
+codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}`
+
+codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type
+
+codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}`
+
+codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+
+codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
+
+codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+
+codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant
+
+codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len})
+
+codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
+
+codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
+
+codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
+
+codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
+
+codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
+
+codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize`
+    .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
+
+codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
+
+codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
+
+codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
+
+codegen_ssa_link_exe_unexpected_error = `link.exe` returned an unexpected error
+
+codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker
+
+codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error}
+
+codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
+
+codegen_ssa_linker_not_found = linker `{$linker_path}` not found
+    .note = {$error}
+
+codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
 
 codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
 
-codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
+codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
+
+codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
+
+codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
+
+codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found
+
+codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
+
+codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
+    .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+
+codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
+
+codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
+
+codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
+
+codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
+    .note = {$output}
+
+codegen_ssa_read_file = failed to read file: {$message}
+
+codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer
+
+codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib: {$error}
+
+codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
+
+codegen_ssa_rlib_missing_format = could not find formats for rlibs
+
+codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
+
+codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
+
+codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected
+
+codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
 
 codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
 
-codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)
+codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
 
-codegen_ssa_thorin_read_input_failure = failed to read input file
+codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status}
+    .note = {$output}
 
-codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind
+codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
 
-codegen_ssa_thorin_parse_input_object_file = failed to parse input object file
-
-codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file
-
-codegen_ssa_thorin_parse_archive_member = failed to parse archive member
-
-codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object
+codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method
+    .label = cannot be applied to safe trait method
+    .label_def = not an `unsafe` function
 
 codegen_ssa_thorin_decompress_data = failed to decompress compressed section
 
-codegen_ssa_thorin_section_without_name = section without name at offset {$offset}
+codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit})
 
-codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset}
+codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data
+
+codegen_ssa_thorin_gimli_read = {$error}
+codegen_ssa_thorin_gimli_write = {$error}
+
+codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format}
+
+codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object
+
+codegen_ssa_thorin_io = {$error}
+codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id})
+
+codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found
+
+codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
+
+codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
+
+codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
+
+codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package
 
 codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset}
 
-codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
-
-codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id})
-
 codegen_ssa_thorin_no_compilation_units = input object has no compilation units
 
 codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit
 
-codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit
+codegen_ssa_thorin_not_output_object_created = no output object was created from inputs
 
-codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
+codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier)
+
+codegen_ssa_thorin_object_read = {$error}
+codegen_ssa_thorin_object_write = {$error}
+codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section
+
+codegen_ssa_thorin_parse_archive_member = failed to parse archive member
+
+codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section
+
+codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file
+
+codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind
+
+codegen_ssa_thorin_parse_input_object_file = failed to parse input object file
+
+codegen_ssa_thorin_parse_unit = failed to parse unit
 
 codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations
 
@@ -82,225 +260,47 @@
 
 codegen_ssa_thorin_parse_unit_header = failed to parse unit header
 
-codegen_ssa_thorin_parse_unit = failed to parse unit
+codegen_ssa_thorin_read_input_failure = failed to read input file
 
-codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format}
-
-codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section
-
-codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section
-
-codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section
-
-codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index
+codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset}
 
 codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index
 
 codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index
 
-codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data
+codegen_ssa_thorin_section_without_name = section without name at offset {$offset}
 
-codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
+codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section
 
-codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package
+codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit
 
-codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier)
+codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index
 
-codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit})
-
-codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found
-
-codegen_ssa_thorin_not_output_object_created = no output object was created from inputs
-
-codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
-
-codegen_ssa_thorin_io = {$error}
-codegen_ssa_thorin_object_read = {$error}
-codegen_ssa_thorin_object_write = {$error}
-codegen_ssa_thorin_gimli_read = {$error}
-codegen_ssa_thorin_gimli_write = {$error}
-
-codegen_ssa_link_exe_unexpected_error = `link.exe` returned an unexpected error
-
-codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer
-
-codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
-
-codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected
-
-codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
-
-codegen_ssa_linker_not_found = linker `{$linker_path}` not found
-    .note = {$error}
+codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
 
 codegen_ssa_unable_to_exe_linker = could not exec the linker `{$linker_path}`
     .note = {$error}
     .command_note = {$command_formatted}
 
-codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found
-
-codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
-
-codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
-
-codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
-    .note = {$output}
+codegen_ssa_unable_to_run = unable to run `{$util}`: {$error}
 
 codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error}
 
-codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status}
-    .note = {$output}
-
-codegen_ssa_unable_to_run = unable to run `{$util}`: {$error}
-
-codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
-
-codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
-
-codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker
-
-codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error}
-
-codegen_ssa_failed_to_write = failed to write {$path}: {$error}
-
 codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error}
 
-codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib: {$error}
-
-codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
-
-codegen_ssa_extract_bundled_libs_open_file = failed to open file '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_mmap_file = failed to mmap file '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_parse_archive = failed to parse archive '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_read_entry = failed to read entry '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_convert_name = failed to convert name '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$error}
-
-codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
-
-codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
-
-codegen_ssa_read_file = failed to read file: {$message}
-
-codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
-
-codegen_ssa_archive_build_failure =
-    failed to build archive: {$error}
-
 codegen_ssa_unknown_archive_kind =
     Don't know how to build archive of type: {$kind}
 
-codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
-
-codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
-    .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
-
-codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
-
-codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
-
-codegen_ssa_erroneous_constant = erroneous constant encountered
-
-codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
-
-codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
+codegen_ssa_unknown_atomic_operation = unknown atomic operation
 
 codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic
 
-codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
+codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
 
-codegen_ssa_unknown_atomic_operation = unknown atomic operation
+codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
 
-codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
+codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)
 
-codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
+codegen_ssa_version_script_write_failure = failed to write version script: {$error}
 
-codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}`
-
-codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}`
-
-codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type
-
-codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
-
-codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}`
-
-codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}`
-
-codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}`
-
-codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
-
-codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
-
-codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}`
-
-codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
-
-codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
-
-codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
-
-codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
-
-codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
-
-codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
-
-codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
-
-codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
-
-codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
-
-codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant
-
-codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len})
-
-codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
-
-codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
-
-codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}`
-
-codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
-
-codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
-
-codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
-
-codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
-
-codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
-
-codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
-
-codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
-
-codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}`
-
-codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
-
-codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}`
-
-codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}`
-
-codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
-
-codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
-
-codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type
-
-codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize`
-    .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
-
-codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
-    .note = the attribute requires exactly one argument
-
-codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
-    .note = an unsuffixed integer value, e.g., `1`, is expected
-
-codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method
-    .label = cannot be applied to safe trait method
-    .label_def = not an `unsafe` function
+codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8a00c42..5cc2342 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1188,6 +1188,9 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
     if sanitizer.contains(SanitizerSet::HWADDRESS) {
         link_sanitizer_runtime(sess, linker, "hwasan");
     }
+    if sanitizer.contains(SanitizerSet::SAFESTACK) {
+        link_sanitizer_runtime(sess, linker, "safestack");
+    }
 }
 
 fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 8bf8477..ad27b85 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -188,6 +188,11 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
     };
 
     let mut file = write::Object::new(binary_format, architecture, endianness);
+    if sess.target.is_like_osx {
+        if let Some(build_version) = macho_object_build_version_for_target(&sess.target) {
+            file.set_macho_build_version(build_version)
+        }
+    }
     let e_flags = match architecture {
         Architecture::Mips => {
             let arch = match sess.target.options.cpu.as_ref() {
@@ -258,6 +263,33 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
     Some(file)
 }
 
+/// Apple's LD, when linking for Mac Catalyst, requires object files to
+/// contain information about what they were built for (LC_BUILD_VERSION):
+/// the platform (macOS/watchOS etc), minimum OS version, and SDK version.
+/// This returns a `MachOBuildVersion` if necessary for the target.
+fn macho_object_build_version_for_target(
+    target: &Target,
+) -> Option<object::write::MachOBuildVersion> {
+    if !target.llvm_target.ends_with("-macabi") {
+        return None;
+    }
+    /// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
+    /// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
+    fn pack_version((major, minor): (u32, u32)) -> u32 {
+        (major << 16) | (minor << 8)
+    }
+
+    let platform = object::macho::PLATFORM_MACCATALYST;
+    let min_os = (14, 0);
+    let sdk = (16, 2);
+
+    let mut build_version = object::write::MachOBuildVersion::default();
+    build_version.platform = platform;
+    build_version.minos = pack_version(min_os);
+    build_version.sdk = pack_version(sdk);
+    Some(build_version)
+}
+
 pub enum MetadataPosition {
     First,
     Last,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index d516ac4..3f0b64b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1256,7 +1256,7 @@ fn codegen_terminator(
                 MergingSucc::False
             }
 
-            mir::TerminatorKind::Drop { place, target, unwind } => {
+            mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
                 self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
             }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 1204c99..51393a5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -111,7 +111,7 @@ pub fn monomorphize<T>(&self, value: T) -> T
         self.instance.subst_mir_and_normalize_erasing_regions(
             self.cx.tcx(),
             ty::ParamEnv::reveal_all(),
-            ty::EarlyBinder(value),
+            ty::EarlyBinder::new(value),
         )
     }
 }
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index f6751df..7d56cf0 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -1,10 +1,36 @@
-const_eval_unstable_in_stable =
-    const-stable function cannot use `#[feature({$gate})]`
-    .unstable_sugg = if it is not part of the public API, make this function unstably const
-    .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+const_eval_interior_mutability_borrow =
+    cannot borrow here, since the borrowed element may contain interior mutability
 
-const_eval_thread_local_access =
-    thread-local statics cannot be accessed at compile-time
+const_eval_interior_mutable_data_refer =
+    {$kind}s cannot refer to interior mutable data
+    .label = this borrow of an interior mutable value may end up in the final value
+    .help = to fix this, the value can be extracted to a separate `static` item and then referenced
+    .teach_note =
+        A constant containing interior mutable data behind a reference can allow you to modify that data.
+        This would make multiple uses of a constant to be able to see different values and allow circumventing
+        the `Send` and `Sync` requirements for shared mutable data, which is unsound.
+
+const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
+
+const_eval_mut_deref =
+    mutation through a reference is not allowed in {$kind}s
+
+const_eval_non_const_fmt_macro_call =
+    cannot call non-const formatting macro in {$kind}s
+
+const_eval_non_const_fn_call =
+    cannot call non-const fn `{$def_path_str}` in {$kind}s
+
+const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str`
+
+const_eval_raw_ptr_comparison =
+    pointers cannot be reliably compared during const eval
+    .note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+
+const_eval_raw_ptr_to_int =
+    pointers cannot be cast to integers during const eval
+    .note = at compile-time, pointers do not have an integer value
+    .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 const_eval_static_access =
     {$kind}s cannot refer to statics
@@ -12,29 +38,23 @@
     .teach_note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
     .teach_help = To fix this, the value can be extracted to a `const` and then used.
 
-const_eval_raw_ptr_to_int =
-    pointers cannot be cast to integers during const eval
-    .note = at compile-time, pointers do not have an integer value
-    .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
-
-const_eval_raw_ptr_comparison =
-    pointers cannot be reliably compared during const eval
-    .note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-
-const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str`
-
-const_eval_mut_deref =
-    mutation through a reference is not allowed in {$kind}s
+const_eval_thread_local_access =
+    thread-local statics cannot be accessed at compile-time
 
 const_eval_transient_mut_borrow = mutable references are not allowed in {$kind}s
 
 const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in {$kind}s
 
-const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
-
 const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {$kind}s
 
-const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
+const_eval_unallowed_heap_allocations =
+    allocations are not allowed in {$kind}s
+    .label = allocation not allowed in {$kind}s
+    .teach_note =
+        The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time.
+
+const_eval_unallowed_inline_asm =
+    inline assembly is not allowed in {$kind}s
 
 const_eval_unallowed_mutable_refs =
     mutable references are not allowed in the final value of {$kind}s
@@ -60,32 +80,12 @@
 
         If you really want global mutable state, try using static mut or a global UnsafeCell.
 
-const_eval_non_const_fmt_macro_call =
-    cannot call non-const formatting macro in {$kind}s
-
-const_eval_non_const_fn_call =
-    cannot call non-const fn `{$def_path_str}` in {$kind}s
-
 const_eval_unallowed_op_in_const_context =
     {$msg}
 
-const_eval_unallowed_heap_allocations =
-    allocations are not allowed in {$kind}s
-    .label = allocation not allowed in {$kind}s
-    .teach_note =
-        The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time.
+const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
 
-const_eval_unallowed_inline_asm =
-    inline assembly is not allowed in {$kind}s
-
-const_eval_interior_mutable_data_refer =
-    {$kind}s cannot refer to interior mutable data
-    .label = this borrow of an interior mutable value may end up in the final value
-    .help = to fix this, the value can be extracted to a separate `static` item and then referenced
-    .teach_note =
-        A constant containing interior mutable data behind a reference can allow you to modify that data.
-        This would make multiple uses of a constant to be able to see different values and allow circumventing
-        the `Send` and `Sync` requirements for shared mutable data, which is unsound.
-
-const_eval_interior_mutability_borrow =
-    cannot borrow here, since the borrowed element may contain interior mutability
+const_eval_unstable_in_stable =
+    const-stable function cannot use `#[feature({$gate})]`
+    .unstable_sugg = if it is not part of the public API, make this function unstably const
+    .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 7e94578..9195ae1 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -497,7 +497,7 @@ pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<TyC
             .try_subst_mir_and_normalize_erasing_regions(
                 *self.tcx,
                 self.param_env,
-                ty::EarlyBinder(value),
+                ty::EarlyBinder::new(value),
             )
             .map_err(|_| err_inval!(TooGeneric))
     }
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index df38792..586e8f0 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -114,7 +114,7 @@ pub(super) fn eval_terminator(
                 }
             }
 
-            Drop { place, target, unwind } => {
+            Drop { place, target, unwind, replace: _ } => {
                 let frame = self.frame();
                 let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
                 let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?;
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index 7ed70ba..40cbf14 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -1,4 +1,6 @@
 use crate::fx::{FxHashMap, FxHasher};
+#[cfg(parallel_compiler)]
+use crate::sync::is_dyn_thread_safe;
 use crate::sync::{CacheAligned, Lock, LockGuard};
 use std::borrow::Borrow;
 use std::collections::hash_map::RawEntryMut;
@@ -18,6 +20,11 @@
 
 /// An array of cache-line aligned inner locked structures with convenience methods.
 pub struct Sharded<T> {
+    /// This mask is used to ensure that accesses are inbounds of `shards`.
+    /// When dynamic thread safety is off, this field is set to 0 causing only
+    /// a single shard to be used for greater cache efficiency.
+    #[cfg(parallel_compiler)]
+    mask: usize,
     shards: [CacheAligned<Lock<T>>; SHARDS],
 }
 
@@ -31,31 +38,54 @@ fn default() -> Self {
 impl<T> Sharded<T> {
     #[inline]
     pub fn new(mut value: impl FnMut() -> T) -> Self {
-        Sharded { shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))) }
+        Sharded {
+            #[cfg(parallel_compiler)]
+            mask: if is_dyn_thread_safe() { SHARDS - 1 } else { 0 },
+            shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
+        }
+    }
+
+    #[inline(always)]
+    fn mask(&self) -> usize {
+        #[cfg(parallel_compiler)]
+        {
+            if SHARDS == 1 { 0 } else { self.mask }
+        }
+        #[cfg(not(parallel_compiler))]
+        {
+            0
+        }
+    }
+
+    #[inline(always)]
+    fn count(&self) -> usize {
+        // `self.mask` is always one below the used shard count
+        self.mask() + 1
     }
 
     /// The shard is selected by hashing `val` with `FxHasher`.
     #[inline]
     pub fn get_shard_by_value<K: Hash + ?Sized>(&self, val: &K) -> &Lock<T> {
-        if SHARDS == 1 { &self.shards[0].0 } else { self.get_shard_by_hash(make_hash(val)) }
+        self.get_shard_by_hash(if SHARDS == 1 { 0 } else { make_hash(val) })
     }
 
     #[inline]
     pub fn get_shard_by_hash(&self, hash: u64) -> &Lock<T> {
-        &self.shards[get_shard_index_by_hash(hash)].0
+        self.get_shard_by_index(get_shard_hash(hash))
     }
 
     #[inline]
     pub fn get_shard_by_index(&self, i: usize) -> &Lock<T> {
-        &self.shards[i].0
+        // SAFETY: The index get ANDed with the mask, ensuring it is always inbounds.
+        unsafe { &self.shards.get_unchecked(i & self.mask()).0 }
     }
 
     pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> {
-        (0..SHARDS).map(|i| self.shards[i].0.lock()).collect()
+        (0..self.count()).map(|i| self.get_shard_by_index(i).lock()).collect()
     }
 
     pub fn try_lock_shards(&self) -> Option<Vec<LockGuard<'_, T>>> {
-        (0..SHARDS).map(|i| self.shards[i].0.try_lock()).collect()
+        (0..self.count()).map(|i| self.get_shard_by_index(i).try_lock()).collect()
     }
 }
 
@@ -136,11 +166,9 @@ pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
 /// `hash` can be computed with any hasher, so long as that hasher is used
 /// consistently for each `Sharded` instance.
 #[inline]
-#[allow(clippy::modulo_one)]
-pub fn get_shard_index_by_hash(hash: u64) -> usize {
+fn get_shard_hash(hash: u64) -> usize {
     let hash_len = mem::size_of::<usize>();
     // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
     // hashbrown also uses the lowest bits, so we can't use those
-    let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize;
-    bits % SHARDS
+    (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize
 }
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index f19b1ff..22b4ec6 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -1,19 +1,19 @@
-driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
+driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
+driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
+driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
 
-driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
-
+driver_impl_ice_flags = compiler flags: {$flags}
+driver_impl_ice_version = rustc {$version} running on {$triple}
 driver_impl_rlink_empty_version_number = The input does not contain version number
 
 driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
 
-driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`
-
 driver_impl_rlink_no_a_file = rlink must be a file
 
-driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
+driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`
 
-driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
-driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
-driver_impl_ice_version = rustc {$version} running on {$triple}
-driver_impl_ice_flags = compiler flags: {$flags}
-driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
+driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
+
+driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
+
+driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs
index a713aff..eb92ccc 100644
--- a/compiler/rustc_driver_impl/src/args.rs
+++ b/compiler/rustc_driver_impl/src/args.rs
@@ -18,6 +18,9 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
     }
 }
 
+/// **Note:** This function doesn't interpret argument 0 in any special way.
+/// If this function is intended to be used with command line arguments,
+/// `argv[0]` must be removed prior to calling it manually.
 pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
     let mut args = Vec::new();
     for arg in at_args {
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 40aa69e..0b5d737 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -250,6 +250,16 @@ fn run_compiler(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
 ) -> interface::Result<()> {
+    // Throw away the first argument, the name of the binary.
+    // In case of at_args being empty, as might be the case by
+    // passing empty argument array to execve under some platforms,
+    // just use an empty slice.
+    //
+    // This situation was possible before due to arg_expand_all being
+    // called before removing the argument, enabling a crash by calling
+    // the compiler with @empty_file as argv[0] and no more arguments.
+    let at_args = at_args.get(1..).unwrap_or_default();
+
     let args = args::arg_expand_all(at_args);
 
     let Some(matches) = handle_options(&args) else { return Ok(()) };
@@ -1074,9 +1084,6 @@ fn print_flag_list<T>(
 /// So with all that in mind, the comments below have some more detail about the
 /// contortions done here to get things to work out correctly.
 pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
-    // Throw away the first argument, the name of the binary
-    let args = &args[1..];
-
     if args.is_empty() {
         // user did not write `-v` nor `-Z unstable-options`, so do not
         // include that extra information.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0133.md b/compiler/rustc_error_codes/src/error_codes/E0133.md
index 1adbcc3..8ca3f03 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0133.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0133.md
@@ -1,4 +1,4 @@
-Unsafe code was used outside of an unsafe function or block.
+Unsafe code was used outside of an unsafe block.
 
 Erroneous code example:
 
@@ -30,4 +30,21 @@
 
 See the [unsafe section][unsafe-section] of the Book for more details.
 
+#### Unsafe code in functions
+
+Unsafe code is currently accepted in unsafe functions, but that is being phased
+out in favor of requiring unsafe blocks here too.
+
+```
+unsafe fn f() { return; }
+
+unsafe fn g() {
+    f(); // Is accepted, but no longer recommended
+    unsafe { f(); } // Recommended way to write this
+}
+```
+
+Linting against this is controlled via the `unsafe_op_in_unsafe_fn` lint, which
+is `allow` by default but will be upgraded to `warn` in a future edition.
+
 [unsafe-section]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
diff --git a/compiler/rustc_errors/messages.ftl b/compiler/rustc_errors/messages.ftl
index dde1d6c..3370973 100644
--- a/compiler/rustc_errors/messages.ftl
+++ b/compiler/rustc_errors/messages.ftl
@@ -1,19 +1,19 @@
-errors_target_invalid_address_space =
-    invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
-
-errors_target_invalid_bits =
-    invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
-
-errors_target_missing_alignment =
-    missing alignment for `{$cause}` in "data-layout"
-
-errors_target_invalid_alignment =
-    invalid alignment for `{$cause}` in "data-layout": {$err}
-
 errors_target_inconsistent_architecture =
     inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
 
 errors_target_inconsistent_pointer_width =
     inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
 
+errors_target_invalid_address_space =
+    invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
+
+errors_target_invalid_alignment =
+    invalid alignment for `{$cause}` in "data-layout": {$err}
+
+errors_target_invalid_bits =
+    invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
+
 errors_target_invalid_bits_size = {$err}
+
+errors_target_missing_alignment =
+    missing alignment for `{$cause}` in "data-layout"
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 70d2718..6c7e682 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -1,56 +1,8 @@
-expand_explain_doc_comment_outer =
-    outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match
-
-expand_explain_doc_comment_inner =
-    inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
-
-expand_expr_repeat_no_syntax_vars =
-    attempted to repeat an expression containing no syntax variables matched as repeating at this depth
-
-expand_must_repeat_once =
-    this must repeat at least once
-
-expand_count_repetition_misplaced =
-    `count` can not be placed inside the inner-most repetition
-
-expand_meta_var_expr_unrecognized_var =
-    variable `{$key}` is not recognized in meta-variable expression
-
-expand_var_still_repeating =
-    variable '{$ident}' is still repeating at this depth
-
-expand_meta_var_dif_seq_matchers = {$msg}
-
-expand_macro_const_stability =
-    macros cannot have const stability attributes
-    .label = invalid const stability attribute
-    .label2 = const stability attribute affects this macro
-
-expand_macro_body_stability =
-    macros cannot have body stability attributes
-    .label = invalid body stability attribute
-    .label2 = body stability attribute affects this macro
-
-expand_resolve_relative_path =
-    cannot resolve relative path in non-file source `{$path}`
-
-expand_attr_no_arguments =
-    attribute must have either one or two arguments
-
-expand_not_a_meta_item =
-    not a meta item
-
-expand_only_one_word =
-    must only be one word
-
-expand_cannot_be_name_of_macro =
-    `{$trait_ident}` cannot be a name of {$macro_type} macro
-
 expand_arg_not_attributes =
     second argument must be `attributes`
 
-expand_attributes_wrong_form =
-    attribute must be of form: `attributes(foo, bar)`
+expand_attr_no_arguments =
+    attribute must have either one or two arguments
 
 expand_attribute_meta_item =
     attribute must be a meta item, not a literal
@@ -58,51 +10,44 @@
 expand_attribute_single_word =
     attribute must only be a single word
 
-expand_helper_attribute_name_invalid =
-    `{$name}` cannot be a name of derive helper attribute
+expand_attributes_wrong_form =
+    attribute must be of form: `attributes(foo, bar)`
+
+expand_cannot_be_name_of_macro =
+    `{$trait_ident}` cannot be a name of {$macro_type} macro
+
+expand_count_repetition_misplaced =
+    `count` can not be placed inside the inner-most repetition
+
+expand_duplicate_matcher_binding = duplicate matcher binding
+    .label = duplicate binding
+    .label2 = previous binding
 
 expand_expected_comma_in_list =
     expected token: `,`
 
-expand_only_one_argument =
-    {$name} takes 1 argument
+expand_explain_doc_comment_inner =
+    inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
 
-expand_takes_no_arguments =
-    {$name} takes no arguments
+expand_explain_doc_comment_outer =
+    outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match
+
+expand_expr_repeat_no_syntax_vars =
+    attempted to repeat an expression containing no syntax variables matched as repeating at this depth
 
 expand_feature_included_in_edition =
     the feature `{$feature}` is included in the Rust {$edition} edition
 
+expand_feature_not_allowed =
+    the feature `{$name}` is not in the list of allowed features
+
 expand_feature_removed =
     feature has been removed
     .label = feature has been removed
     .reason = {$reason}
 
-expand_feature_not_allowed =
-    the feature `{$name}` is not in the list of allowed features
-
-expand_recursion_limit_reached =
-    recursion limit reached while expanding `{$descr}`
-    .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
-
-expand_malformed_feature_attribute =
-    malformed `feature` attribute input
-    .expected = expected just one word
-
-expand_remove_expr_not_supported =
-    removing an expression is not supported in this position
-
-expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses
-expand_invalid_cfg_no_predicate = `cfg` predicate is not specified
-expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified
-expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal
-expand_invalid_cfg_expected_syntax = expected syntax is
-
-expand_wrong_fragment_kind =
-    non-{$kind} macro in {$kind} position: {$name}
-
-expand_unsupported_key_value =
-    key-value macro attributes are not supported
+expand_helper_attribute_name_invalid =
+    `{$name}` cannot be a name of derive helper attribute
 
 expand_incomplete_parse =
     macro expansion ignores token `{$token}` and any following
@@ -110,33 +55,88 @@
     .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context
     .suggestion_add_semi = you might be missing a semicolon here
 
-expand_remove_node_not_supported =
-    removing {$descr} is not supported in this position
+expand_invalid_cfg_expected_syntax = expected syntax is
+
+expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified
+expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses
+expand_invalid_cfg_no_predicate = `cfg` predicate is not specified
+expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal
+expand_macro_body_stability =
+    macros cannot have body stability attributes
+    .label = invalid body stability attribute
+    .label2 = body stability attribute affects this macro
+
+expand_macro_const_stability =
+    macros cannot have const stability attributes
+    .label = invalid const stability attribute
+    .label2 = const stability attribute affects this macro
+
+expand_malformed_feature_attribute =
+    malformed `feature` attribute input
+    .expected = expected just one word
+
+expand_meta_var_dif_seq_matchers = {$msg}
+
+expand_meta_var_expr_unrecognized_var =
+    variable `{$key}` is not recognized in meta-variable expression
 
 expand_module_circular =
     circular modules: {$modules}
 
-expand_module_in_block =
-    cannot declare a non-inline module inside a block unless it has a path attribute
-    .note = maybe `use` the module `{$name}` instead of redeclaring it
-
 expand_module_file_not_found =
     file not found for module `{$name}`
     .help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}"
 
+expand_module_in_block =
+    cannot declare a non-inline module inside a block unless it has a path attribute
+    .note = maybe `use` the module `{$name}` instead of redeclaring it
+
 expand_module_multiple_candidates =
     file for module `{$name}` found at both "{$default_path}" and "{$secondary_path}"
     .help = delete or rename one of them to remove the ambiguity
 
-expand_trace_macro = trace_macro
+expand_must_repeat_once =
+    this must repeat at least once
+
+expand_not_a_meta_item =
+    not a meta item
+
+expand_only_one_argument =
+    {$name} takes 1 argument
+
+expand_only_one_word =
+    must only be one word
+
+expand_proc_macro_derive_tokens =
+    proc-macro derive produced unparsable tokens
 
 expand_proc_macro_panicked =
     proc macro panicked
     .help = message: {$message}
 
-expand_proc_macro_derive_tokens =
-    proc-macro derive produced unparsable tokens
+expand_recursion_limit_reached =
+    recursion limit reached while expanding `{$descr}`
+    .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
 
-expand_duplicate_matcher_binding = duplicate matcher binding
-    .label = duplicate binding
-    .label2 = previous binding
+expand_remove_expr_not_supported =
+    removing an expression is not supported in this position
+
+expand_remove_node_not_supported =
+    removing {$descr} is not supported in this position
+
+expand_resolve_relative_path =
+    cannot resolve relative path in non-file source `{$path}`
+
+expand_takes_no_arguments =
+    {$name} takes no arguments
+
+expand_trace_macro = trace_macro
+
+expand_unsupported_key_value =
+    key-value macro attributes are not supported
+
+expand_var_still_repeating =
+    variable '{$ident}' is still repeating at this depth
+
+expand_wrong_fragment_kind =
+    non-{$kind} macro in {$kind} position: {$name}
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 5e5c984..02d1dfc 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -1,17 +1,103 @@
-hir_analysis_unrecognized_atomic_operation =
-    unrecognized atomic operation function: `{$op}`
-    .label = unrecognized atomic operation
+hir_analysis_ambiguous_lifetime_bound =
+    ambiguous lifetime bound, explicit lifetime bound required
 
-hir_analysis_wrong_number_of_generic_arguments_to_intrinsic =
-    intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected}
-    .label = expected {$expected} {$descr} {$expected ->
-        [one] parameter
-        *[other] parameters
-    }
+hir_analysis_assoc_type_binding_not_allowed =
+    associated type bindings are not allowed here
+    .label = associated type not allowed here
 
-hir_analysis_unrecognized_intrinsic_function =
-    unrecognized intrinsic function: `{$name}`
-    .label = unrecognized intrinsic
+hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters
+    .suggestion = use a fully qualified path with inferred lifetimes
+
+hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
+
+hir_analysis_async_trait_impl_should_be_async =
+    method `{$method_name}` should be async because the method from the trait is async
+    .trait_item_label = required because the trait method is async
+
+hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
+    .label = deref recursion limit reached
+    .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+
+hir_analysis_cannot_capture_late_bound_const_in_anon_const =
+    cannot capture late-bound const parameter in a constant
+    .label = parameter defined here
+
+hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
+    cannot capture late-bound type parameter in a constant
+    .label = parameter defined here
+
+hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+
+hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
+    .label = `for<...>` is here
+
+hir_analysis_const_bound_for_non_const_trait =
+    ~const can only be applied to `#[const_trait]` traits
+
+hir_analysis_const_impl_for_non_const_trait =
+    const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
+    .suggestion = mark `{$trait_name}` as const
+    .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+    .adding = adding a non-const method body in the future would be a breaking change
+
+hir_analysis_const_param_ty_impl_on_non_adt =
+    the trait `ConstParamTy` may not be implemented for this type
+    .label = type is not a structure or enumeration
+
+hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
+
+hir_analysis_copy_impl_on_non_adt =
+    the trait `Copy` cannot be implemented for this type
+    .label = type is not a structure or enumeration
+
+hir_analysis_copy_impl_on_type_with_dtor =
+    the trait `Copy` cannot be implemented for this type; the type has a destructor
+    .label = `Copy` not allowed on types with destructors
+
+hir_analysis_drop_impl_negative = negative `Drop` impls are not supported
+
+hir_analysis_drop_impl_on_wrong_item =
+    the `Drop` trait may only be implemented for local structs, enums, and unions
+    .label = must be a struct, enum, or union in the current crate
+
+hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
+
+hir_analysis_empty_specialization = specialization impl does not specialize any associated items
+    .note = impl is a specialization of this impl
+
+hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed
+    .label = overflowed on value after {$discr}
+    .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome
+
+hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+hir_analysis_field_already_declared =
+    field `{$field_name}` is already declared
+    .label = field already declared
+    .previous_decl_label = `{$field_name}` first declared here
+
+hir_analysis_function_not_found_in_trait = function not found in this trait
+
+hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
+    .note = required by this annotation
+
+hir_analysis_functions_names_duplicated = functions names are duplicated
+    .note = all `#[rustc_must_implement_one_of]` arguments must be unique
+
+hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
+    .label = cannot specialize default item `{$ident}`
+    .ok_label = parent `impl` is here
+    .note = to specialize, `{$ident}` in the parent `impl` must be marked `default`
+
+hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
+    .note = parent implementation is in crate `{$cname}`
+
+hir_analysis_invalid_union_field =
+    field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+    .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+
+hir_analysis_invalid_union_field_sugg =
+    wrap the field type in `ManuallyDrop<...>`
 
 hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
     lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
@@ -20,58 +106,39 @@
     .where_label = this `where` clause might not match the one in the trait
     .bounds_label = this bound might be missing in the impl
 
-hir_analysis_async_trait_impl_should_be_async =
-    method `{$method_name}` should be async because the method from the trait is async
-    .trait_item_label = required because the trait method is async
+hir_analysis_linkage_type =
+    invalid type for variable with `#[linkage]` attribute
 
-hir_analysis_drop_impl_on_wrong_item =
-    the `Drop` trait may only be implemented for local structs, enums, and unions
-    .label = must be a struct, enum, or union in the current crate
+hir_analysis_main_function_async = `main` function is not allowed to be `async`
+    .label = `main` function is not allowed to be `async`
 
-hir_analysis_field_already_declared =
-    field `{$field_name}` is already declared
-    .label = field already declared
-    .previous_decl_label = `{$field_name}` first declared here
+hir_analysis_main_function_generic_parameters = `main` function is not allowed to have generic parameters
+    .label = `main` cannot have generic parameters
 
-hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
-
-hir_analysis_const_param_ty_impl_on_non_adt =
-    the trait `ConstParamTy` may not be implemented for this type
-    .label = type is not a structure or enumeration
-
-hir_analysis_ambiguous_lifetime_bound =
-    ambiguous lifetime bound, explicit lifetime bound required
-
-hir_analysis_assoc_type_binding_not_allowed =
-    associated type bindings are not allowed here
-    .label = associated type not allowed here
-
-hir_analysis_parenthesized_fn_trait_expansion =
-    parenthesized trait syntax expands to `{$expanded_type}`
-
-hir_analysis_typeof_reserved_keyword_used =
-    `typeof` is a reserved keyword but unimplemented
-    .suggestion = consider replacing `typeof(...)` with an actual type
-    .label = reserved keyword
-
-hir_analysis_value_of_associated_struct_already_specified =
-    the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
-    .label = re-bound here
-    .previous_bound_label = `{$item_name}` bound here first
-
-hir_analysis_unconstrained_opaque_type = unconstrained opaque type
-    .note = `{$name}` must be used in combination with a concrete type within the same {$what}
+hir_analysis_main_function_return_type_generic = `main` function return type is not allowed to have generic parameters
 
 hir_analysis_manual_implementation =
     manual implementations of `{$trait_name}` are experimental
     .label = manual implementations of `{$trait_name}` are experimental
     .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
+hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
+    .label = missing one of `{$missing_items_msg}` in implementation
+    .note = required because of this annotation
 
-hir_analysis_trait_object_declared_with_no_traits =
-    at least one trait is required for an object type
-    .alias_span = this alias does not contain a trait
+hir_analysis_missing_tilde_const = missing `~const` qualifier for specialization
+
+hir_analysis_missing_trait_item = not all trait items implemented, missing: `{$missing_items_msg}`
+    .label = missing `{$missing_items_msg}` in implementation
+
+hir_analysis_missing_trait_item_label = `{$item}` from trait
+
+hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snippet}`
+
+hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}`
+    .note = default implementation of `{$missing_item_name}` is unstable
+    .some_note = use of unstable library feature '{$feature}': {$r}
+    .none_note = use of unstable library feature '{$feature}'
 
 hir_analysis_missing_type_params =
     the type {$parameterCount ->
@@ -95,98 +162,35 @@
     } to {$parameters}
     .note = because of the default `Self` reference, type parameters must be specified on object types
 
-hir_analysis_copy_impl_on_type_with_dtor =
-    the trait `Copy` cannot be implemented for this type; the type has a destructor
-    .label = `Copy` not allowed on types with destructors
-
 hir_analysis_multiple_relaxed_default_bounds =
     type parameter has more than one relaxed default bound, only one is supported
 
-hir_analysis_copy_impl_on_non_adt =
-    the trait `Copy` cannot be implemented for this type
-    .label = type is not a structure or enumeration
+hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
 
-hir_analysis_const_impl_for_non_const_trait =
-    const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
-    .suggestion = mark `{$trait_name}` as const
-    .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
-    .adding = adding a non-const method body in the future would be a breaking change
+hir_analysis_must_implement_not_function = not a function
 
-hir_analysis_const_bound_for_non_const_trait =
-    ~const can only be applied to `#[const_trait]` traits
+hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
 
-hir_analysis_self_in_impl_self =
-    `Self` is not valid in the self type of an impl block
-    .note = replace `Self` with a different type
+hir_analysis_must_implement_not_function_span_note = required by this annotation
 
-hir_analysis_linkage_type =
-    invalid type for variable with `#[linkage]` attribute
+hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
 
-hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
-    .label = deref recursion limit reached
-    .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
+    .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
 
-hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause
-    .label = `main` cannot have a `where` clause
-
-hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]`
-    .suggestion = remove this annotation
-
-hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
-
-hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]`
-    .label = `start` is not allowed to be `#[track_caller]`
-
-hir_analysis_start_not_target_feature = `start` is not allowed to have `#[target_feature]`
-    .label = `start` is not allowed to have `#[target_feature]`
-
-hir_analysis_start_not_async = `start` is not allowed to be `async`
-    .label = `start` is not allowed to be `async`
-
-hir_analysis_start_function_where = start function is not allowed to have a `where` clause
-    .label = start function cannot have a `where` clause
-
-hir_analysis_start_function_parameters = start function is not allowed to have type parameters
-    .label = start function cannot have type parameters
-
-hir_analysis_main_function_return_type_generic = `main` function return type is not allowed to have generic parameters
-
-hir_analysis_main_function_async = `main` function is not allowed to be `async`
-    .label = `main` function is not allowed to be `async`
-
-hir_analysis_main_function_generic_parameters = `main` function is not allowed to have generic parameters
-    .label = `main` cannot have generic parameters
-
-hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
-    .label = C-variadic function must have a compatible calling convention
-
-hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
-    cannot capture late-bound type parameter in a constant
-    .label = parameter defined here
-
-hir_analysis_cannot_capture_late_bound_const_in_anon_const =
-    cannot capture late-bound const parameter in a constant
-    .label = parameter defined here
-
-hir_analysis_variances_of = {$variances_of}
+hir_analysis_parenthesized_fn_trait_expansion =
+    parenthesized trait syntax expands to `{$expanded_type}`
 
 hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
     .suggestion = cast the value to `{$cast_ty}`
     .help = cast the value to `{$cast_ty}`
 
-hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
+    .label = not allowed in type signatures
 
-hir_analysis_invalid_union_field =
-    field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
-    .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
-
-hir_analysis_invalid_union_field_sugg =
-    wrap the field type in `ManuallyDrop<...>`
-
-hir_analysis_return_type_notation_on_non_rpitit =
-    return type notation used on function that is not `async` and does not return `impl Trait`
-    .note = function returns `{$ty}`, which is not compatible with associated type return bounds
-    .label = this function must be `async` or return `impl Trait`
+hir_analysis_return_type_notation_conflicting_bound =
+    ambiguous associated function `{$assoc_name}` for `{$ty_name}`
+    .note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
 
 hir_analysis_return_type_notation_equality_bound =
     return type notation is not allowed to use type equality
@@ -194,100 +198,96 @@
 hir_analysis_return_type_notation_missing_method =
     cannot find associated function `{$assoc_name}` for `{$ty_name}`
 
-hir_analysis_return_type_notation_conflicting_bound =
-    ambiguous associated function `{$assoc_name}` for `{$ty_name}`
-    .note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
+hir_analysis_return_type_notation_on_non_rpitit =
+    return type notation used on function that is not `async` and does not return `impl Trait`
+    .note = function returns `{$ty}`, which is not compatible with associated type return bounds
+    .label = this function must be `async` or return `impl Trait`
 
-hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
-    .label = not allowed in type signatures
-
-hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters
-    .suggestion = use a fully qualified path with inferred lifetimes
-
-hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
-
-hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed
-    .label = overflowed on value after {$discr}
-    .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome
-
-hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
-    .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
-
-hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
-
-hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
-
-hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
-    .note = required by this annotation
-
-hir_analysis_must_implement_not_function = not a function
-
-hir_analysis_must_implement_not_function_span_note = required by this annotation
-
-hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
-
-hir_analysis_function_not_found_in_trait = function not found in this trait
-
-hir_analysis_functions_names_duplicated = functions names are duplicated
-    .note = all `#[rustc_must_implement_one_of]` arguments must be unique
+hir_analysis_self_in_impl_self =
+    `Self` is not valid in the self type of an impl block
+    .note = replace `Self` with a different type
 
 hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code
     .help = add `#![feature(simd_ffi)]` to the crate attributes to enable
 
-hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
-    .label = cannot specialize default item `{$ident}`
-    .ok_label = parent `impl` is here
-    .note = to specialize, `{$ident}` in the parent `impl` must be marked `default`
+hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable
+    .help = add `#![feature(min_specialization)]` to the crate attributes to enable
 
-hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
-    .note = parent implementation is in crate `{$cname}`
+hir_analysis_start_function_parameters = start function is not allowed to have type parameters
+    .label = start function cannot have type parameters
 
-hir_analysis_missing_trait_item = not all trait items implemented, missing: `{$missing_items_msg}`
-    .label = missing `{$missing_items_msg}` in implementation
+hir_analysis_start_function_where = start function is not allowed to have a `where` clause
+    .label = start function cannot have a `where` clause
 
-hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snippet}`
+hir_analysis_start_not_async = `start` is not allowed to be `async`
+    .label = `start` is not allowed to be `async`
 
-hir_analysis_missing_trait_item_label = `{$item}` from trait
+hir_analysis_start_not_target_feature = `start` is not allowed to have `#[target_feature]`
+    .label = `start` is not allowed to have `#[target_feature]`
 
-hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
-    .label = missing one of `{$missing_items_msg}` in implementation
-    .note = required because of this annotation
+hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]`
+    .label = `start` is not allowed to be `#[track_caller]`
 
-hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}`
-    .note = default implementation of `{$missing_item_name}` is unstable
-    .some_note = use of unstable library feature '{$feature}': {$r}
-    .none_note = use of unstable library feature '{$feature}'
+hir_analysis_static_specialize = cannot specialize on `'static` lifetime
+
+hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
+
+hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
+
+hir_analysis_too_large_static = extern static is too large for the current architecture
+
+hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]`
+    .suggestion = remove this annotation
+
+hir_analysis_trait_object_declared_with_no_traits =
+    at least one trait is required for an object type
+    .alias_span = this alias does not contain a trait
 
 hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number}
     .label = needs exactly one variant, but has {$number}
     .many_label = too many variants in `{$path}`
     .multi_label = variant here
 
-hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
-    .label = needs at most one non-zero-sized field, but has {$field_count}
-    .labels = this field is non-zero-sized
-
 hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
     .label = needs at most one non-zero-sized field, but has {$field_count}
     .labels = this field is non-zero-sized
 
-hir_analysis_too_large_static = extern static is too large for the current architecture
+hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
+    .label = needs at most one non-zero-sized field, but has {$field_count}
+    .labels = this field is non-zero-sized
 
-hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable
-    .help = add `#![feature(min_specialization)]` to the crate attributes to enable
+hir_analysis_typeof_reserved_keyword_used =
+    `typeof` is a reserved keyword but unimplemented
+    .suggestion = consider replacing `typeof(...)` with an actual type
+    .label = reserved keyword
 
-hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
-    .label = `for<...>` is here
+hir_analysis_unconstrained_opaque_type = unconstrained opaque type
+    .note = `{$name}` must be used in combination with a concrete type within the same {$what}
 
-hir_analysis_empty_specialization = specialization impl does not specialize any associated items
-    .note = impl is a specialization of this impl
+hir_analysis_unrecognized_atomic_operation =
+    unrecognized atomic operation function: `{$op}`
+    .label = unrecognized atomic operation
 
-hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
+hir_analysis_unrecognized_intrinsic_function =
+    unrecognized intrinsic function: `{$name}`
+    .label = unrecognized intrinsic
 
-hir_analysis_static_specialize = cannot specialize on `'static` lifetime
+hir_analysis_value_of_associated_struct_already_specified =
+    the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
+    .label = re-bound here
+    .previous_bound_label = `{$item_name}` bound here first
 
-hir_analysis_missing_tilde_const = missing `~const` qualifier for specialization
+hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
+    .label = C-variadic function must have a compatible calling convention
 
-hir_analysis_drop_impl_negative = negative `Drop` impls are not supported
+hir_analysis_variances_of = {$variances_of}
 
-hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
+hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause
+    .label = `main` cannot have a `where` clause
+
+hir_analysis_wrong_number_of_generic_arguments_to_intrinsic =
+    intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected}
+    .label = expected {$expected} {$descr} {$expected ->
+        [one] parameter
+        *[other] parameters
+    }
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 5fb06cf..284ae0e 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1159,7 +1159,7 @@ fn add_predicates_for_ast_type_binding(
             // those that do.
             self.one_bound_for_assoc_type(
                 || traits::supertraits(tcx, trait_ref),
-                trait_ref.print_only_trait_path(),
+                trait_ref.skip_binder().print_only_trait_name(),
                 binding.item_name,
                 path_span,
                 match binding.kind {
@@ -1278,7 +1278,7 @@ fn add_predicates_for_ast_type_binding(
             // params (and trait ref's late bound params). This logic is very similar to
             // `Predicate::subst_supertrait`, and it's no coincidence why.
             let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
-            let subst_output = ty::EarlyBinder(shifted_output).subst(tcx, substs);
+            let subst_output = ty::EarlyBinder::new(shifted_output).subst(tcx, substs);
 
             let bound_vars = tcx.late_bound_vars(binding.hir_id);
             ty::Binder::bind_with_vars(subst_output, bound_vars)
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 8bf1e0e..283a9ed 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -794,14 +794,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                     })
                 });
                 debug!(%ty);
-                collected_tys.insert(def_id, ty::EarlyBinder(ty));
+                collected_tys.insert(def_id, ty::EarlyBinder::new(ty));
             }
             Err(err) => {
                 let reported = tcx.sess.delay_span_bug(
                     return_span,
                     format!("could not fully resolve: {ty} => {err:?}"),
                 );
-                collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported)));
+                collected_tys.insert(def_id, ty::EarlyBinder::new(tcx.ty_error(reported)));
             }
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index e0ba255..eeb69c3 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -128,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     // We don't need to normalize this param-env or anything, since we're only
     // substituting it with free params, so no additional param-env normalization
     // can occur on top of what has been done in the param_env query itself.
-    let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id))
+    let param_env = ty::EarlyBinder::new(tcx.param_env(adt_def_id))
         .subst(tcx, adt_to_impl_substs)
         .with_constness(tcx.constness(drop_impl_def_id));
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index b403ee9..4c513c4 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1398,7 +1398,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
             let mut param_count = CountParams::default();
             let has_region = pred.visit_with(&mut param_count).is_break();
-            let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs);
+            let substituted_pred = ty::EarlyBinder::new(pred).subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
             if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index ca0d550..75d99fe 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1124,7 +1124,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
             bug!("unexpected sort of node in fn_sig(): {:?}", x);
         }
     };
-    ty::EarlyBinder(output)
+    ty::EarlyBinder::new(output)
 }
 
 fn infer_return_ty_for_fn_sig<'tcx>(
@@ -1312,7 +1312,7 @@ fn impl_trait_ref(
                 check_impl_constness(tcx, impl_.constness, ast_trait_ref),
             )
         })
-        .map(ty::EarlyBinder)
+        .map(ty::EarlyBinder::new)
 }
 
 fn check_impl_constness(
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 948b903..03c8c59 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -86,7 +86,7 @@ pub(super) fn explicit_item_bounds(
         Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
             let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item();
             let opaque_ty = item.expect_opaque_ty();
-            return ty::EarlyBinder(opaque_type_bounds(
+            return ty::EarlyBinder::new(opaque_type_bounds(
                 tcx,
                 opaque_def_id.expect_local(),
                 opaque_ty.bounds,
@@ -124,7 +124,7 @@ pub(super) fn explicit_item_bounds(
         }
         _ => bug!("item_bounds called on {:?}", def_id),
     };
-    ty::EarlyBinder(bounds)
+    ty::EarlyBinder::new(bounds)
 }
 
 pub(super) fn item_bounds(
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 8e082d3..0b57d69 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -323,7 +323,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                 return map[&assoc_item.trait_item_def_id.unwrap()];
             }
             Err(_) => {
-                return ty::EarlyBinder(tcx.ty_error_with_message(
+                return ty::EarlyBinder::new(tcx.ty_error_with_message(
                     DUMMY_SP,
                     "Could not collect return position impl trait in trait tys",
                 ));
@@ -497,7 +497,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             bug!("unexpected sort of node in type_of(): {:?}", x);
         }
     };
-    ty::EarlyBinder(output)
+    ty::EarlyBinder::new(output)
 }
 
 fn infer_placeholder_type<'a>(
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 357deb0..d7f11d3 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -68,7 +68,7 @@ pub(crate) fn explicit_predicates_of(
                 }
             }
 
-            ty::EarlyBinder(required_predicates)
+            ty::EarlyBinder::new(required_predicates)
         })
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 0cd2fc1..ced994a 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -68,12 +68,13 @@ pub(super) fn infer_predicates(
             // Therefore mark `predicates_added` as true and which will ensure
             // we walk the crates again and re-calculate predicates for all
             // items.
-            let item_predicates_len: usize =
-                global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.0.len());
+            let item_predicates_len: usize = global_inferred_outlives
+                .get(&item_did.to_def_id())
+                .map_or(0, |p| p.as_ref().skip_binder().len());
             if item_required_predicates.len() > item_predicates_len {
                 predicates_added = true;
                 global_inferred_outlives
-                    .insert(item_did.to_def_id(), ty::EarlyBinder(item_required_predicates));
+                    .insert(item_did.to_def_id(), ty::EarlyBinder::new(item_required_predicates));
             }
         }
 
@@ -137,7 +138,9 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 // 'a` holds for `Foo`.
                 debug!("Adt");
                 if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) {
-                    for (unsubstituted_predicate, &span) in &unsubstituted_predicates.0 {
+                    for (unsubstituted_predicate, &span) in
+                        unsubstituted_predicates.as_ref().skip_binder()
+                    {
                         // `unsubstituted_predicate` is `U: 'b` in the
                         // example above. So apply the substitution to
                         // get `T: 'a` (or `predicate`):
@@ -251,7 +254,7 @@ fn check_explicit_predicates<'tcx>(
     );
     let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
 
-    for (outlives_predicate, &span) in &explicit_predicates.0 {
+    for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() {
         debug!("outlives_predicate = {:?}", &outlives_predicate);
 
         // Careful: If we are inferring the effects of a `dyn Trait<..>`
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index a8596c7..2106d6f 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -98,24 +98,27 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
     let predicates = global_inferred_outlives
         .iter()
         .map(|(&def_id, set)| {
-            let predicates = &*tcx.arena.alloc_from_iter(set.0.iter().filter_map(
-                |(ty::OutlivesPredicate(kind1, region2), &span)| {
-                    match kind1.unpack() {
-                        GenericArgKind::Type(ty1) => Some((
-                            ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)),
-                            span,
-                        )),
-                        GenericArgKind::Lifetime(region1) => Some((
-                            ty::Clause::RegionOutlives(ty::OutlivesPredicate(region1, *region2)),
-                            span,
-                        )),
-                        GenericArgKind::Const(_) => {
-                            // Generic consts don't impose any constraints.
-                            None
+            let predicates =
+                &*tcx.arena.alloc_from_iter(set.as_ref().skip_binder().iter().filter_map(
+                    |(ty::OutlivesPredicate(kind1, region2), &span)| {
+                        match kind1.unpack() {
+                            GenericArgKind::Type(ty1) => Some((
+                                ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)),
+                                span,
+                            )),
+                            GenericArgKind::Lifetime(region1) => Some((
+                                ty::Clause::RegionOutlives(ty::OutlivesPredicate(
+                                    region1, *region2,
+                                )),
+                                span,
+                            )),
+                            GenericArgKind::Const(_) => {
+                                // Generic consts don't impose any constraints.
+                                None
+                            }
                         }
-                    }
-                },
-            ));
+                    },
+                ));
             (def_id, predicates)
         })
         .collect();
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 4a669e3..aab432e 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -1,67 +1,20 @@
-hir_typeck_field_multiply_specified_in_initializer =
-    field `{$ident}` specified more than once
-    .label = used more than once
-    .previous_use_label = first use of `{$ident}`
-
-hir_typeck_functional_record_update_on_non_struct =
-    functional record update syntax requires a struct
-
-hir_typeck_return_stmt_outside_of_fn_body =
-    return statement outside of function body
-    .encl_body_label = the return is part of this body...
-    .encl_fn_label = ...not the enclosing function body
-
-hir_typeck_yield_expr_outside_of_generator =
-    yield expression outside of generator literal
-
-hir_typeck_struct_expr_non_exhaustive =
-    cannot create non-exhaustive {$what} using struct expression
-
-hir_typeck_method_call_on_unknown_type =
-    the type of this value must be known to call a method on a raw pointer on it
-
-hir_typeck_address_of_temporary_taken = cannot take address of a temporary
-    .label = temporary value
+hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
 
 hir_typeck_add_return_type_add = try adding a return type
 
 hir_typeck_add_return_type_missing_here = a return type might be missing here
 
-hir_typeck_expected_default_return_type = expected `()` because of default return type
+hir_typeck_address_of_temporary_taken = cannot take address of a temporary
+    .label = temporary value
 
-hir_typeck_expected_return_type = expected `{$expected}` because of return type
+hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where
+    .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new
 
-hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
-
-hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
-
-hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
-hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
-
-hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
-
-hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
-    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
-
-hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
-    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
-
-hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
-hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
-hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
-
-hir_typeck_convert_to_str = try converting the passed type into a `&str`
-
-hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters
-
-hir_typeck_fru_note = this expression may have been misinterpreted as a `..` range expression
-hir_typeck_fru_expr = this expression does not end in a comma...
-hir_typeck_fru_expr2 = ... so this is interpreted as a `..` range expression, instead of functional record update syntax
-hir_typeck_fru_suggestion =
-    to set the remaining fields{$expr ->
-        [NONE]{""}
-        *[other] {" "}from `{$expr}`
-    }, separate the last named field with a comma
+hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty ->
+    [NONE] {""}
+    [implement] , perhaps you need to implement it
+    *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it
+}
 
 hir_typeck_const_select_must_be_const = this argument must be a `const fn`
     .help = consult the documentation on `const_eval_select` for more information
@@ -70,23 +23,72 @@
     .note = expected a function item, found {$ty}
     .help = consult the documentation on `const_eval_select` for more information
 
-hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
-hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
+hir_typeck_convert_to_str = try converting the passed type into a `&str`
 
-hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where
-    .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new
+hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
 
-hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
+hir_typeck_expected_default_return_type = expected `()` because of default return type
 
-hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new`
+hir_typeck_expected_return_type = expected `{$expected}` because of return type
+
+hir_typeck_field_multiply_specified_in_initializer =
+    field `{$ident}` specified more than once
+    .label = used more than once
+    .previous_use_label = first use of `{$ident}`
+
+hir_typeck_fru_expr = this expression does not end in a comma...
+hir_typeck_fru_expr2 = ... so this is interpreted as a `..` range expression, instead of functional record update syntax
+hir_typeck_fru_note = this expression may have been misinterpreted as a `..` range expression
+hir_typeck_fru_suggestion =
+    to set the remaining fields{$expr ->
+        [NONE]{""}
+        *[other] {" "}from `{$expr}`
+    }, separate the last named field with a comma
+
+hir_typeck_functional_record_update_on_non_struct =
+    functional record update syntax requires a struct
+
+hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
+hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
+hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
+hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
+
+hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
+    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
+
+hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
+    .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
+
+hir_typeck_method_call_on_unknown_raw_pointee =
+    cannot call a method on a raw pointer with an unknown pointee type
+
+hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
 
 hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
     [true] {""}
     *[other] {" "}in the current scope
 }
 
-hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty ->
-    [NONE] {""}
-    [implement] , perhaps you need to implement it
-    *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it
-}
+hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
+
+hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters
+
+hir_typeck_return_stmt_outside_of_fn_body =
+    return statement outside of function body
+    .encl_body_label = the return is part of this body...
+    .encl_fn_label = ...not the enclosing function body
+
+hir_typeck_struct_expr_non_exhaustive =
+    cannot create non-exhaustive {$what} using struct expression
+
+hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
+
+hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new`
+
+hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
+
+hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
+hir_typeck_yield_expr_outside_of_generator =
+    yield expression outside of generator literal
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 102a313..4222205 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -49,8 +49,8 @@ pub struct StructExprNonExhaustive {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_typeck_method_call_on_unknown_type, code = "E0699")]
-pub struct MethodCallOnUnknownType {
+#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = "E0699")]
+pub struct MethodCallOnUnknownRawPointee {
     #[primary_span]
     pub span: Span,
 }
@@ -319,3 +319,11 @@ pub struct CandidateTraitNote {
     pub item_name: Ident,
     pub action_or_ty: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_ctor_is_private, code = "E0603")]
+pub struct CtorIsPrivate {
+    #[primary_span]
+    pub span: Span,
+    pub def: String,
+}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 2fdcd09..38ddb7e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1,4 +1,5 @@
 use crate::callee::{self, DeferredCallResolution};
+use crate::errors::CtorIsPrivate;
 use crate::method::{self, MethodCallee, SelfSource};
 use crate::rvalue_scopes;
 use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
@@ -1207,6 +1208,12 @@ pub fn instantiate_value_path(
             match ty.normalized.ty_adt_def() {
                 Some(adt_def) if adt_def.has_ctor() => {
                     let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();
+                    // Check the visibility of the ctor.
+                    let vis = tcx.visibility(ctor_def_id);
+                    if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) {
+                        tcx.sess
+                            .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) });
+                    }
                     let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
                     let user_substs = Self::user_substs_for_adt(ty);
                     user_self_ty = user_substs.user_self_ty;
@@ -1379,7 +1386,7 @@ fn inferred_kind(
         // the referenced item.
         let ty = tcx.type_of(def_id);
         assert!(!substs.has_escaping_bound_vars());
-        assert!(!ty.0.has_escaping_bound_vars());
+        assert!(!ty.skip_binder().has_escaping_bound_vars());
         let ty_substituted = self.normalize(span, ty.subst(tcx, substs));
 
         if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index ba21ede..9f3d35a 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,7 +3,7 @@
 use super::MethodError;
 use super::NoMatchData;
 
-use crate::errors::MethodCallOnUnknownType;
+use crate::errors::MethodCallOnUnknownRawPointee;
 use crate::FnCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -438,7 +438,7 @@ fn probe_op<OP, R>(
                 // so we do a future-compat lint here for the 2015 edition
                 // (see https://github.com/rust-lang/rust/issues/46906)
                 if self.tcx.sess.rust_2018() {
-                    self.tcx.sess.emit_err(MethodCallOnUnknownType { span });
+                    self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span });
                 } else {
                     self.tcx.struct_span_lint_hir(
                         lint::builtin::TYVAR_BEHIND_RAW_POINTER,
diff --git a/compiler/rustc_incremental/messages.ftl b/compiler/rustc_incremental/messages.ftl
index b760620..9fa4e0f 100644
--- a/compiler/rustc_incremental/messages.ftl
+++ b/compiler/rustc_incremental/messages.ftl
@@ -1,118 +1,118 @@
-incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
+incremental_assert_loaded =
+    we asserted that an existing incremental cache directory should be successfully loaded, but it was not
 
-incremental_missing_depnode = missing `DepNode` variant
-
-incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected
-
-incremental_no_path = no path from `{$source}` to `{$target}`
-
-incremental_ok = OK
-
-incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
-
-incremental_missing_query_depgraph =
-    found CGU-reuse attribute but `-Zquery-dep-graph` was not specified
-
-incremental_malformed_cgu_name =
-    found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case).
-
-incremental_no_module_named =
-    no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
-
-incremental_field_associated_value_expected = associated value expected for `{$name}`
-
-incremental_no_field = no field `{$name}`
+incremental_assert_not_loaded =
+    we asserted that the incremental cache should not be loaded, but it was loaded
 
 incremental_assertion_auto =
     `except` specified DepNodes that can not be affected for "{$name}": "{$e}"
 
-incremental_undefined_clean_dirty_assertions_item =
-    clean/dirty auto-assertions not yet defined for Node::Item.node={$kind}
-
-incremental_undefined_clean_dirty_assertions =
-    clean/dirty auto-assertions not yet defined for {$kind}
-
-incremental_repeated_depnode_label = dep-node label `{$label}` is repeated
-
-incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized
-
-incremental_not_dirty = `{$dep_node_str}` should be dirty but is not
-
-incremental_not_clean = `{$dep_node_str}` should be clean but is not
-
-incremental_not_loaded = `{$dep_node_str}` should have been loaded from disk but it was not
-
-incremental_unknown_item = unknown item `{$name}`
-
-incremental_no_cfg = no cfg attribute
+incremental_associated_value_expected = expected an associated value
 
 incremental_associated_value_expected_for = associated value expected for `{$ident}`
 
-incremental_associated_value_expected = expected an associated value
-
-incremental_unchecked_clean = found unchecked `#[rustc_clean]` attribute
-
-incremental_delete_old = unable to delete old {$name} at `{$path}`: {$err}
-
-incremental_create_new = failed to create {$name} at `{$path}`: {$err}
-
-incremental_write_new = failed to write {$name} to `{$path}`: {$err}
-
 incremental_canonicalize_path = incremental compilation: error canonicalizing path `{$path}`: {$err}
 
+incremental_cargo_help_1 =
+    incremental compilation can be disabled by setting the environment variable CARGO_INCREMENTAL=0 (see https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)
+incremental_cargo_help_2 =
+    the entire build directory can be changed to a different filesystem by setting the environment variable CARGO_TARGET_DIR to a different path (see https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)
+
+incremental_copy_workproduct_to_cache =
+    error copying object file `{$from}` to incremental directory as `{$to}`: {$err}
+
+incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err}
+
 incremental_create_incr_comp_dir =
     could not create incremental compilation {$tag} directory `{$path}`: {$err}
 
 incremental_create_lock =
     incremental compilation: could not create session directory lock file: {$lock_err}
-incremental_lock_unsupported =
-    the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation
-incremental_cargo_help_1 =
-    incremental compilation can be disabled by setting the environment variable CARGO_INCREMENTAL=0 (see https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)
-incremental_cargo_help_2 =
-    the entire build directory can be changed to a different filesystem by setting the environment variable CARGO_TARGET_DIR to a different path (see https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)
+incremental_create_new = failed to create {$name} at `{$path}`: {$err}
 
-incremental_delete_lock =
-    error deleting lock file for incremental compilation session directory `{$path}`: {$err}
-
-incremental_hard_link_failed =
-    hard linking files in the incremental compilation cache failed. copying files instead. consider moving the cache directory to a file system which supports hard linking in session dir `{$path}`
-
-incremental_delete_partial = failed to delete partly initialized session dir `{$path}`: {$err}
+incremental_decode_incr_cache = could not decode incremental cache: {$err}
 
 incremental_delete_full = error deleting incremental compilation session directory `{$path}`: {$err}
 
-incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err}
-
-incremental_invalid_gc_failed =
-    failed to garbage collect invalid incremental compilation session directory `{$path}`: {$err}
-
-incremental_finalized_gc_failed =
-    failed to garbage collect finalized incremental compilation session directory `{$path}`: {$err}
-
-incremental_session_gc_failed =
-    failed to garbage collect incremental compilation session directory `{$path}`: {$err}
-
-incremental_assert_not_loaded =
-    we asserted that the incremental cache should not be loaded, but it was loaded
-
-incremental_assert_loaded =
-    we asserted that an existing incremental cache directory should be successfully loaded, but it was not
-
 incremental_delete_incompatible =
     failed to delete invalidated or incompatible incremental compilation session directory contents `{$path}`: {$err}
 
+incremental_delete_lock =
+    error deleting lock file for incremental compilation session directory `{$path}`: {$err}
+
+incremental_delete_old = unable to delete old {$name} at `{$path}`: {$err}
+
+incremental_delete_partial = failed to delete partly initialized session dir `{$path}`: {$err}
+
+incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err}
+
+incremental_field_associated_value_expected = associated value expected for `{$name}`
+
+incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err}
+
+incremental_finalized_gc_failed =
+    failed to garbage collect finalized incremental compilation session directory `{$path}`: {$err}
+
+incremental_hard_link_failed =
+    hard linking files in the incremental compilation cache failed. copying files instead. consider moving the cache directory to a file system which supports hard linking in session dir `{$path}`
+
+incremental_invalid_gc_failed =
+    failed to garbage collect invalid incremental compilation session directory `{$path}`: {$err}
+
 incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err}
 
-incremental_decode_incr_cache = could not decode incremental cache: {$err}
+incremental_lock_unsupported =
+    the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation
+incremental_malformed_cgu_name =
+    found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case).
 
-incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err}
+incremental_missing_depnode = missing `DepNode` variant
+
+incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected
+
+incremental_missing_query_depgraph =
+    found CGU-reuse attribute but `-Zquery-dep-graph` was not specified
 
 incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err}
 
-incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err}
+incremental_no_cfg = no cfg attribute
 
-incremental_copy_workproduct_to_cache =
-    error copying object file `{$from}` to incremental directory as `{$to}`: {$err}
+incremental_no_field = no field `{$name}`
 
-incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err}
+incremental_no_module_named =
+    no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
+
+incremental_no_path = no path from `{$source}` to `{$target}`
+
+incremental_not_clean = `{$dep_node_str}` should be clean but is not
+
+incremental_not_dirty = `{$dep_node_str}` should be dirty but is not
+
+incremental_not_loaded = `{$dep_node_str}` should have been loaded from disk but it was not
+
+incremental_ok = OK
+
+incremental_repeated_depnode_label = dep-node label `{$label}` is repeated
+
+incremental_session_gc_failed =
+    failed to garbage collect incremental compilation session directory `{$path}`: {$err}
+
+incremental_unchecked_clean = found unchecked `#[rustc_clean]` attribute
+
+incremental_undefined_clean_dirty_assertions =
+    clean/dirty auto-assertions not yet defined for {$kind}
+
+incremental_undefined_clean_dirty_assertions_item =
+    clean/dirty auto-assertions not yet defined for Node::Item.node={$kind}
+
+incremental_unknown_item = unknown item `{$name}`
+
+incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
+
+incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
+
+incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized
+
+incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err}
+
+incremental_write_new = failed to write {$name} to `{$path}`: {$err}
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index fdc4ff0..f44c4a7 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -1,257 +1,8 @@
-infer_opaque_hidden_type =
-    opaque type's hidden type cannot be another opaque type from the same scope
-    .label = one of the two opaque types used here has to be outside its defining scope
-    .opaque_type = opaque type whose hidden type is being assigned
-    .hidden_type = opaque type being used as hidden type
-
-infer_type_annotations_needed = {$source_kind ->
-    [closure] type annotations needed for the closure `{$source_name}`
-    [normal] type annotations needed for `{$source_name}`
-    *[other] type annotations needed
-}
-    .label = type must be known at this point
-
-infer_label_bad = {$bad_kind ->
-    *[other] cannot infer type
-    [more_info] cannot infer {$prefix_kind ->
-        *[type] type for {$prefix}
-        [const_with_param] the value of const parameter
-        [const] the value of the constant
-    } `{$name}`{$has_parent ->
-        [true] {" "}declared on the {$parent_prefix} `{$parent_name}`
-        *[false] {""}
-    }
-}
-
-infer_source_kind_subdiag_let = {$kind ->
-    [with_pattern] consider giving `{$name}` an explicit type
-    [closure] consider giving this closure parameter an explicit type
-    *[other] consider giving this pattern a type
-}{$x_kind ->
-    [has_name] , where the {$prefix_kind ->
-        *[type] type for {$prefix}
-        [const_with_param] value of const parameter
-        [const] value of the constant
-    } `{$arg_name}` is specified
-    [underscore] , where the placeholders `_` are specified
-    *[empty] {""}
-}
-
-infer_source_kind_subdiag_generic_label =
-    cannot infer {$is_type ->
-    [true] type
-    *[false] the value
-    } of the {$is_type ->
-    [true] type
-    *[false] const
-    } {$parent_exists ->
-    [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}`
-    *[false] parameter {$param_name}
-    }
-
-infer_source_kind_subdiag_generic_suggestion =
-    consider specifying the generic {$arg_count ->
-    [one] argument
-    *[other] arguments
-    }
-
-infer_source_kind_fully_qualified =
-    try using a fully qualified path to specify the expected types
-
-infer_source_kind_closure_return =
-    try giving this closure an explicit return type
-
-# generator_kind  may need to be translated
-infer_need_type_info_in_generator =
-    type inside {$generator_kind ->
-    [async_block] `async` block
-    [async_closure] `async` closure
-    [async_fn] `async fn` body
-    *[generator] generator
-    } must be known in this context
-
-
-infer_subtype = ...so that the {$requirement ->
-    [method_compat] method type is compatible with trait
-    [type_compat] associated type is compatible with trait
-    [const_compat] const is compatible with trait
-    [expr_assignable] expression is assignable
-    [if_else_different] `if` and `else` have incompatible types
-    [no_else] `if` missing an `else` returns `()`
-    [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
-    [intrinsic_correct_type] intrinsic has the correct type
-    [method_correct_type] method receiver has the correct type
-    *[other] types are compatible
-}
-infer_subtype_2 = ...so that {$requirement ->
-    [method_compat] method type is compatible with trait
-    [type_compat] associated type is compatible with trait
-    [const_compat] const is compatible with trait
-    [expr_assignable] expression is assignable
-    [if_else_different] `if` and `else` have incompatible types
-    [no_else] `if` missing an `else` returns `()`
-    [fn_main_correct_type] `main` function has the correct type
-    [fn_start_correct_type] `#[start]` function has the correct type
-    [intrinsic_correct_type] intrinsic has the correct type
-    [method_correct_type] method receiver has the correct type
-    *[other] types are compatible
-}
-
-infer_reborrow = ...so that reference does not outlive borrowed content
-infer_reborrow_upvar = ...so that closure can access `{$name}`
-infer_relate_object_bound = ...so that it can be closed over into an object
-infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
-infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
-    [true] ...
-    *[false] {""}
-}
-infer_relate_param_bound_2 = ...that is required by this bound
-infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
-infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
-infer_ascribe_user_type_prove_predicate = ...so that the where clause holds
-
-infer_nothing = {""}
-
-infer_lifetime_mismatch = lifetime mismatch
-
-infer_declared_different = this parameter and the return type are declared with different lifetimes...
-infer_data_returned = ...but data{$label_var1_exists ->
-    [true] {" "}from `{$label_var1}`
-    *[false] {""}
-} is returned here
-
-infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
-infer_declared_multiple = this type is declared with multiple lifetimes...
-infer_types_declared_different = these two types are declared with different lifetimes...
-infer_data_flows = ...but data{$label_var1_exists ->
-    [true] {" "}from `{$label_var1}`
-    *[false] -> {""}
-} flows{$label_var2_exists ->
-    [true] {" "}into `{$label_var2}`
-    *[false] -> {""}
-} here
-
-infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
-    [true] {" "}and update trait if needed
-    *[false] {""}
-}
-infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
-
-infer_region_explanation = {$pref_kind ->
-    *[should_not_happen] [{$pref_kind}]
-    [ref_valid_for] ...the reference is valid for
-    [content_valid_for] ...but the borrowed content is only valid for
-    [type_obj_valid_for] object type is valid for
-    [source_pointer_valid_for] source pointer is only valid for
-    [type_satisfy] type must satisfy
-    [type_outlive] type must outlive
-    [lf_param_instantiated_with] lifetime parameter instantiated with
-    [lf_param_must_outlive] but lifetime parameter must outlive
-    [lf_instantiated_with] lifetime instantiated with
-    [lf_must_outlive] but lifetime must outlive
-    [pointer_valid_for] the pointer is valid for
-    [data_valid_for] but the referenced data is only valid for
-    [empty] {""}
-}{$pref_kind ->
-    [empty] {""}
-    *[other] {" "}
-}{$desc_kind ->
-    *[should_not_happen] [{$desc_kind}]
-    [restatic] the static lifetime
-    [revar] lifetime {$desc_arg}
-    [as_defined] the lifetime `{$desc_arg}` as defined here
-    [as_defined_anon] the anonymous lifetime as defined here
-    [defined_here] the anonymous lifetime defined here
-    [defined_here_reg] the lifetime `{$desc_arg}` as defined here
-}{$suff_kind ->
-    *[should_not_happen] [{$suff_kind}]
-    [empty]{""}
-    [continues] ...
-    [req_by_binding] {" "}as required by this binding
-}
-
-infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
-infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
-infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
-infer_lf_bound_not_satisfied = lifetime bound not satisfied
-infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long
-infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
-
-infer_mismatched_static_lifetime = incompatible lifetime on type
-infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
-infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
-infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
-infer_msl_introduces_static = introduces a `'static` lifetime requirement
-infer_msl_unmet_req = because this has an unmet lifetime requirement
-infer_msl_trait_note = this has an implicit `'static` lifetime requirement
-infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
-infer_suggest_add_let_for_letchains = consider adding `let`
-
-infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
-    .label = lifetime `{$named}` required
-
-infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
-    .label = lifetime `{$named}` required
-
-infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
-
-infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
-
-infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
-infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
-infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
-infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
-infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
-infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
-    [true] ...
-    *[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`
-
-infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
+infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
     [true] , for some specific lifetime `'{$lifetime}`
     *[false] {""}
 }
-infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
+infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
     [true] , for some specific lifetime `'{$lifetime}`
     *[false] {""}
 }
@@ -260,26 +11,62 @@
     *[false] {""}
 }
 
-infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
-    .label_satisfy = doesn't satisfy where-clause
-    .label_where = due to a where-clause on `{$def_id}`...
-    .label_dup = implementation of `{$trait_def_id}` is not general enough
+infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`
 
-infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
-    .found = found `{$found}`
-    .expected = expected `{$expected}`
-    .expected_found = expected signature `{$expected}`
-               {"   "}found signature `{$found}`
+infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
+infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
+infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_ascribe_user_type_prove_predicate = ...so that the where clause holds
 
-infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
-infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
-infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+infer_await_both_futures = consider `await`ing on both `Future`s
+infer_await_future = consider `await`ing on the `Future`
+infer_await_note = calling an async function returns a future
 
-infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
-infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
-infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
-infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
-
+infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long
 infer_but_calling_introduces = {$has_param_name ->
     [true] `{$param_name}`
     *[false] `fn` parameter
@@ -314,6 +101,77 @@
     .used_here = ...is used here...
     .introduced_by_bound = `'static` lifetime requirement introduced by this bound
 
+infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
+infer_consider_specifying_length = consider specifying the actual array length
+infer_data_flows = ...but data{$label_var1_exists ->
+    [true] {" "}from `{$label_var1}`
+    *[false] -> {""}
+} flows{$label_var2_exists ->
+    [true] {" "}into `{$label_var2}`
+    *[false] -> {""}
+} here
+
+infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
+infer_data_returned = ...but data{$label_var1_exists ->
+    [true] {" "}from `{$label_var1}`
+    *[false] {""}
+} is returned here
+
+infer_declared_different = this parameter and the return type are declared with different lifetimes...
+infer_declared_multiple = this type is declared with multiple lifetimes...
+infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
+infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
+infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
+infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
+
+infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
+
+infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
+
+infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
+    .label = lifetime `{$named}` required
+
+infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
+    .label = lifetime `{$named}` required
+
+infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
+
+infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same
+infer_fps_cast = consider casting to a fn pointer
+infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
+
+infer_fps_items_are_distinct = fn items are distinct from fn pointers
+infer_fps_remove_ref = consider removing the reference
+infer_fps_use_ref = consider using a reference
+infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
+infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
+infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
+infer_label_bad = {$bad_kind ->
+    *[other] cannot infer type
+    [more_info] cannot infer {$prefix_kind ->
+        *[type] type for {$prefix}
+        [const_with_param] the value of const parameter
+        [const] the value of the constant
+    } `{$name}`{$has_parent ->
+        [true] {" "}declared on the {$parent_prefix} `{$parent_name}`
+        *[false] {""}
+    }
+}
+
+infer_lf_bound_not_satisfied = lifetime bound not satisfied
+infer_lifetime_mismatch = lifetime mismatch
+
+infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
+    [true] {" "}and update trait if needed
+    *[false] {""}
+}
+infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
+
+infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
+infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
+infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
+infer_mismatched_static_lifetime = incompatible lifetime on type
 infer_more_targeted = {$has_param_name ->
     [true] `{$param_name}`
     *[false] `fn` parameter
@@ -322,72 +180,215 @@
     *[false] an anonymous lifetime `'_`
 } but calling `{$ident}` introduces an implicit `'static` lifetime requirement
 
-infer_ril_introduced_here = `'static` requirement introduced here
-infer_ril_introduced_by = requirement introduced by this return type
-infer_ril_because_of = because of this returned expression
-infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
+infer_msl_introduces_static = introduces a `'static` lifetime requirement
+infer_msl_trait_note = this has an implicit `'static` lifetime requirement
+infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
+infer_msl_unmet_req = because this has an unmet lifetime requirement
+infer_need_type_info_in_generator =
+    type inside {$generator_kind ->
+    [async_block] `async` block
+    [async_closure] `async` closure
+    [async_fn] `async fn` body
+    *[generator] generator
+    } must be known in this context
 
-infer_where_remove = remove the `where` clause
-infer_where_copy_predicates = copy the `where` clause predicates from the trait
 
-infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions
-infer_srs_remove = consider removing this semicolon
-infer_srs_add = consider returning the local binding `{$ident}`
-infer_srs_add_one = consider returning one of these bindings
+infer_nothing = {""}
 
-infer_await_both_futures = consider `await`ing on both `Future`s
-infer_await_future = consider `await`ing on the `Future`
-infer_await_note = calling an async function returns a future
+infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
+infer_oc_closure_selfref = closure/generator type that references itself
+infer_oc_const_compat = const not compatible with trait
+infer_oc_fn_main_correct_type = `main` function has wrong type
+infer_oc_fn_start_correct_type = `#[start]` function has wrong type
+infer_oc_generic = mismatched types
 
-infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
-infer_prlf_defined_without_sub = the lifetime defined here...
-infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
-infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here
-infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
-
+infer_oc_if_else_different = `if` and `else` have incompatible types
+infer_oc_intrinsic_correct_type = intrinsic has wrong type
+infer_oc_match_compat = `match` arms have incompatible types
+infer_oc_method_compat = method not compatible with trait
+infer_oc_method_correct_type = mismatched `self` parameter type
+infer_oc_no_diverge = `else` clause of `let...else` does not diverge
+infer_oc_no_else = `if` may be missing an `else` clause
+infer_oc_try_compat = `?` operator has incompatible types
+infer_oc_type_compat = type not compatible with trait
 infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
     .label = opaque type defined here
 
-infer_fps_use_ref = consider using a reference
-infer_fps_remove_ref = consider removing the reference
-infer_fps_cast = consider casting to a fn pointer
-infer_fps_items_are_distinct = fn items are distinct from fn pointers
-infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
+infer_opaque_hidden_type =
+    opaque type's hidden type cannot be another opaque type from the same scope
+    .label = one of the two opaque types used here has to be outside its defining scope
+    .opaque_type = opaque type whose hidden type is being assigned
+    .hidden_type = opaque type being used as hidden type
 
-infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same
-infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
+infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
+infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
+infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
+infer_prlf_defined_without_sub = the lifetime defined here...
+infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
+infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here
+infer_reborrow = ...so that reference does not outlive borrowed content
+infer_reborrow_upvar = ...so that closure can access `{$name}`
+infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
+
+infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
+infer_region_explanation = {$pref_kind ->
+    *[should_not_happen] [{$pref_kind}]
+    [ref_valid_for] ...the reference is valid for
+    [content_valid_for] ...but the borrowed content is only valid for
+    [type_obj_valid_for] object type is valid for
+    [source_pointer_valid_for] source pointer is only valid for
+    [type_satisfy] type must satisfy
+    [type_outlive] type must outlive
+    [lf_param_instantiated_with] lifetime parameter instantiated with
+    [lf_param_must_outlive] but lifetime parameter must outlive
+    [lf_instantiated_with] lifetime instantiated with
+    [lf_must_outlive] but lifetime must outlive
+    [pointer_valid_for] the pointer is valid for
+    [data_valid_for] but the referenced data is only valid for
+    [empty] {""}
+}{$pref_kind ->
+    [empty] {""}
+    *[other] {" "}
+}{$desc_kind ->
+    *[should_not_happen] [{$desc_kind}]
+    [restatic] the static lifetime
+    [revar] lifetime {$desc_arg}
+    [as_defined] the lifetime `{$desc_arg}` as defined here
+    [as_defined_anon] the anonymous lifetime as defined here
+    [defined_here] the anonymous lifetime defined here
+    [defined_here_reg] the lifetime `{$desc_arg}` as defined here
+}{$suff_kind ->
+    *[should_not_happen] [{$suff_kind}]
+    [empty]{""}
+    [continues] ...
+    [req_by_binding] {" "}as required by this binding
+}
+
+infer_relate_object_bound = ...so that it can be closed over into an object
+infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
+    [true] ...
+    *[false] {""}
+}
+infer_relate_param_bound_2 = ...that is required by this bound
+infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
+infer_ril_because_of = because of this returned expression
+infer_ril_introduced_by = requirement introduced by this return type
+infer_ril_introduced_here = `'static` requirement introduced here
+infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
 
 infer_sarwa_option = you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`
 infer_sarwa_result = you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()`
 
-infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}`
-
-infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object
 infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions
 
-infer_stp_wrap_one = try wrapping the pattern in `{$variant}`
+infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object
+infer_source_kind_closure_return =
+    try giving this closure an explicit return type
+
+# generator_kind  may need to be translated
+infer_source_kind_fully_qualified =
+    try using a fully qualified path to specify the expected types
+
+infer_source_kind_subdiag_generic_label =
+    cannot infer {$is_type ->
+    [true] type
+    *[false] the value
+    } of the {$is_type ->
+    [true] type
+    *[false] const
+    } {$parent_exists ->
+    [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}`
+    *[false] parameter {$param_name}
+    }
+
+infer_source_kind_subdiag_generic_suggestion =
+    consider specifying the generic {$arg_count ->
+    [one] argument
+    *[other] arguments
+    }
+
+infer_source_kind_subdiag_let = {$kind ->
+    [with_pattern] consider giving `{$name}` an explicit type
+    [closure] consider giving this closure parameter an explicit type
+    *[other] consider giving this pattern a type
+}{$x_kind ->
+    [has_name] , where the {$prefix_kind ->
+        *[type] type for {$prefix}
+        [const_with_param] value of const parameter
+        [const] value of the constant
+    } `{$arg_name}` is specified
+    [underscore] , where the placeholders `_` are specified
+    *[empty] {""}
+}
+
+infer_srs_add = consider returning the local binding `{$ident}`
+infer_srs_add_one = consider returning one of these bindings
+
+infer_srs_remove = consider removing this semicolon
+infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions
 infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}`
 
+infer_stp_wrap_one = try wrapping the pattern in `{$variant}`
+infer_subtype = ...so that the {$requirement ->
+    [method_compat] method type is compatible with trait
+    [type_compat] associated type is compatible with trait
+    [const_compat] const is compatible with trait
+    [expr_assignable] expression is assignable
+    [if_else_different] `if` and `else` have incompatible types
+    [no_else] `if` missing an `else` returns `()`
+    [fn_main_correct_type] `main` function has the correct type
+    [fn_start_correct_type] `#[start]` function has the correct type
+    [intrinsic_correct_type] intrinsic has the correct type
+    [method_correct_type] method receiver has the correct type
+    *[other] types are compatible
+}
+infer_subtype_2 = ...so that {$requirement ->
+    [method_compat] method type is compatible with trait
+    [type_compat] associated type is compatible with trait
+    [const_compat] const is compatible with trait
+    [expr_assignable] expression is assignable
+    [if_else_different] `if` and `else` have incompatible types
+    [no_else] `if` missing an `else` returns `()`
+    [fn_main_correct_type] `main` function has the correct type
+    [fn_start_correct_type] `#[start]` function has the correct type
+    [intrinsic_correct_type] intrinsic has the correct type
+    [method_correct_type] method receiver has the correct type
+    *[other] types are compatible
+}
+
+infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}`
+
+infer_suggest_add_let_for_letchains = consider adding `let`
+
+infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
+infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+
+infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
+    .found = found `{$found}`
+    .expected = expected `{$expected}`
+    .expected_found = expected signature `{$expected}`
+               {"   "}found signature `{$found}`
+
+infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
+    .label_satisfy = doesn't satisfy where-clause
+    .label_where = due to a where-clause on `{$def_id}`...
+    .label_dup = implementation of `{$trait_def_id}` is not general enough
+
+infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}`
+
 infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element
 
-infer_oc_method_compat = method not compatible with trait
-infer_oc_type_compat = type not compatible with trait
-infer_oc_const_compat = const not compatible with trait
-infer_oc_try_compat = `?` operator has incompatible types
-infer_oc_match_compat = `match` arms have incompatible types
-infer_oc_if_else_different = `if` and `else` have incompatible types
-infer_oc_no_else = `if` may be missing an `else` clause
-infer_oc_no_diverge = `else` clause of `let...else` does not diverge
-infer_oc_fn_main_correct_type = `main` function has wrong type
-infer_oc_fn_start_correct_type = `#[start]` function has wrong type
-infer_oc_intrinsic_correct_type = intrinsic has wrong type
-infer_oc_method_correct_type = mismatched `self` parameter type
-infer_oc_closure_selfref = closure/generator type that references itself
-infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
-infer_oc_generic = mismatched types
+infer_type_annotations_needed = {$source_kind ->
+    [closure] type annotations needed for the closure `{$source_name}`
+    [normal] type annotations needed for `{$source_name}`
+    *[other] type annotations needed
+}
+    .label = type must be known at this point
 
-infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
-infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
-infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
-infer_consider_specifying_length = consider specifying the actual array length
-infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}`
+infer_types_declared_different = these two types are declared with different lifetimes...
+infer_where_copy_predicates = copy the `where` clause predicates from the trait
+
+infer_where_remove = remove the `where` clause
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index de9afbb..88256c8 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -15,7 +15,7 @@
 use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
-use crate::traits::query::{Fallible, NoSolution};
+use crate::traits::query::NoSolution;
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
 use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt};
 use rustc_data_structures::captures::Captures;
@@ -57,7 +57,7 @@ pub fn make_canonicalized_query_response<T>(
         inference_vars: CanonicalVarValues<'tcx>,
         answer: T,
         fulfill_cx: &mut dyn TraitEngine<'tcx>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
+    ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
     where
         T: Debug + TypeFoldable<TyCtxt<'tcx>>,
         Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index c2bf0f3..59ae2ce 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -293,7 +293,7 @@ pub fn declared_bounds_from_definition(
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
         let bounds = tcx.item_bounds(alias_ty.def_id);
-        trace!("{:#?}", bounds.0);
+        trace!("{:#?}", bounds.skip_binder());
         bounds
             .subst_iter(tcx, alias_ty.substs)
             .filter_map(|p| p.to_opt_type_outlives())
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index 3799489..be1a75f 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -1,9 +1,28 @@
+interface_cant_emit_mir =
+    could not emit MIR: {$error}
+
+interface_emoji_identifier =
+    identifiers cannot contain emoji: `{$ident}`
+
+interface_error_writing_dependencies =
+    error writing dependencies to `{$path}`: {$error}
+
+interface_failed_writing_file =
+    failed to write file {$path}: {$error}"
+
 interface_ferris_identifier =
     Ferris cannot be used as an identifier
     .suggestion = try using their name instead
 
-interface_emoji_identifier =
-    identifiers cannot contain emoji: `{$ident}`
+interface_generated_file_conflicts_with_directory =
+    the generated executable for the input file "{$input_path}" conflicts with the existing directory "{$dir_path}"
+
+interface_ignoring_extra_filename = ignoring -C extra-filename flag due to -o flag
+
+interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
+
+interface_input_file_would_be_overwritten =
+    the input file "{$path}" would be overwritten by the generated executable
 
 interface_mixed_bin_crate =
     cannot mix `bin` crate type with others
@@ -11,23 +30,14 @@
 interface_mixed_proc_macro_crate =
     cannot mix `proc-macro` crate type with others
 
-interface_error_writing_dependencies =
-    error writing dependencies to `{$path}`: {$error}
-
-interface_input_file_would_be_overwritten =
-    the input file "{$path}" would be overwritten by the generated executable
-
-interface_generated_file_conflicts_with_directory =
-    the generated executable for the input file "{$input_path}" conflicts with the existing directory "{$dir_path}"
-
-interface_temps_dir_error =
-    failed to find or create the directory specified by `--temps-dir`
+interface_multiple_output_types_adaption =
+    due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
 
 interface_out_dir_error =
     failed to find or create the directory specified by `--out-dir`
 
-interface_cant_emit_mir =
-    could not emit MIR: {$error}
+interface_proc_macro_crate_panic_abort =
+    building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
 
 interface_rustc_error_fatal =
     fatal error triggered by #[rustc_error]
@@ -35,18 +45,8 @@
 interface_rustc_error_unexpected_annotation =
     unexpected annotation used with `#[rustc_error(...)]`!
 
-interface_failed_writing_file =
-    failed to write file {$path}: {$error}"
-
-interface_proc_macro_crate_panic_abort =
-    building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+interface_temps_dir_error =
+    failed to find or create the directory specified by `--temps-dir`
 
 interface_unsupported_crate_type_for_target =
     dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
-
-interface_multiple_output_types_adaption =
-    due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
-
-interface_ignoring_extra_filename = ignoring -C extra-filename flag due to -o flag
-
-interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index e1658d3..d34a3af 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -5,6 +5,202 @@
     .use_explicit_into_iter_suggestion =
         or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
 
+lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering
+    .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
+
+lint_atomic_ordering_invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write
+    .label = invalid failure ordering
+    .help = consider using `Acquire` or `Relaxed` failure ordering instead
+
+lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering
+    .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
+    .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+lint_bad_attribute_argument = bad attribute argument
+
+lint_bad_opt_access = {$msg}
+
+lint_builtin_allow_internal_unsafe =
+    `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site
+
+lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition
+    .suggestion = try naming the parameter or explicitly ignoring it
+
+lint_builtin_asm_labels = avoid using named labels in inline assembly
+
+lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty}
+
+lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature
+    .previous_decl_label = `{$orig}` previously declared here
+    .mismatch_label = this signature doesn't match the previous declaration
+
+lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature
+    .previous_decl_label = `{$orig}` previously declared here
+    .mismatch_label = this signature doesn't match the previous declaration
+lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
+    .suggestion = try a static value
+
+lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
+lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
+lint_builtin_deprecated_attr_default_suggestion = remove this attribute
+
+lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
+    .msg_suggestion = {$msg}
+    .default_suggestion = remove this attribute
+lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used.
+lint_builtin_deref_nullptr = dereferencing a null pointer
+    .label = this code causes undefined behavior when executed
+
+lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
+    .suggestion = use `..=` for an inclusive range
+
+lint_builtin_explicit_outlives = outlives requirements can be inferred
+    .suggestion = remove {$count ->
+        [one] this bound
+        *[other] these bounds
+    }
+
+lint_builtin_export_name_fn = declaration of a function with `export_name`
+lint_builtin_export_name_method = declaration of a method with `export_name`
+
+lint_builtin_export_name_static = declaration of a static with `export_name`
+lint_builtin_impl_unsafe_method = implementation of an `unsafe` method
+
+lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes
+    .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
+    .help = consider using `min_{$name}` instead, which is more stable and complete
+
+lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition
+    .suggestion = you can use a raw identifier to stay compatible
+
+lint_builtin_link_section_fn = declaration of a function with `link_section`
+
+lint_builtin_link_section_static = declaration of a static with `link_section`
+
+lint_builtin_missing_copy_impl = type could implement `Copy`; consider adding `impl Copy`
+
+lint_builtin_missing_debug_impl =
+    type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation
+
+lint_builtin_missing_doc = missing documentation for {$article} {$desc}
+
+lint_builtin_mutable_transmutes =
+    transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
+
+lint_builtin_no_mangle_fn = declaration of a `no_mangle` function
+lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled
+    .suggestion = remove this attribute
+
+lint_builtin_no_mangle_method = declaration of a `no_mangle` method
+lint_builtin_no_mangle_static = declaration of a `no_mangle` static
+lint_builtin_non_shorthand_field_patterns = the `{$ident}:` in this pattern is redundant
+    .suggestion = use shorthand field pattern
+
+lint_builtin_overridden_symbol_name =
+    the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them
+
+lint_builtin_overridden_symbol_section =
+    the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them
+
+lint_builtin_special_module_name_used_lib = found module declaration for lib.rs
+    .note = lib.rs is the root of this crate's library target
+    .help = to refer to it from other targets, use the library's name as the path
+
+lint_builtin_special_module_name_used_main = found module declaration for main.rs
+    .note = a binary crate cannot be used as library
+
+lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters
+
+lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
+
+lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases
+    .suggestion = the bound will not be checked when the type alias is used, and should be removed
+
+lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases
+    .suggestion = the clause will not be checked when the type alias is used, and should be removed
+
+lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
+    .help = was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
+    .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+lint_builtin_unnameable_test_items = cannot test inner items
+
+lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
+lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+
+lint_builtin_unpermitted_type_init_uninit = the type `{$ty}` does not permit being left uninitialized
+
+lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization
+lint_builtin_unreachable_pub = unreachable `pub` {$what}
+    .suggestion = consider restricting its visibility
+    .help = or consider exporting it for use by other crates
+
+lint_builtin_unsafe_block = usage of an `unsafe` block
+
+lint_builtin_unsafe_impl = implementation of an `unsafe` trait
+
+lint_builtin_unsafe_trait = declaration of an `unsafe` trait
+
+lint_builtin_unstable_features = unstable feature
+
+lint_builtin_unused_doc_comment = unused doc comment
+    .label = rustdoc does not generate documentation for {$kind}
+    .plain_help = use `//` for a plain comment
+    .block_help = use `/* */` for a plain comment
+
+lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
+    .suggestion = use `loop`
+
+lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
+
+lint_check_name_unknown = unknown lint: `{$lint_name}`
+    .help = did you mean: `{$suggestion}`
+
+lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
+
+lint_check_name_warning = {$msg}
+
+lint_command_line_source = `forbid` lint level was set on command line
+
+lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}`
+    .label = this is where the previous identifier occurred
+
+lint_cstring_ptr = getting the inner pointer of a temporary `CString`
+    .as_ptr_label = this pointer will be invalid
+    .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+    .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+    .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
+
+lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
+    .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
+
+lint_default_source = `forbid` lint level is the default for {$id}
+
+lint_deprecated_lint_name =
+    lint name `{$name}` is deprecated and may not have an effect in the future.
+    .suggestion = change it to
+
+lint_diag_out_of_impl =
+    diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
+
+lint_drop_glue =
+    types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped
+
+lint_drop_trait_constraints =
+    bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped
+
+lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing
+    .label = argument has type `{$arg_ty}`
+    .note = use `let _ = ...` to ignore the expression or result
+
+lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing
+    .label = argument has type `{$arg_ty}`
+    .note = use `let _ = ...` to ignore the expression or result
+
 lint_enum_intrinsics_mem_discriminant =
     the return value of `mem::discriminant` is unspecified when called with a non-enum type
     .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum.
@@ -24,49 +220,12 @@
     .use_while_let = to check pattern in a loop use `while let`
     .use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents
 
-lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
-    .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
-    .function_label = this function returns `()`, which is likely not what you wanted
-    .argument_label = called `Iterator::map` with callable that returns `()`
-    .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
-    .suggestion = you might have meant to use `Iterator::for_each`
-
-lint_non_binding_let_on_sync_lock =
-    non-binding let on a synchronization lock
-
-lint_non_binding_let_on_drop_type =
-    non-binding let on a type that implements `Drop`
-
-lint_non_binding_let_suggestion =
-    consider binding to an unused variable to avoid immediately dropping the value
-
-lint_non_binding_let_multi_suggestion =
-    consider immediately dropping the value
-
-lint_deprecated_lint_name =
-    lint name `{$name}` is deprecated and may not have an effect in the future.
-    .suggestion = change it to
-
-lint_renamed_or_removed_lint = {$msg}
-    .suggestion = use the new name
-
-lint_suspicious_double_ref_op =
-    using `.{$call}()` on a double reference, which returns `{$ty}` instead of {$op ->
-        *[should_not_happen] [{$op}]
-        [deref] dereferencing
-        [borrow] borrowing
-        [clone] cloning
-    } the inner type
-
-lint_unknown_lint =
-    unknown lint: `{$name}`
-    .suggestion = did you mean
-
-lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
-
-lint_unknown_gated_lint =
-    unknown lint: `{$name}`
-    .note = the `{$name}` lint is unstable
+lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing
+    .label = argument has type `{$arg_ty}`
+    .note = use `let _ = ...` to ignore the expression or result
+lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing
+    .label = argument has type `{$arg_ty}`
+    .note = use `let _ = ...` to ignore the expression or result
 
 lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
     .label = this {$label} contains {$count ->
@@ -81,56 +240,111 @@
     .suggestion_escape = if you want to keep them but make them visible in your source code, you can escape them
     .no_suggestion_note_escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped}
 
-lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
-    .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
-
-lint_query_instability = using `{$query}` can result in unstable query results
-    .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
-
-lint_tykind_kind = usage of `ty::TyKind::<kind>`
-    .suggestion = try using `ty::<kind>` directly
-
-lint_tykind = usage of `ty::TyKind`
-    .help = try using `Ty` instead
-
-lint_ty_qualified = usage of qualified `ty::{$ty}`
-    .suggestion = try importing it and using it unqualified
-
-lint_lintpass_by_hand = implementing `LintPass` by hand
-    .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
-
-lint_non_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]`
-    .help = only existing keywords are allowed in core/std
-
-lint_diag_out_of_impl =
-    diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
-
-lint_untranslatable_diag = diagnostics should be created using translatable messages
-
-lint_trivial_untranslatable_diag = diagnostic with static strings only
-
-lint_bad_opt_access = {$msg}
-
-lint_cstring_ptr = getting the inner pointer of a temporary `CString`
-    .as_ptr_label = this pointer will be invalid
-    .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
-    .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-    .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
-
-lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
-
 lint_identifier_non_ascii_char = identifier contains non-ASCII characters
 
 lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
 
-lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}`
-    .label = this is where the previous identifier occurred
+lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
+
+lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
+    .label = not FFI-safe
+    .note = the type is defined here
+
+lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI
+
+lint_improper_ctypes_array_help = consider passing a pointer to the array
+
+lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe
+lint_improper_ctypes_box = box cannot be represented as a single pointer
+
+lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
+
+lint_improper_ctypes_char_reason = the `char` type has no C equivalent
+lint_improper_ctypes_dyn = trait objects have no C equivalent
+
+lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
+
+lint_improper_ctypes_enum_repr_help =
+    consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+
+lint_improper_ctypes_enum_repr_reason = enum has no representation hint
+lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead
+
+lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention
+lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive
+lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants
+
+lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
+
+lint_improper_ctypes_opaque = opaque types have no C equivalent
+
+lint_improper_ctypes_slice_help = consider using a raw pointer instead
+
+lint_improper_ctypes_slice_reason = slices have no C equivalent
+lint_improper_ctypes_str_help = consider using `*const u8` and a length instead
+
+lint_improper_ctypes_str_reason = string slices have no C equivalent
+lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct
+
+lint_improper_ctypes_struct_fieldless_reason = this struct has no fields
+lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+
+lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout
+lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive
+lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields
+
+lint_improper_ctypes_tuple_help = consider using a struct instead
+
+lint_improper_ctypes_tuple_reason = tuples have unspecified layout
+lint_improper_ctypes_union_fieldless_help = consider adding a member to this union
+
+lint_improper_ctypes_union_fieldless_reason = this union has no fields
+lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
+
+lint_improper_ctypes_union_layout_reason = this union has unspecified layout
+lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
+
+lint_lintpass_by_hand = implementing `LintPass` by hand
+    .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
+
+lint_malformed_attribute = malformed lint attribute input
+
+lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
+    .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
+    .function_label = this function returns `()`, which is likely not what you wanted
+    .argument_label = called `Iterator::map` with callable that returns `()`
+    .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
+    .suggestion = you might have meant to use `Iterator::for_each`
 
 lint_mixed_script_confusables =
     the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
     .includes_note = the usage includes {$includes}
     .note = please recheck to make sure their usages are indeed what you want
 
+lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
+
+lint_node_source = `forbid` level set here
+    .note = {$reason}
+
+lint_non_binding_let_multi_suggestion =
+    consider immediately dropping the value
+
+lint_non_binding_let_on_drop_type =
+    non-binding let on a type that implements `Drop`
+
+lint_non_binding_let_on_sync_lock =
+    non-binding let on a synchronization lock
+
+lint_non_binding_let_suggestion =
+    consider binding to an unused variable to avoid immediately dropping the value
+
+lint_non_camel_case_type = {$sort} `{$name}` should have an upper camel case name
+    .suggestion = convert the identifier to upper camel case
+    .label = should have an UpperCamelCase name
+
+lint_non_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]`
+    .help = only existing keywords are allowed in core/std
+
 lint_non_fmt_panic = panic message is not a string literal
     .note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021
     .more_info_note = for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
@@ -144,6 +358,14 @@
         *[false] use
     } std::panic::panic_any instead
 
+lint_non_fmt_panic_braces =
+    panic message contains {$count ->
+        [one] a brace
+        *[other] braces
+    }
+    .note = this message is not used as a format string, but will be in Rust 2021
+    .suggestion = add a "{"{"}{"}"}" format string to use the message literally
+
 lint_non_fmt_panic_unused =
     panic message contains {$count ->
         [one] an unused
@@ -159,18 +381,6 @@
     }
     .add_fmt_suggestion = or add a "{"{"}{"}"}" format string to use the message literally
 
-lint_non_fmt_panic_braces =
-    panic message contains {$count ->
-        [one] a brace
-        *[other] braces
-    }
-    .note = this message is not used as a format string, but will be in Rust 2021
-    .suggestion = add a "{"{"}{"}"}" format string to use the message literally
-
-lint_non_camel_case_type = {$sort} `{$name}` should have an upper camel case name
-    .suggestion = convert the identifier to upper camel case
-    .label = should have an UpperCamelCase name
-
 lint_non_snake_case = {$sort} `{$name}` should have a snake case name
     .rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier
     .cannot_convert_note = `{$sc}` cannot be used as a raw identifier
@@ -187,29 +397,13 @@
     .label = unnecessary method call
     .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed
 
-lint_pass_by_value = passing `{$ty}` by reference
-    .suggestion = try passing by value
+lint_only_cast_u8_to_char = only `u8` can be cast into `char`
+    .suggestion = use a `char` literal instead
 
-lint_redundant_semicolons =
-    unnecessary trailing {$multiple ->
-        [true] semicolons
-        *[false] semicolon
-    }
-    .suggestion = remove {$multiple ->
-        [true] these semicolons
-        *[false] this semicolon
-    }
+lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds
+    .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
 
-lint_drop_trait_constraints =
-    bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped
-
-lint_drop_glue =
-    types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped
-
-lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}`
-
-lint_range_use_inclusive_range = use an inclusive range instead
-
+lint_opaque_hidden_inferred_bound_sugg = add this bound
 
 lint_overflowing_bin_hex = literal out of range for `{$ty}`
     .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
@@ -222,96 +416,92 @@
     .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
     .help = consider using the type `{$suggestion_ty}` instead
 
-lint_only_cast_u8_to_char = only `u8` can be cast into `char`
-    .suggestion = use a `char` literal instead
+lint_overflowing_literal = literal out of range for `{$ty}`
+    .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY`
 
 lint_overflowing_uint = literal out of range for `{$ty}`
     .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
 
-lint_overflowing_literal = literal out of range for `{$ty}`
-    .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY`
+lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
+    .label = overruled by previous forbid
 
-lint_unused_comparisons = comparison is useless due to type limits
+lint_pass_by_value = passing `{$ty}` by reference
+    .suggestion = try passing by value
 
-lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
-    .label = not FFI-safe
-    .note = the type is defined here
+lint_path_statement_drop = path statement drops value
+    .suggestion = use `drop` to clarify the intent
 
-lint_improper_ctypes_opaque = opaque types have no C equivalent
+lint_path_statement_no_effect = path statement with no effect
 
-lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention
-lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead
+lint_query_instability = using `{$query}` can result in unstable query results
+    .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
-lint_improper_ctypes_tuple_reason = tuples have unspecified layout
-lint_improper_ctypes_tuple_help = consider using a struct instead
+lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}`
 
-lint_improper_ctypes_str_reason = string slices have no C equivalent
-lint_improper_ctypes_str_help = consider using `*const u8` and a length instead
+lint_range_use_inclusive_range = use an inclusive range instead
 
-lint_improper_ctypes_dyn = trait objects have no C equivalent
 
-lint_improper_ctypes_slice_reason = slices have no C equivalent
-lint_improper_ctypes_slice_help = consider using a raw pointer instead
+lint_reason_must_be_string_literal = reason must be a string literal
 
-lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI
+lint_reason_must_come_last = reason in lint attribute must come last
 
-lint_improper_ctypes_char_reason = the `char` type has no C equivalent
-lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
+lint_redundant_semicolons =
+    unnecessary trailing {$multiple ->
+        [true] semicolons
+        *[false] semicolon
+    }
+    .suggestion = remove {$multiple ->
+        [true] these semicolons
+        *[false] this semicolon
+    }
 
-lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive
-lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants
+lint_renamed_or_removed_lint = {$msg}
+    .suggestion = use the new name
 
-lint_improper_ctypes_enum_repr_reason = enum has no representation hint
-lint_improper_ctypes_enum_repr_help =
-    consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+lint_requested_level = requested on the command line with `{$level} {$lint_name}`
 
-lint_improper_ctypes_struct_fieldless_reason = this struct has no fields
-lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct
+lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
+    .label = target type is set here
 
-lint_improper_ctypes_union_fieldless_reason = this union has no fields
-lint_improper_ctypes_union_fieldless_help = consider adding a member to this union
+lint_suspicious_double_ref_op =
+    using `.{$call}()` on a double reference, which returns `{$ty}` instead of {$op ->
+        *[should_not_happen] [{$op}]
+        [deref] dereferencing
+        [borrow] borrowing
+        [clone] cloning
+    } the inner type
 
-lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive
-lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
+lint_trivial_untranslatable_diag = diagnostic with static strings only
 
-lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout
-lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+lint_ty_qualified = usage of qualified `ty::{$ty}`
+    .suggestion = try importing it and using it unqualified
 
-lint_improper_ctypes_union_layout_reason = this union has unspecified layout
-lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
+lint_tykind = usage of `ty::TyKind`
+    .help = try using `Ty` instead
 
-lint_improper_ctypes_box = box cannot be represented as a single pointer
+lint_tykind_kind = usage of `ty::TyKind::<kind>`
+    .suggestion = try using `ty::<kind>` directly
 
-lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
+lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
+     .label = this function will not propagate the caller location
 
-lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields
+lint_unknown_gated_lint =
+    unknown lint: `{$name}`
+    .note = the `{$name}` lint is unstable
 
-lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe
-lint_improper_ctypes_array_help = consider passing a pointer to the array
+lint_unknown_lint =
+    unknown lint: `{$name}`
+    .suggestion = did you mean
 
-lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
+lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
+    .help = add `#![register_tool({$tool_name})]` to the crate root
 
-lint_variant_size_differences =
-    enum variant is more than three times larger ({$largest} bytes) than the next largest
+lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
 
-lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering
-    .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+lint_untranslatable_diag = diagnostics should be created using translatable messages
 
-lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
-    .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
-
-lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering
-    .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
-
-lint_atomic_ordering_invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write
-    .label = invalid failure ordering
-    .help = consider using `Acquire` or `Relaxed` failure ordering instead
-
-lint_unused_op = unused {$op} that must be used
-    .label = the {$op} produces a value
-    .suggestion = use `let _ = ...` to ignore the resulting value
-
-lint_unused_result = unused result of type `{$ty}`
+lint_unused_allocation = unnecessary allocation, use `&` instead
+lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
 
 lint_unused_closure =
     unused {$pre}{$count ->
@@ -320,6 +510,14 @@
     }{$post} that must be used
     .note = closures are lazy and do nothing unless called
 
+lint_unused_comparisons = comparison is useless due to type limits
+
+lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
+    .suggestion = use `let _ = ...` to ignore the resulting value
+
+lint_unused_delim = unnecessary {$delim} around {$item}
+    .suggestion = remove these {$delim}
+
 lint_unused_generator =
     unused {$pre}{$count ->
         [one] generator
@@ -327,212 +525,13 @@
     }{$post} that must be used
     .note = generators are lazy and do nothing unless resumed
 
-lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
-    .suggestion = use `let _ = ...` to ignore the resulting value
-
-lint_path_statement_drop = path statement drops value
-    .suggestion = use `drop` to clarify the intent
-
-lint_path_statement_no_effect = path statement with no effect
-
-lint_unused_delim = unnecessary {$delim} around {$item}
-    .suggestion = remove these {$delim}
-
 lint_unused_import_braces = braces around {$node} is unnecessary
 
-lint_unused_allocation = unnecessary allocation, use `&` instead
-lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
+lint_unused_op = unused {$op} that must be used
+    .label = the {$op} produces a value
+    .suggestion = use `let _ = ...` to ignore the resulting value
 
-lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
-    .suggestion = use `loop`
+lint_unused_result = unused result of type `{$ty}`
 
-lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty}
-
-lint_builtin_non_shorthand_field_patterns = the `{$ident}:` in this pattern is redundant
-    .suggestion = use shorthand field pattern
-
-lint_builtin_overridden_symbol_name =
-    the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them
-
-lint_builtin_overridden_symbol_section =
-    the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them
-
-lint_builtin_allow_internal_unsafe =
-    `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site
-
-lint_builtin_unsafe_block = usage of an `unsafe` block
-
-lint_builtin_unsafe_trait = declaration of an `unsafe` trait
-
-lint_builtin_unsafe_impl = implementation of an `unsafe` trait
-
-lint_builtin_no_mangle_fn = declaration of a `no_mangle` function
-lint_builtin_export_name_fn = declaration of a function with `export_name`
-lint_builtin_link_section_fn = declaration of a function with `link_section`
-
-lint_builtin_no_mangle_static = declaration of a `no_mangle` static
-lint_builtin_export_name_static = declaration of a static with `export_name`
-lint_builtin_link_section_static = declaration of a static with `link_section`
-
-lint_builtin_no_mangle_method = declaration of a `no_mangle` method
-lint_builtin_export_name_method = declaration of a method with `export_name`
-
-lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
-lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
-lint_builtin_impl_unsafe_method = implementation of an `unsafe` method
-
-lint_builtin_missing_doc = missing documentation for {$article} {$desc}
-
-lint_builtin_missing_copy_impl = type could implement `Copy`; consider adding `impl Copy`
-
-lint_builtin_missing_debug_impl =
-    type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation
-
-lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition
-    .suggestion = try naming the parameter or explicitly ignoring it
-
-lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
-    .msg_suggestion = {$msg}
-    .default_suggestion = remove this attribute
-lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used.
-lint_builtin_deprecated_attr_default_suggestion = remove this attribute
-
-lint_builtin_unused_doc_comment = unused doc comment
-    .label = rustdoc does not generate documentation for {$kind}
-    .plain_help = use `//` for a plain comment
-    .block_help = use `/* */` for a plain comment
-
-lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled
-    .suggestion = remove this attribute
-
-lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
-    .suggestion = try a static value
-
-lint_builtin_mutable_transmutes =
-    transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
-
-lint_builtin_unstable_features = unstable feature
-
-lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
-     .label = this function will not propagate the caller location
-
-lint_builtin_unreachable_pub = unreachable `pub` {$what}
-    .suggestion = consider restricting its visibility
-    .help = or consider exporting it for use by other crates
-
-lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
-    .help = was set with `--cfg` but isn't in the `--check-cfg` expected names
-
-lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
-    .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
-
-lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
-
-lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases
-    .suggestion = the clause will not be checked when the type alias is used, and should be removed
-
-lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases
-    .suggestion = the bound will not be checked when the type alias is used, and should be removed
-
-lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters
-
-lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
-    .suggestion = use `..=` for an inclusive range
-
-lint_builtin_unnameable_test_items = cannot test inner items
-
-lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition
-    .suggestion = you can use a raw identifier to stay compatible
-
-lint_builtin_explicit_outlives = outlives requirements can be inferred
-    .suggestion = remove {$count ->
-        [one] this bound
-        *[other] these bounds
-    }
-
-lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes
-    .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
-    .help = consider using `min_{$name}` instead, which is more stable and complete
-
-lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization
-lint_builtin_unpermitted_type_init_uninit = the type `{$ty}` does not permit being left uninitialized
-
-lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
-lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
-
-lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature
-    .previous_decl_label = `{$orig}` previously declared here
-    .mismatch_label = this signature doesn't match the previous declaration
-lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature
-    .previous_decl_label = `{$orig}` previously declared here
-    .mismatch_label = this signature doesn't match the previous declaration
-
-lint_builtin_deref_nullptr = dereferencing a null pointer
-    .label = this code causes undefined behavior when executed
-
-lint_builtin_asm_labels = avoid using named labels in inline assembly
-
-lint_builtin_special_module_name_used_lib = found module declaration for lib.rs
-    .note = lib.rs is the root of this crate's library target
-    .help = to refer to it from other targets, use the library's name as the path
-
-lint_builtin_special_module_name_used_main = found module declaration for main.rs
-    .note = a binary crate cannot be used as library
-
-lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
-    .label = target type is set here
-
-lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
-    .label = overruled by previous forbid
-
-lint_default_source = `forbid` lint level is the default for {$id}
-
-lint_node_source = `forbid` level set here
-    .note = {$reason}
-
-lint_command_line_source = `forbid` lint level was set on command line
-
-lint_malformed_attribute = malformed lint attribute input
-
-lint_bad_attribute_argument = bad attribute argument
-
-lint_reason_must_be_string_literal = reason must be a string literal
-
-lint_reason_must_come_last = reason in lint attribute must come last
-
-lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
-    .help = add `#![register_tool({$tool_name})]` to the crate root
-
-lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
-
-lint_requested_level = requested on the command line with `{$level} {$lint_name}`
-
-lint_check_name_unknown = unknown lint: `{$lint_name}`
-    .help = did you mean: `{$suggestion}`
-
-lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
-
-lint_check_name_warning = {$msg}
-
-lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
-
-lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds
-    .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
-
-lint_opaque_hidden_inferred_bound_sugg = add this bound
-
-lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing
-    .label = argument has type `{$arg_ty}`
-    .note = use `let _ = ...` to ignore the expression or result
-
-lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing
-    .label = argument has type `{$arg_ty}`
-    .note = use `let _ = ...` to ignore the expression or result
-
-lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing
-    .label = argument has type `{$arg_ty}`
-    .note = use `let _ = ...` to ignore the expression or result
-
-lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing
-    .label = argument has type `{$arg_ty}`
-    .note = use `let _ = ...` to ignore the expression or result
+lint_variant_size_differences =
+    enum variant is more than three times larger ({$largest} bytes) than the next largest
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 1d0c43e..947530a 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -952,6 +952,10 @@ fn lookup_with_diagnostics(
                     db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace));
                     db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace));
                 }
+                BuiltinLintDiagnostics::HiddenGlobReexports { name, namespace, glob_reexport_span, private_item_span } => {
+                    db.span_label(glob_reexport_span, format!("the name `{}` in the {} namespace is supposed to be publicly re-exported here", name, namespace));
+                    db.span_label(private_item_span, "but the private item here shadows it");
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(db)
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index b92ed11f..8376835 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -242,7 +242,9 @@ fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
 
 struct QueryMapExpectationsWrapper<'tcx> {
     tcx: TyCtxt<'tcx>,
+    /// HirId of the currently investigated element.
     cur: HirId,
+    /// Level map for `cur`.
     specs: ShallowLintLevelMap,
     expectations: Vec<(LintExpectationId, LintExpectation)>,
     unstable_to_stable_ids: FxHashMap<LintExpectationId, LintExpectationId>,
@@ -255,11 +257,11 @@ fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
         self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
     }
     fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
-        let specs = self.specs.specs.get_mut_or_insert_default(self.cur.local_id);
-        specs.clear();
-        specs.insert(id, lvl);
+        self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl);
     }
     fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
+        // We cannot use `tcx.lint_level_at_node` because we want to know in which order the
+        // attributes have been inserted, in particular whether an `expect` follows a `forbid`.
         self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
     }
     fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
@@ -355,7 +357,9 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
 
 impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> {
     fn add_id(&mut self, hir_id: HirId) {
+        // Change both the `HirId` and the associated specs.
         self.provider.cur = hir_id;
+        self.provider.specs.specs.clear();
         self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id));
     }
 }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 6e9dc88..1507087 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3272,6 +3272,43 @@
     "ambiguous glob re-exports",
 }
 
+declare_lint! {
+    /// The `hidden_glob_reexports` lint detects cases where glob re-export items are shadowed by
+    /// private items.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(hidden_glob_reexports)]
+    ///
+    /// pub mod upstream {
+    ///     mod inner { pub struct Foo {}; pub struct Bar {}; }
+    ///     pub use self::inner::*;
+    ///     struct Foo {} // private item shadows `inner::Foo`
+    /// }
+    ///
+    /// // mod downstream {
+    /// //     fn test() {
+    /// //         let _ = crate::upstream::Foo; // inaccessible
+    /// //     }
+    /// // }
+    ///
+    /// pub fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This was previously accepted without any errors or warnings but it could silently break a
+    /// crate's downstream user code. If the `struct Foo` was added, `dep::inner::Foo` would
+    /// silently become inaccessible and trigger a "`struct `Foo` is private`" visibility error at
+    /// the downstream use site.
+    pub HIDDEN_GLOB_REEXPORTS,
+    Warn,
+    "name introduced by a private item shadows a name introduced by a public glob re-export",
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -3304,6 +3341,7 @@
         FORBIDDEN_LINT_GROUPS,
         FUNCTION_ITEM_REFERENCES,
         FUZZY_PROVENANCE_CASTS,
+        HIDDEN_GLOB_REEXPORTS,
         ILL_FORMED_ATTRIBUTE_INPUT,
         ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
         IMPLIED_BOUNDS_ENTAILMENT,
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index e27e322..5a5031b 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -540,6 +540,16 @@ pub enum BuiltinLintDiagnostics {
         /// Span where the same name is also re-exported.
         duplicate_reexport_span: Span,
     },
+    HiddenGlobReexports {
+        /// The name of the local binding which shadows the glob re-export.
+        name: String,
+        /// The namespace for which the shadowing occurred in.
+        namespace: String,
+        /// The glob reexport that is shadowed by the local binding.
+        glob_reexport_span: Span,
+        /// The local binding that shadows the glob reexport.
+        private_item_span: Span,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 0589062..af6f4d5 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -96,6 +96,7 @@
   AllocatedPointer = 38,
   AllocAlign = 39,
 #endif
+  SanitizeSafeStack = 40,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 49acd71..ea04899 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -234,6 +234,8 @@
   case AllocAlign:
     return Attribute::AllocAlign;
 #endif
+  case SanitizeSafeStack:
+    return Attribute::SafeStack;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 79b8b41..6d8601b 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -1,131 +1,58 @@
-metadata_rlib_required =
-    crate `{$crate_name}` required to be available in rlib format, but was not found in this form
+metadata_as_needed_compatibility =
+    linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
 
-metadata_lib_required =
-    crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+metadata_bad_panic_strategy =
+    the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
 
-metadata_rustc_lib_required =
-    crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
-    .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
-    .help = try adding `extern crate rustc_driver;` at the top level of this crate
+metadata_bundle_needs_static =
+    linking modifier `bundle` is only compatible with `static` linking kind
+
+metadata_cannot_find_crate =
+    can't find crate for `{$crate_name}`{$add_info}
+
+metadata_cant_find_crate =
+    can't find crate
+
+metadata_compiler_missing_profiler =
+    the compiler may have been built without the profiler runtime
+
+metadata_conflicting_alloc_error_handler =
+    the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
+
+metadata_conflicting_global_alloc =
+    the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
+
+metadata_consider_building_std =
+    consider building the standard library from source with `cargo build -Zbuild-std`
+
+metadata_consider_downloading_target =
+    consider downloading the target with `rustup target add {$locator_triple}`
 
 metadata_crate_dep_multiple =
     cannot satisfy dependencies so `{$crate_name}` only shows up once
     .help = having upstream crates all available in one format will likely make this go away
 
-metadata_two_panic_runtimes =
-    cannot link together two panic runtimes: {$prev_name} and {$cur_name}
+metadata_crate_location_unknown_type =
+    extern location for {$crate_name} is of an unknown type: {$path}
 
-metadata_bad_panic_strategy =
-    the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
+metadata_crate_not_panic_runtime =
+    the crate `{$crate_name}` is not a panic runtime
 
-metadata_required_panic_strategy =
-    the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
-
-metadata_incompatible_panic_in_drop_strategy =
-    the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
-
-metadata_multiple_names_in_link =
-    multiple `name` arguments in a single `#[link]` attribute
-
-metadata_multiple_kinds_in_link =
-    multiple `kind` arguments in a single `#[link]` attribute
-
-metadata_link_name_form =
-    link name must be of the form `name = "string"`
-
-metadata_link_kind_form =
-    link kind must be of the form `kind = "string"`
-
-metadata_link_modifiers_form =
-    link modifiers must be of the form `modifiers = "string"`
-
-metadata_link_cfg_form =
-    link cfg must be of the form `cfg(/* predicate */)`
-
-metadata_wasm_import_form =
-    wasm import module must be of the form `wasm_import_module = "string"`
+metadata_dl_error =
+    {$err}
 
 metadata_empty_link_name =
     link name must not be empty
     .label = empty link name
 
-metadata_link_framework_apple =
-    link kind `framework` is only supported on Apple targets
-
-metadata_framework_only_windows =
-    link kind `raw-dylib` is only supported on Windows targets
-
-metadata_unknown_link_kind =
-    unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib
-    .label = unknown link kind
-
-metadata_multiple_link_modifiers =
-    multiple `modifiers` arguments in a single `#[link]` attribute
-
-metadata_multiple_cfgs =
-    multiple `cfg` arguments in a single `#[link]` attribute
-
-metadata_link_cfg_single_predicate =
-    link cfg must have a single predicate argument
-
-metadata_multiple_wasm_import =
-    multiple `wasm_import_module` arguments in a single `#[link]` attribute
-
-metadata_unexpected_link_arg =
-    unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
-
-metadata_invalid_link_modifier =
-    invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
-
-metadata_multiple_modifiers =
-    multiple `{$modifier}` modifiers in a single `modifiers` argument
-
-metadata_bundle_needs_static =
-    linking modifier `bundle` is only compatible with `static` linking kind
-
-metadata_whole_archive_needs_static =
-    linking modifier `whole-archive` is only compatible with `static` linking kind
-
-metadata_as_needed_compatibility =
-    linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
-
-metadata_unknown_link_modifier =
-    unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
-
-metadata_incompatible_wasm_link =
-    `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
-
-metadata_link_requires_name =
-    `#[link]` attribute requires a `name = "string"` argument
-    .label = missing `name` argument
-
-metadata_raw_dylib_no_nul =
-    link name must not contain NUL characters if link kind is `raw-dylib`
-
-metadata_link_ordinal_raw_dylib =
-    `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-
-metadata_lib_framework_apple =
-    library kind `framework` is only supported on Apple targets
-
 metadata_empty_renaming_target =
     an empty renaming target was specified for library `{$lib_name}`
 
-metadata_renaming_no_link =
-    renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library
+metadata_extern_location_not_exist =
+    extern location for {$crate_name} does not exist: {$location}
 
-metadata_multiple_renamings =
-    multiple renamings were specified for library `{$lib_name}`
-
-metadata_no_link_mod_override =
-    overriding linking modifiers from command line is not supported
-
-metadata_unsupported_abi_i686 =
-    ABI not supported by `#[link(kind = "raw-dylib")]` on i686
-
-metadata_unsupported_abi =
-    ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
+metadata_extern_location_not_file =
+    extern location for {$crate_name} is not a file: {$location}
 
 metadata_fail_create_file_encoder =
     failed to create file encoder: {$err}
@@ -136,72 +63,189 @@
 metadata_fail_write_file =
     failed to write to the file: {$err}
 
-metadata_crate_not_panic_runtime =
-    the crate `{$crate_name}` is not a panic runtime
+metadata_failed_create_encoded_metadata =
+    failed to create encoded metadata from file: {$err}
 
-metadata_no_panic_strategy =
-    the crate `{$crate_name}` does not have the panic strategy `{$strategy}`
+metadata_failed_create_file =
+    failed to create the file {$filename}: {$err}
 
-metadata_profiler_builtins_needs_core =
-    `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]`
+metadata_failed_create_tempdir =
+    couldn't create a temp dir: {$err}
 
-metadata_not_profiler_runtime =
-    the crate `{$crate_name}` is not a profiler runtime
+metadata_failed_write_error =
+    failed to write {$filename}: {$err}
 
-metadata_no_multiple_global_alloc =
-    cannot define multiple global allocators
-    .label = cannot define a new global allocator
+metadata_found_crate_versions =
+    the following crate versions were found:{$found_crates}
 
-metadata_prev_global_alloc =
-    previous global allocator defined here
+metadata_found_staticlib =
+    found staticlib `{$crate_name}` instead of rlib or dylib{$add_info}
+    .help = please recompile that crate using --crate-type lib
+
+metadata_framework_only_windows =
+    link kind `raw-dylib` is only supported on Windows targets
+
+metadata_global_alloc_required =
+    no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
+
+metadata_import_name_type_form =
+    import name type must be of the form `import_name_type = "string"`
+
+metadata_import_name_type_raw =
+    import name type can only be used with link kind `raw-dylib`
+
+metadata_import_name_type_x86 =
+    import name type is only supported on x86
+
+metadata_incompatible_panic_in_drop_strategy =
+    the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+
+metadata_incompatible_rustc =
+    found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
+    .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
+
+metadata_incompatible_wasm_link =
+    `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
+
+metadata_install_missing_components =
+    maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
+
+metadata_invalid_link_modifier =
+    invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+
+metadata_invalid_meta_files =
+    found invalid metadata files for crate `{$crate_name}`{$add_info}
+
+metadata_lib_filename_form =
+    file name should be lib*.rlib or {$dll_prefix}*{$dll_suffix}
+
+metadata_lib_framework_apple =
+    library kind `framework` is only supported on Apple targets
+
+metadata_lib_required =
+    crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+
+metadata_link_cfg_form =
+    link cfg must be of the form `cfg(/* predicate */)`
+
+metadata_link_cfg_single_predicate =
+    link cfg must have a single predicate argument
+
+metadata_link_framework_apple =
+    link kind `framework` is only supported on Apple targets
+
+metadata_link_kind_form =
+    link kind must be of the form `kind = "string"`
+
+metadata_link_modifiers_form =
+    link modifiers must be of the form `modifiers = "string"`
+
+metadata_link_name_form =
+    link name must be of the form `name = "string"`
+
+metadata_link_ordinal_raw_dylib =
+    `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+
+metadata_link_requires_name =
+    `#[link]` attribute requires a `name = "string"` argument
+    .label = missing `name` argument
+
+metadata_missing_native_library =
+    could not find native static library `{$libname}`, perhaps an -L flag is missing?
+
+metadata_multiple_candidates =
+    multiple candidates for `{$flavor}` dependency `{$crate_name}` found
+
+metadata_multiple_cfgs =
+    multiple `cfg` arguments in a single `#[link]` attribute
+
+metadata_multiple_import_name_type =
+    multiple `import_name_type` arguments in a single `#[link]` attribute
+
+metadata_multiple_kinds_in_link =
+    multiple `kind` arguments in a single `#[link]` attribute
+
+metadata_multiple_link_modifiers =
+    multiple `modifiers` arguments in a single `#[link]` attribute
+
+metadata_multiple_modifiers =
+    multiple `{$modifier}` modifiers in a single `modifiers` argument
+
+metadata_multiple_names_in_link =
+    multiple `name` arguments in a single `#[link]` attribute
+
+metadata_multiple_renamings =
+    multiple renamings were specified for library `{$lib_name}`
+
+metadata_multiple_wasm_import =
+    multiple `wasm_import_module` arguments in a single `#[link]` attribute
+
+metadata_newer_crate_version =
+    found possibly newer version of crate `{$crate_name}`{$add_info}
+    .note = perhaps that crate needs to be recompiled?
+
+metadata_no_crate_with_triple =
+    couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info}
+
+metadata_no_dylib_plugin =
+    plugin `{$crate_name}` only found in rlib format, but must be available in dylib format
+
+metadata_no_link_mod_override =
+    overriding linking modifiers from command line is not supported
 
 metadata_no_multiple_alloc_error_handler =
     cannot define multiple allocation error handlers
     .label = cannot define a new allocation error handler
 
-metadata_prev_alloc_error_handler =
-    previous allocation error handler defined here
+metadata_no_multiple_global_alloc =
+    cannot define multiple global allocators
+    .label = cannot define a new global allocator
 
-metadata_conflicting_global_alloc =
-    the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
-
-metadata_conflicting_alloc_error_handler =
-    the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
-
-metadata_global_alloc_required =
-    no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
+metadata_no_panic_strategy =
+    the crate `{$crate_name}` does not have the panic strategy `{$strategy}`
 
 metadata_no_transitive_needs_dep =
     the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
 
-metadata_failed_write_error =
-    failed to write {$filename}: {$err}
-
-metadata_missing_native_library =
-    could not find native static library `{$libname}`, perhaps an -L flag is missing?
-
-metadata_only_provide_library_name = only provide the library name `{$suggested_name}`, not the full filename
-
-metadata_failed_create_tempdir =
-    couldn't create a temp dir: {$err}
-
-metadata_failed_create_file =
-    failed to create the file {$filename}: {$err}
-
-metadata_failed_create_encoded_metadata =
-    failed to create encoded metadata from file: {$err}
-
 metadata_non_ascii_name =
     cannot load a crate with a non-ascii name `{$crate_name}`
 
-metadata_extern_location_not_exist =
-    extern location for {$crate_name} does not exist: {$location}
+metadata_not_profiler_runtime =
+    the crate `{$crate_name}` is not a profiler runtime
 
-metadata_extern_location_not_file =
-    extern location for {$crate_name} is not a file: {$location}
+metadata_only_provide_library_name = only provide the library name `{$suggested_name}`, not the full filename
 
-metadata_multiple_candidates =
-    multiple candidates for `{$flavor}` dependency `{$crate_name}` found
+metadata_prev_alloc_error_handler =
+    previous allocation error handler defined here
+
+metadata_prev_global_alloc =
+    previous global allocator defined here
+
+metadata_profiler_builtins_needs_core =
+    `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]`
+
+metadata_raw_dylib_no_nul =
+    link name must not contain NUL characters if link kind is `raw-dylib`
+
+metadata_renaming_no_link =
+    renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library
+
+metadata_required_panic_strategy =
+    the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+
+metadata_rlib_required =
+    crate `{$crate_name}` required to be available in rlib format, but was not found in this form
+
+metadata_rustc_lib_required =
+    crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+    .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
+    .help = try adding `extern crate rustc_driver;` at the top level of this crate
+
+metadata_stable_crate_id_collision =
+    found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values.
+
+metadata_std_required =
+    `std` is required by `{$current_crate}` because it does not declare `#![no_std]`
 
 metadata_symbol_conflicts_current =
     the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
@@ -209,80 +253,36 @@
 metadata_symbol_conflicts_others =
     found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two.
 
-metadata_stable_crate_id_collision =
-    found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values.
-
-metadata_dl_error =
-    {$err}
-
-metadata_newer_crate_version =
-    found possibly newer version of crate `{$crate_name}`{$add_info}
-    .note = perhaps that crate needs to be recompiled?
-
-metadata_found_crate_versions =
-    the following crate versions were found:{$found_crates}
-
-metadata_no_crate_with_triple =
-    couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info}
-
-metadata_found_staticlib =
-    found staticlib `{$crate_name}` instead of rlib or dylib{$add_info}
-    .help = please recompile that crate using --crate-type lib
-
-metadata_incompatible_rustc =
-    found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
-    .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
-
-metadata_invalid_meta_files =
-    found invalid metadata files for crate `{$crate_name}`{$add_info}
-
-metadata_cannot_find_crate =
-    can't find crate for `{$crate_name}`{$add_info}
-
-metadata_no_dylib_plugin =
-    plugin `{$crate_name}` only found in rlib format, but must be available in dylib format
+metadata_target_no_std_support =
+    the `{$locator_triple}` target may not support the standard library
 
 metadata_target_not_installed =
     the `{$locator_triple}` target may not be installed
 
-metadata_target_no_std_support =
-    the `{$locator_triple}` target may not support the standard library
+metadata_two_panic_runtimes =
+    cannot link together two panic runtimes: {$prev_name} and {$cur_name}
 
-metadata_consider_downloading_target =
-    consider downloading the target with `rustup target add {$locator_triple}`
-
-metadata_std_required =
-    `std` is required by `{$current_crate}` because it does not declare `#![no_std]`
-
-metadata_consider_building_std =
-    consider building the standard library from source with `cargo build -Zbuild-std`
-
-metadata_compiler_missing_profiler =
-    the compiler may have been built without the profiler runtime
-
-metadata_install_missing_components =
-    maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
-
-metadata_cant_find_crate =
-    can't find crate
-
-metadata_crate_location_unknown_type =
-    extern location for {$crate_name} is of an unknown type: {$path}
-
-metadata_lib_filename_form =
-    file name should be lib*.rlib or {$dll_prefix}*{$dll_suffix}
-
-metadata_multiple_import_name_type =
-    multiple `import_name_type` arguments in a single `#[link]` attribute
-
-metadata_import_name_type_form =
-    import name type must be of the form `import_name_type = "string"`
-
-metadata_import_name_type_x86 =
-    import name type is only supported on x86
+metadata_unexpected_link_arg =
+    unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
 
 metadata_unknown_import_name_type =
     unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated
 
-metadata_import_name_type_raw =
-    import name type can only be used with link kind `raw-dylib`
+metadata_unknown_link_kind =
+    unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib
+    .label = unknown link kind
+
+metadata_unknown_link_modifier =
+    unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
+
+metadata_unsupported_abi =
+    ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
+
+metadata_unsupported_abi_i686 =
+    ABI not supported by `#[link(kind = "raw-dylib")]` on i686
+
+metadata_wasm_import_form =
+    wasm import module must be of the form `wasm_import_module = "string"`
+
+metadata_whole_archive_needs_static =
+    linking modifier `whole-archive` is only compatible with `static` linking kind
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index cc4e60c..731bbb1 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -851,7 +851,7 @@ fn get_explicit_item_bounds(
         } else {
             tcx.arena.alloc_from_iter(lazy.decode((self, tcx)))
         };
-        ty::EarlyBinder(&*output)
+        ty::EarlyBinder::new(&*output)
     }
 
     fn get_variant(
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index f067bca..e3a0ce3 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1727,7 +1727,7 @@ fn encode_info_for_closure(&mut self, def_id: LocalDefId) {
             ty::Closure(_, substs) => {
                 let constness = self.tcx.constness(def_id.to_def_id());
                 self.tables.constness.set_some(def_id.to_def_id().index, constness);
-                record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig()));
+                record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::new(substs.as_closure().sig()));
             }
 
             _ => bug!("closure that is neither generator nor closure"),
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 64d511c..3d581da 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -1,45 +1,45 @@
-middle_drop_check_overflow =
-    overflow while adding drop-check rules for {$ty}
-    .note = overflowed on {$overflow_ty}
-
-middle_opaque_hidden_type_mismatch =
-    concrete type differs from previous defining opaque type use
-    .label = expected `{$self_ty}`, got `{$other_ty}`
+middle_cannot_be_normalized =
+    unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
 
 middle_conflict_types =
     this expression supplies two conflicting concrete types for the same opaque type
 
-middle_previous_use_here =
-    previous use here
+middle_const_eval_non_int =
+    constant evaluation of enum discriminant resulted in non-integer
+
+middle_const_not_used_in_type_alias =
+    const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+
+middle_cycle =
+    a cycle occurred during layout computation
+
+middle_drop_check_overflow =
+    overflow while adding drop-check rules for {$ty}
+    .note = overflowed on {$overflow_ty}
 
 middle_limit_invalid =
     `limit` must be a non-negative integer
     .label = {$error_str}
 
+middle_opaque_hidden_type_mismatch =
+    concrete type differs from previous defining opaque type use
+    .label = expected `{$self_ty}`, got `{$other_ty}`
+
+middle_previous_use_here =
+    previous use here
+
 middle_recursion_limit_reached =
     reached the recursion limit finding the struct tail for `{$ty}`
     .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]`
 
-middle_const_eval_non_int =
-    constant evaluation of enum discriminant resulted in non-integer
+middle_requires_lang_item = requires `{$name}` lang_item
+
+middle_strict_coherence_needs_negative_coherence =
+    to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
+    .label = due to this attribute
 
 middle_unknown_layout =
     the type `{$ty}` has an unknown layout
 
 middle_values_too_big =
     values of the type `{$ty}` are too big for the current architecture
-
-middle_cannot_be_normalized =
-    unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
-
-middle_cycle =
-    a cycle occurred during layout computation
-
-middle_strict_coherence_needs_negative_coherence =
-    to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
-    .label = due to this attribute
-
-middle_requires_lang_item = requires `{$name}` lang_item
-
-middle_const_not_used_in_type_alias =
-    const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 5c71910..34e47de 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -476,7 +476,7 @@ pub fn return_ty(&self) -> Ty<'tcx> {
     /// Returns the return type; it always return first element from `local_decls` array.
     #[inline]
     pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
-        ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty)
+        ty::EarlyBinder::new(self.local_decls[RETURN_PLACE].ty)
     }
 
     /// Gets the location of the terminator for the given block.
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index ff54ec5..f31b343 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -334,10 +334,7 @@ pub fn size_estimate(&self) -> usize {
     }
 
     pub fn modify_size_estimate(&mut self, delta: usize) {
-        assert!(self.size_estimate.is_some());
-        if let Some(size_estimate) = self.size_estimate {
-            self.size_estimate = Some(size_estimate + delta);
-        }
+        *self.size_estimate.as_mut().unwrap() += delta;
     }
 
     pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool {
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 21faf19..6d6d71b 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -603,7 +603,11 @@ pub enum TerminatorKind<'tcx> {
     /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
     /// > the place or one of its "parents" occurred more recently than a move out of it. This does not
     /// > consider indirect assignments.
-    Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction },
+    ///
+    /// The `replace` flag indicates whether this terminator was created as part of an assignment.
+    /// This should only be used for diagnostic purposes, and does not have any operational
+    /// meaning.
+    Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool },
 
     /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
     /// the referred to function. The operand types must match the argument types of the function.
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 2c6126c..561ef37 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -105,7 +105,7 @@ pub struct Terminator<'tcx> {
     pub kind: TerminatorKind<'tcx>,
 }
 
-pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a;
+pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
 pub type SuccessorsMut<'a> =
     iter::Chain<std::option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>;
 
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
index 7d247ee..99ead14 100644
--- a/compiler/rustc_middle/src/mir/traversal.rs
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -149,7 +149,7 @@ fn traverse_successor(&mut self) {
         //      B     C
         //      |     |
         //      |     |
-        //      D     |
+        //      |     D
         //       \   /
         //        \ /
         //         E
@@ -159,26 +159,26 @@ fn traverse_successor(&mut self) {
         //
         // When the first call to `traverse_successor` happens, the following happens:
         //
-        //     [(B, [D]),  // `B` taken from the successors of `A`, pushed to the
-        //                 // top of the stack along with the successors of `B`
-        //      (A, [C])]
+        //     [(C, [D]),  // `C` taken from the successors of `A`, pushed to the
+        //                 // top of the stack along with the successors of `C`
+        //      (A, [B])]
         //
-        //     [(D, [E]),  // `D` taken from successors of `B`, pushed to stack
-        //      (B, []),
-        //      (A, [C])]
+        //     [(D, [E]),  // `D` taken from successors of `C`, pushed to stack
+        //      (C, []),
+        //      (A, [B])]
         //
         //     [(E, []),   // `E` taken from successors of `D`, pushed to stack
         //      (D, []),
-        //      (B, []),
-        //      (A, [C])]
+        //      (C, []),
+        //      (A, [B])]
         //
         // Now that the top of the stack has no successors we can traverse, each item will
-        // be popped off during iteration until we get back to `A`. This yields [E, D, B].
+        // be popped off during iteration until we get back to `A`. This yields [E, D, C].
         //
-        // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but
+        // When we yield `C` and call `traverse_successor`, we push `B` to the stack, but
         // since we've already visited `E`, that child isn't added to the stack. The last
-        // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A]
-        while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next() {
+        // two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A]
+        while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next_back() {
             if self.visited.insert(bb) {
                 if let Some(term) = &self.basic_blocks[bb].terminator {
                     self.visit_stack.push((bb, term.successors()));
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 596dd80..942654b 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -504,6 +504,7 @@ fn super_terminator(&mut self,
                         place,
                         target: _,
                         unwind: _,
+                        replace: _,
                     } => {
                         self.visit_place(
                             place,
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index c4f8718..eae5a28 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -95,8 +95,6 @@ pub fn new(value: T) -> Self {
 #[derive(Copy, Clone, Debug, HashStable, PartialEq, Eq)]
 pub struct NoSolution;
 
-pub type Fallible<T> = Result<T, NoSolution>;
-
 impl<'tcx> From<TypeError<'tcx>> for NoSolution {
     fn from(_: TypeError<'tcx>) -> NoSolution {
         NoSolution
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 7c5c030..2b99fca 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -573,7 +573,7 @@ pub fn destructor(self, tcx: TyCtxt<'tcx>) -> Option<Destructor> {
     /// Due to normalization being eager, this applies even if
     /// the associated type is behind a pointer (e.g., issue #31299).
     pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
-        ty::EarlyBinder(tcx.adt_sized_constraint(self.did()))
+        ty::EarlyBinder::new(tcx.adt_sized_constraint(self.did()))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 1a4bd14..5fcbc4a 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -254,5 +254,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBind
             "`const_param_default` expected a generic parameter with a constant"
         ),
     };
-    ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id))
+    ty::EarlyBinder::new(Const::from_anon_const(tcx, default_def_id))
 }
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index b0ffe78..b27ee8c 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -343,7 +343,7 @@ pub fn instantiate_own(
         substs: SubstsRef<'tcx>,
     ) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
     {
-        EarlyBinder(self.predicates).subst_iter_copied(tcx, substs)
+        EarlyBinder::new(self.predicates).subst_iter_copied(tcx, substs)
     }
 
     #[instrument(level = "debug", skip(self, tcx))]
@@ -358,7 +358,7 @@ fn instantiate_into(
         }
         instantiated
             .predicates
-            .extend(self.predicates.iter().map(|(p, _)| EarlyBinder(*p).subst(tcx, substs)));
+            .extend(self.predicates.iter().map(|(p, _)| EarlyBinder::new(*p).subst(tcx, substs)));
         instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp));
     }
 
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
index ac42d6e..b3cc27e 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -158,7 +158,7 @@ pub fn subst(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Self {
     fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> {
         match self {
             Self::ConstIsZero(c) => {
-                let c = ty::EarlyBinder(c).subst(tcx, substs);
+                let c = ty::EarlyBinder::new(c).subst(tcx, substs);
                 let pred = match c.kind().try_to_target_usize(tcx) {
                     Some(0) => Self::True,
                     Some(1..) => Self::False,
@@ -167,7 +167,7 @@ fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Sel
                 Some(pred)
             }
             Self::GenericType(t) => {
-                Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx))
+                Some(ty::EarlyBinder::new(t).subst(tcx, substs).inhabited_predicate(tcx))
             }
             Self::And(&[a, b]) => match a.subst_opt(tcx, substs) {
                 None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index a8d0dca..4b2c7e8 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -53,7 +53,6 @@
 use rustc_span::{ExpnId, ExpnKind, Span};
 use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
 pub use rustc_target::abi::{ReprFlags, ReprOptions};
-use rustc_type_ir::WithCachedTypeInfo;
 pub use subst::*;
 pub use vtable::*;
 
@@ -145,6 +144,7 @@
 mod parameterized;
 mod rvalue_scopes;
 mod structural_impls;
+#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
 mod sty;
 mod typeck_results;
 
@@ -764,7 +764,7 @@ pub fn subst_supertrait(
         let shifted_pred =
             tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder());
         // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1>
-        let new = EarlyBinder(shifted_pred).subst(tcx, trait_ref.skip_binder().substs);
+        let new = EarlyBinder::new(shifted_pred).subst(tcx, trait_ref.skip_binder().substs);
         // 3) ['x] + ['b] -> ['x, 'b]
         let bound_vars =
             tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars));
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 64e7480..2de0a3f 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -123,7 +123,7 @@ fn default_print_def_path(
                         impl_trait_ref.map(|i| i.subst(self.tcx(), substs)),
                     )
                 } else {
-                    (self_ty.0, impl_trait_ref.map(|i| i.0))
+                    (self_ty.subst_identity(), impl_trait_ref.map(|i| i.subst_identity()))
                 };
                 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
             }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index a064174..d6c88ea 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -700,7 +700,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                     if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) }
                 }
             }
-            ty::Error(_) => p!("[type error]"),
+            ty::Error(_) => p!("{{type error}}"),
             ty::Param(ref param_ty) => p!(print(param_ty)),
             ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
                 ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?,
@@ -1379,8 +1379,8 @@ macro_rules! print_underscore {
             },
             // FIXME(generic_const_exprs):
             // write out some legible representation of an abstract const?
-            ty::ConstKind::Expr(_) => p!("[const expr]"),
-            ty::ConstKind::Error(_) => p!("[const error]"),
+            ty::ConstKind::Expr(_) => p!("{{const expr}}"),
+            ty::ConstKind::Error(_) => p!("{{const error}}"),
         };
         Ok(self)
     }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index e6d51c4..82f79a0 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -568,7 +568,7 @@ pub fn state_tys(
         let layout = tcx.generator_layout(def_id).unwrap();
         layout.variant_fields.iter().map(move |variant| {
             variant.iter().map(move |field| {
-                ty::EarlyBinder(layout.field_tys[*field].ty).subst(tcx, self.substs)
+                ty::EarlyBinder::new(layout.field_tys[*field].ty).subst(tcx, self.substs)
             })
         })
     }
@@ -2366,7 +2366,7 @@ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
 
             ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)),
 
-            ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(),
+            ty::Adt(def, _substs) => def.sized_constraint(tcx).skip_binder().is_empty(),
 
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
 
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 43f9563..8691a30 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -538,13 +538,17 @@ fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFl
 /// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder).
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[derive(Encodable, Decodable, HashStable)]
-pub struct EarlyBinder<T>(pub T);
+pub struct EarlyBinder<T>(T);
 
 /// For early binders, you should first call `subst` before using any visitors.
 impl<'tcx, T> !TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
 impl<'tcx, T> !TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {}
 
 impl<T> EarlyBinder<T> {
+    pub fn new(inner: T) -> EarlyBinder<T> {
+        EarlyBinder(inner)
+    }
+
     pub fn as_ref(&self) -> EarlyBinder<&T> {
         EarlyBinder(&self.0)
     }
@@ -582,6 +586,9 @@ pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
     /// arguments of an `FnSig`). Otherwise, consider using
     /// [`subst_identity`](EarlyBinder::subst_identity).
     ///
+    /// To skip the binder on `x: &EarlyBinder<T>` to obtain `&T`, leverage
+    /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`.
+    ///
     /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is
     /// the analogous operation on [`super::Binder`].
     pub fn skip_binder(self) -> T {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index ba05135..dade50d 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -709,7 +709,7 @@ pub fn generator_hidden_types(
             .as_ref()
             .map_or_else(|| [].iter(), |l| l.field_tys.iter())
             .filter(|decl| !decl.ignore_for_traits)
-            .map(|decl| ty::EarlyBinder(decl.ty))
+            .map(|decl| ty::EarlyBinder::new(decl.ty))
     }
 
     /// Normalizes all opaque types in the given value, replacing them
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index c62c33d..58374f6 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -96,13 +96,13 @@ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
 
 impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
-        ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle))
+        ty::EarlyBinder::new(Ty::from_cycle_error(tcx, cycle))
     }
 }
 
 impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
-        ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle))
+        ty::EarlyBinder::new(ty::Binder::from_cycle_error(tcx, cycle))
     }
 }
 
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 0282492..cb265cf 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -1,62 +1,40 @@
-mir_build_unconditional_recursion = function cannot return without recursing
-    .label = cannot return without recursing
-    .help = a `loop` may express intention better if this is on purpose
+mir_build_adt_defined_here = `{$ty}` defined here
 
-mir_build_unconditional_recursion_call_site_label = recursive call site
+mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable
 
-mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
-    call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
-    .note = consult the function's documentation for information on how to avoid undefined behavior
-    .label = call to unsafe function
+mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
 
-mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
-    call to unsafe function is unsafe and requires unsafe block (error E0133)
-    .note = consult the function's documentation for information on how to avoid undefined behavior
-    .label = call to unsafe function
+mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
 
-mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
-    use of inline assembly is unsafe and requires unsafe block (error E0133)
-    .note = inline assembly is entirely unchecked and can cause undefined behavior
-    .label = use of inline assembly
+mir_build_bindings_with_variant_name =
+    pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
+    .suggestion = to match on the variant, qualify the path
 
-mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
-    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
-    block (error E0133)
-    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
-    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_build_borrow = value is borrowed by `{$name}` here
 
-mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
-    use of mutable static is unsafe and requires unsafe block (error E0133)
-    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-    .label = use of mutable static
-
-mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
-    use of extern static is unsafe and requires unsafe block (error E0133)
-    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-    .label = use of extern static
-
-mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
-    dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-    .label = dereference of raw pointer
-
-mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
-    access to union field is unsafe and requires unsafe block (error E0133)
-    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
-    .label = access to union field
-
-mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
-    mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
-    .note = mutating layout constrained fields cannot statically be checked for valid values
-    .label = mutation of layout constrained field
-
-mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
-    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+mir_build_borrow_of_layout_constrained_field_requires_unsafe =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
     .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
     .label = borrow of layout constrained field with interior mutability
 
-mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
-    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_borrow_of_moved_value = borrow of moved value
+    .label = value moved into `{$name}` here
+    .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
+    .value_borrowed_label = value borrowed here after move
+    .suggestion = borrow this binding in the pattern to avoid moving the value
+
+mir_build_call_to_fn_with_requires_unsafe =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
     .note = can only be called if the required target features are available
     .label = call to function with `#[target_feature]`
 
@@ -70,55 +48,24 @@
     .note = consult the function's documentation for information on how to avoid undefined behavior
     .label = call to unsafe function
 
-mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    call to unsafe function `{$function}` is unsafe and requires unsafe function or block
-    .note = consult the function's documentation for information on how to avoid undefined behavior
-    .label = call to unsafe function
-
 mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed =
     call to unsafe function is unsafe and requires unsafe function or block
     .note = consult the function's documentation for information on how to avoid undefined behavior
     .label = call to unsafe function
 
-mir_build_inline_assembly_requires_unsafe =
-    use of inline assembly is unsafe and requires unsafe block
-    .note = inline assembly is entirely unchecked and can cause undefined behavior
-    .label = use of inline assembly
+mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    call to unsafe function `{$function}` is unsafe and requires unsafe function or block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
 
-mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    use of inline assembly is unsafe and requires unsafe function or block
-    .note = inline assembly is entirely unchecked and can cause undefined behavior
-    .label = use of inline assembly
+mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
 
-mir_build_initializing_type_with_requires_unsafe =
-    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
-    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
-    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
 
-mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
-    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
-    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_build_const_pattern_depends_on_generic_parameter =
+    constant pattern depends on a generic parameter
 
-mir_build_mutable_static_requires_unsafe =
-    use of mutable static is unsafe and requires unsafe block
-    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-    .label = use of mutable static
-
-mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    use of mutable static is unsafe and requires unsafe function or block
-    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-    .label = use of mutable static
-
-mir_build_extern_static_requires_unsafe =
-    use of extern static is unsafe and requires unsafe block
-    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-    .label = use of extern static
-
-mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    use of extern static is unsafe and requires unsafe function or block
-    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-    .label = use of extern static
+mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
 
 mir_build_deref_raw_pointer_requires_unsafe =
     dereference of raw pointer is unsafe and requires unsafe block
@@ -130,117 +77,46 @@
     .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
     .label = dereference of raw pointer
 
-mir_build_union_field_requires_unsafe =
-    access to union field is unsafe and requires unsafe block
-    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
-    .label = access to union field
+mir_build_extern_static_requires_unsafe =
+    use of extern static is unsafe and requires unsafe block
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
 
-mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    access to union field is unsafe and requires unsafe function or block
-    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
-    .label = access to union field
+mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of extern static is unsafe and requires unsafe function or block
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
 
-mir_build_mutation_of_layout_constrained_field_requires_unsafe =
-    mutation of layout constrained field is unsafe and requires unsafe block
-    .note = mutating layout constrained fields cannot statically be checked for valid values
-    .label = mutation of layout constrained field
+mir_build_float_pattern = floating-point types cannot be used in patterns
 
-mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    mutation of layout constrained field is unsafe and requires unsafe function or block
-    .note = mutating layout constrained fields cannot statically be checked for valid values
-    .label = mutation of layout constrained field
+mir_build_indirect_structural_match =
+    to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
 
-mir_build_borrow_of_layout_constrained_field_requires_unsafe =
-    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
-    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
-    .label = borrow of layout constrained field with interior mutability
+mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
 
-mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
-    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
-    .label = borrow of layout constrained field with interior mutability
+mir_build_initializing_type_with_requires_unsafe =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
 
-mir_build_call_to_fn_with_requires_unsafe =
-    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
-    .note = can only be called if the required target features are available
-    .label = call to function with `#[target_feature]`
+mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
 
-mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
-    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
-    .note = can only be called if the required target features are available
-    .label = call to function with `#[target_feature]`
+mir_build_inline_assembly_requires_unsafe =
+    use of inline assembly is unsafe and requires unsafe block
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
 
-mir_build_unused_unsafe = unnecessary `unsafe` block
-    .label = unnecessary `unsafe` block
+mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of inline assembly is unsafe and requires unsafe function or block
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
 
-mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
-mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
+mir_build_interpreted_as_const = introduce a variable instead
 
-mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
-    .def_note = `{$peeled_ty}` defined here
-    .type_note = the matched value is of type `{$ty}`
-    .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
-    .reference_note = references are always considered inhabited
-    .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-    .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
-
-mir_build_static_in_pattern = statics cannot be referenced in patterns
-
-mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
-
-mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
-
-mir_build_non_const_path = runtime values cannot be referenced in patterns
-
-mir_build_unreachable_pattern = unreachable pattern
-    .label = unreachable pattern
-    .catchall_label = matches any value
-
-mir_build_const_pattern_depends_on_generic_parameter =
-    constant pattern depends on a generic parameter
-
-mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
-
-mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
-    lower range bound must be less than or equal to upper
-    .label = lower bound larger than upper bound
-    .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
-
-mir_build_literal_in_range_out_of_bounds =
-    literal out of range for `{$ty}`
-    .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`
-
-mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
-
-mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
-        [one] pattern
-        *[other] patterns
-    } in let chain
-    .note = {$count ->
-        [one] this pattern
-        *[other] these patterns
-    } will always match
-    .help = consider moving {$count ->
-        [one] it
-        *[other] them
-    } outside of the construct
-
-mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
-        [one] pattern
-        *[other] patterns
-    } in let chain
-    .note = {$count ->
-        [one] this pattern
-        *[other] these patterns
-    } will always match
-    .help = consider moving {$count ->
-        [one] it
-        *[other] them
-    } into the body
-
-mir_build_bindings_with_variant_name =
-    pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
-    .suggestion = to match on the variant, qualify the path
+mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
 
 mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
         [one] pattern
@@ -282,80 +158,97 @@
     } will always match, so the loop will never exit
     .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it
 
-mir_build_borrow_of_moved_value = borrow of moved value
-    .label = value moved into `{$name}` here
-    .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
-    .value_borrowed_label = value borrowed here after move
-    .suggestion = borrow this binding in the pattern to avoid moving the value
+mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
+        [one] pattern
+        *[other] patterns
+    } in let chain
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match
+    .help = consider moving {$count ->
+        [one] it
+        *[other] them
+    } outside of the construct
 
-mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
+mir_build_literal_in_range_out_of_bounds =
+    literal out of range for `{$ty}`
+    .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`
 
-mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable
+mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
+    lower range bound must be less than or equal to upper
+    .label = lower bound larger than upper bound
+    .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
 
-mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
+mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
 
-mir_build_moved_while_borrowed = cannot move out of value because it is borrowed
-
-mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here
-
-mir_build_borrow = value is borrowed by `{$name}` here
+mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 
 mir_build_moved = value is moved into `{$name}` here
 
-mir_build_union_pattern = cannot use unions in constant patterns
+mir_build_moved_while_borrowed = cannot move out of value because it is borrowed
 
-mir_build_type_not_structural =
-     to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
 
-mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
+mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here
 
-mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
+mir_build_mutable_static_requires_unsafe =
+    use of mutable static is unsafe and requires unsafe block
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
 
-mir_build_float_pattern = floating-point types cannot be used in patterns
+mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of mutable static is unsafe and requires unsafe function or block
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
 
-mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+mir_build_mutation_of_layout_constrained_field_requires_unsafe =
+    mutation of layout constrained field is unsafe and requires unsafe block
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
 
-mir_build_indirect_structural_match =
-    to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    mutation of layout constrained field is unsafe and requires unsafe function or block
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
 
-mir_build_nontrivial_structural_match =
-    to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
-
-mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
-
-mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
-    .range = ... with this range
-    .note = you likely meant to write mutually exclusive ranges
+mir_build_non_const_path = runtime values cannot be referenced in patterns
 
 mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
     .help = ensure that all variants are matched explicitly by adding the suggested match arms
     .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
 
-mir_build_uncovered = {$count ->
-        [1] pattern `{$witness_1}`
-        [2] patterns `{$witness_1}` and `{$witness_2}`
-        [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
-        *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
-    } not covered
+mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
+    .def_note = `{$peeled_ty}` defined here
+    .type_note = the matched value is of type `{$ty}`
+    .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
+    .reference_note = references are always considered inhabited
+    .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+    .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
-mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
+mir_build_nontrivial_structural_match =
+    to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+
+mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
+    .range = ... with this range
+    .note = you likely meant to write mutually exclusive ranges
 
 mir_build_pattern_not_covered = refutable pattern in {$origin}
     .pattern_ty = the matched value is of type `{$pattern_ty}`
 
-mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
 
-mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
 
-mir_build_adt_defined_here = `{$ty}` defined here
+mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
+    .attributes = no other attributes may be applied
+    .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
+    .missing_box = `#[rustc_box]` requires the `owned_box` lang item
 
-mir_build_variant_defined_here = not covered
+mir_build_static_in_pattern = statics cannot be referenced in patterns
 
-mir_build_interpreted_as_const = introduce a variable instead
+mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
 
-mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
 
 mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
         [one] variant that isn't
@@ -367,10 +260,117 @@
         *[other] variants that aren't
     } matched
 
-mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
+        [one] pattern
+        *[other] patterns
+    } in let chain
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match
+    .help = consider moving {$count ->
+        [one] it
+        *[other] them
+    } into the body
 
+mir_build_type_not_structural =
+     to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
 
-mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
-    .attributes = no other attributes may be applied
-    .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
-    .missing_box = `#[rustc_box]` requires the `owned_box` lang item
+mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+
+mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
+
+mir_build_unconditional_recursion = function cannot return without recursing
+    .label = cannot return without recursing
+    .help = a `loop` may express intention better if this is on purpose
+
+mir_build_unconditional_recursion_call_site_label = recursive call site
+
+mir_build_uncovered = {$count ->
+        [1] pattern `{$witness_1}`
+        [2] patterns `{$witness_1}` and `{$witness_2}`
+        [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
+        *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
+    } not covered
+
+mir_build_union_field_requires_unsafe =
+    access to union field is unsafe and requires unsafe block
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    access to union field is unsafe and requires unsafe function or block
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_union_pattern = cannot use unions in constant patterns
+
+mir_build_unreachable_pattern = unreachable pattern
+    .label = unreachable pattern
+    .catchall_label = matches any value
+
+mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
+    call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
+    call to unsafe function is unsafe and requires unsafe block (error E0133)
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
+    dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
+    use of extern static is unsafe and requires unsafe block (error E0133)
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
+    block (error E0133)
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
+    use of inline assembly is unsafe and requires unsafe block (error E0133)
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
+    use of mutable static is unsafe and requires unsafe block (error E0133)
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
+    mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
+    access to union field is unsafe and requires unsafe block (error E0133)
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
+
+mir_build_unused_unsafe = unnecessary `unsafe` block
+    .label = unnecessary `unsafe` block
+
+mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
+mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
+
+mir_build_variant_defined_here = not covered
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index b744227..ebf830c 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -57,6 +57,7 @@ pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>>
                     place: self.parse_place(args[0])?,
                     target: self.parse_block(args[1])?,
                     unwind: UnwindAction::Continue,
+                    replace: false,
                 })
             },
             @call("mir_call", args) => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index bcab4c0..3742d64 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -725,6 +725,7 @@ fn build_zero_repeat(
                         place: to_drop,
                         target: success,
                         unwind: UnwindAction::Continue,
+                        replace: false,
                     },
                 );
                 this.diverge_from(block);
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 7331f8e..7c0fbc6 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -91,7 +91,7 @@
 use rustc_middle::mir::*;
 use rustc_middle::thir::{Expr, LintLevel};
 
-use rustc_span::{DesugaringKind, Span, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
 
 #[derive(Debug)]
 pub struct Scopes<'tcx> {
@@ -371,6 +371,7 @@ fn link_blocks<'tcx>(
                         // The caller will handle this if needed.
                         unwind: UnwindAction::Terminate,
                         place: drop_data.0.local.into(),
+                        replace: false,
                     };
                     cfg.terminate(block, drop_data.0.source_info, terminator);
                 }
@@ -1128,9 +1129,6 @@ pub(crate) fn build_drop_and_replace(
         place: Place<'tcx>,
         value: Rvalue<'tcx>,
     ) -> BlockAnd<()> {
-        let span = self.tcx.with_stable_hashing_context(|hcx| {
-            span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx)
-        });
         let source_info = self.source_info(span);
 
         // create the new block for the assignment
@@ -1148,6 +1146,7 @@ pub(crate) fn build_drop_and_replace(
                 place,
                 target: assign,
                 unwind: UnwindAction::Cleanup(assign_unwind),
+                replace: true,
             },
         );
         self.diverge_from(block);
@@ -1261,6 +1260,7 @@ fn build_scope_drops<'tcx>(
                         place: local.into(),
                         target: next,
                         unwind: UnwindAction::Continue,
+                        replace: false,
                     },
                 );
                 block = next;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index c11a4f7..1e51cb9 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -491,8 +491,8 @@ fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>)
             AdtDefinedHere { adt_def_span, ty, variants }
         };
 
-        // Emit an extra note if the first uncovered witness is
-        // visibly uninhabited anywhere in the current crate.
+        // Emit an extra note if the first uncovered witness would be uninhabited
+        // if we disregard visibility.
         let witness_1_is_privately_uninhabited =
             if cx.tcx.features().exhaustive_patterns
                 && let Some(witness_1) = witnesses.get(0)
diff --git a/compiler/rustc_mir_dataflow/messages.ftl b/compiler/rustc_mir_dataflow/messages.ftl
index 9885415..5698367 100644
--- a/compiler/rustc_mir_dataflow/messages.ftl
+++ b/compiler/rustc_mir_dataflow/messages.ftl
@@ -1,11 +1,23 @@
+mir_dataflow_duplicate_values_for =
+    duplicate values for `{$name}`
+
 mir_dataflow_path_must_end_in_filename =
     path must end in a filename
 
-mir_dataflow_unknown_formatter =
-    unknown formatter
+mir_dataflow_peek_argument_not_a_local =
+    rustc_peek: argument was not a local
 
-mir_dataflow_duplicate_values_for =
-    duplicate values for `{$name}`
+mir_dataflow_peek_argument_untracked =
+    rustc_peek: argument untracked
+
+mir_dataflow_peek_bit_not_set =
+    rustc_peek: bit not set
+
+mir_dataflow_peek_must_be_not_temporary =
+    dataflow::sanity_check cannot feed a non-temp to rustc_peek
+
+mir_dataflow_peek_must_be_place_or_ref_place =
+    rustc_peek: argument expression must be either `place` or `&place`
 
 mir_dataflow_requires_an_argument =
     `{$name}` requires an argument
@@ -13,17 +25,5 @@
 mir_dataflow_stop_after_dataflow_ended_compilation =
     stop_after_dataflow ended compilation
 
-mir_dataflow_peek_must_be_place_or_ref_place =
-    rustc_peek: argument expression must be either `place` or `&place`
-
-mir_dataflow_peek_must_be_not_temporary =
-    dataflow::sanity_check cannot feed a non-temp to rustc_peek
-
-mir_dataflow_peek_bit_not_set =
-    rustc_peek: bit not set
-
-mir_dataflow_peek_argument_not_a_local =
-    rustc_peek: argument was not a local
-
-mir_dataflow_peek_argument_untracked =
-    rustc_peek: argument untracked
+mir_dataflow_unknown_formatter =
+    unknown formatter
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 1889507..d615c83 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -237,6 +237,7 @@ pub fn elaborate_drop(&mut self, bb: BasicBlock) {
                         place: self.place,
                         target: self.succ,
                         unwind: self.unwind.into_action(),
+                        replace: false,
                     },
                 );
             }
@@ -719,6 +720,7 @@ fn drop_loop(
                 place: tcx.mk_place_deref(ptr),
                 target: loop_block,
                 unwind: unwind.into_action(),
+                replace: false,
             },
         );
 
@@ -963,8 +965,12 @@ fn unelaborated_free_block(
     }
 
     fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
-        let block =
-            TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_action() };
+        let block = TerminatorKind::Drop {
+            place: self.place,
+            target,
+            unwind: unwind.into_action(),
+            replace: false,
+        };
         self.new_block(unwind, block)
     }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index c8fe1af..ba328e7 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -479,7 +479,7 @@ fn join_state_into_successors_of<'tcx, A>(
             Goto { target } => propagate(target, exit_state),
 
             Assert { target, unwind, expected: _, msg: _, cond: _ }
-            | Drop { target, unwind, place: _ }
+            | Drop { target, unwind, place: _, replace: _ }
             | FalseUnwind { real_target: target, unwind } => {
                 if let UnwindAction::Cleanup(unwind) = unwind {
                     propagate(unwind, exit_state);
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index 8c85cb5f..b13429d 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -1,3 +1,8 @@
+mir_transform_arithmetic_overflow = this arithmetic operation will overflow
+mir_transform_call_to_unsafe_label = call to unsafe function
+mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
+mir_transform_const_defined_here = `const` item defined here
+
 mir_transform_const_modify = attempting to modify a `const` item
     .note = each usage of a `const` item creates a new temporary; the original `const` item will not be modified
 
@@ -6,50 +11,10 @@
     .note2 = the mutable reference will refer to this temporary, not the original `const` item
     .note3 = mutable reference created due to call to this method
 
-mir_transform_const_defined_here = `const` item defined here
-
-mir_transform_unaligned_packed_ref = reference to packed field is unaligned
-    .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
-    .note_ub = 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)
-
-mir_transform_unused_unsafe = unnecessary `unsafe` block
-    .label = because it's nested under this `unsafe` block
-
-mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
-    [true] function or block
-    *[false] block
-    }
-    .not_inherited = items do not inherit unsafety from separate enclosing items
-
-mir_transform_call_to_unsafe_label = call to unsafe function
-mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
-mir_transform_use_of_asm_label = use of inline assembly
-mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
-mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
-mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
 mir_transform_const_ptr2int_label = cast of pointer to int
 mir_transform_const_ptr2int_note = casting pointers to integers in constants
-mir_transform_use_of_static_mut_label = use of mutable static
-mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-mir_transform_use_of_extern_static_label = use of extern static
-mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 mir_transform_deref_ptr_label = dereference of raw pointer
 mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-mir_transform_union_access_label = access to union field
-mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
-mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
-mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
-mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
-mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
-mir_transform_target_feature_call_label = call to function with `#[target_feature]`
-mir_transform_target_feature_call_note = can only be called if the required target features are available
-
-mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
-
-mir_transform_arithmetic_overflow = this arithmetic operation will overflow
-mir_transform_operation_will_panic = this operation will panic at runtime
-
 mir_transform_ffi_unwind_call = call to {$foreign ->
     [true] foreign function
     *[false] function pointer
@@ -58,9 +23,45 @@
 mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
     .suggestion = cast `{$ident}` to obtain a function pointer
 
+mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
 mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
     .label = the value is held across this suspend point
     .note = {$reason}
     .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
 
+mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
+mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
+mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
+mir_transform_operation_will_panic = this operation will panic at runtime
+
+mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
+    [true] function or block
+    *[false] block
+    }
+    .not_inherited = items do not inherit unsafety from separate enclosing items
+
 mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
+
+mir_transform_target_feature_call_label = call to function with `#[target_feature]`
+mir_transform_target_feature_call_note = can only be called if the required target features are available
+
+mir_transform_unaligned_packed_ref = reference to packed field is unaligned
+    .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+    .note_ub = 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)
+
+mir_transform_union_access_label = access to union field
+mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
+
+mir_transform_unused_unsafe = unnecessary `unsafe` block
+    .label = because it's nested under this `unsafe` block
+
+mir_transform_use_of_asm_label = use of inline assembly
+mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
+mir_transform_use_of_extern_static_label = use of extern static
+mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+mir_transform_use_of_static_mut_label = use of mutable static
+mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index b29ffcc..ef2a0c7 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -80,7 +80,7 @@ fn add_move_for_packed_drop<'tcx>(
     is_cleanup: bool,
 ) {
     debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
-    let TerminatorKind::Drop { ref place, target, unwind } = terminator.kind else {
+    let TerminatorKind::Drop { ref place, target, unwind, replace } = terminator.kind else {
         unreachable!();
     };
 
@@ -98,6 +98,11 @@ fn add_move_for_packed_drop<'tcx>(
     patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
     patch.patch_terminator(
         loc.block,
-        TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind },
+        TerminatorKind::Drop {
+            place: Place::from(temp),
+            target: storage_dead_block,
+            unwind,
+            replace,
+        },
     );
 }
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index d60184e..1fe8ea0 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -75,6 +75,14 @@ struct PointerFinder<'tcx, 'a> {
 }
 
 impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> {
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+        if let Rvalue::AddressOf(..) = rvalue {
+            // Ignore dereferences inside of an AddressOf
+            return;
+        }
+        self.super_rvalue(rvalue, location);
+    }
+
     fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
         if let PlaceContext::NonUse(_) = context {
             return;
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 98e7a51..fda0e10 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -14,7 +14,7 @@
 use rustc_mir_dataflow::MoveDataParamEnv;
 use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits};
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
-use rustc_span::{DesugaringKind, Span};
+use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use std::fmt;
 
@@ -401,7 +401,7 @@ fn elaborate_drops(&mut self) {
             let terminator = data.terminator();
 
             match terminator.kind {
-                TerminatorKind::Drop { mut place, target, unwind } => {
+                TerminatorKind::Drop { mut place, target, unwind, replace } => {
                     if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) {
                         place = new_place;
                     }
@@ -434,10 +434,7 @@ fn elaborate_drops(&mut self) {
                             )
                         }
                         LookupResult::Parent(..) => {
-                            if !matches!(
-                                terminator.source_info.span.desugaring_kind(),
-                                Some(DesugaringKind::Replace),
-                            ) {
+                            if !replace {
                                 self.tcx.sess.delay_span_bug(
                                     terminator.source_info.span,
                                     format!("drop of untracked value {:?}", bb),
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 5989dbe..c045812 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -83,7 +83,7 @@ fn check_bound_args(
                         // If the inner type matches the type bound by `Pointer`
                         if inner_ty == bound_ty {
                             // Do a substitution using the parameters from the callsite
-                            let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref);
+                            let subst_ty = EarlyBinder::new(inner_ty).subst(self.tcx, substs_ref);
                             if let Some((fn_id, fn_substs)) =
                                 FunctionItemRefChecker::is_fn_ref(subst_ty)
                             {
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 891e446..89567ed 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1045,7 +1045,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
     for (block, block_data) in body.basic_blocks.iter_enumerated() {
         let (target, unwind, source_info) = match block_data.terminator() {
-            Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => {
+            Terminator {
+                source_info,
+                kind: TerminatorKind::Drop { place, target, unwind, replace: _ },
+            } => {
                 if let Some(local) = place.as_local() {
                     if local == SELF_ARG {
                         (target, unwind, source_info)
@@ -1304,6 +1307,7 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
         place: Place::from(SELF_ARG),
         target: return_block,
         unwind: UnwindAction::Continue,
+        replace: false,
     };
     let source_info = SourceInfo::outermost(body.span);
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 1748b1b..e27d48f 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -192,7 +192,7 @@ fn try_inlining(
         let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions(
             self.tcx,
             self.param_env,
-            ty::EarlyBinder(callee_body.clone()),
+            ty::EarlyBinder::new(callee_body.clone()),
         ) else {
             return Err("failed to normalize callee body");
         };
@@ -449,16 +449,16 @@ fn check_mir_body(
             checker.visit_basic_block_data(bb, blk);
 
             let term = blk.terminator();
-            if let TerminatorKind::Drop { ref place, target, unwind } = term.kind {
+            if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind {
                 work_list.push(target);
 
                 // If the place doesn't actually need dropping, treat it like a regular goto.
                 let ty = callsite
                     .callee
-                    .subst_mir(self.tcx, ty::EarlyBinder(&place.ty(callee_body, tcx).ty));
+                    .subst_mir(self.tcx, ty::EarlyBinder::new(&place.ty(callee_body, tcx).ty));
                 if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind {
-                        work_list.push(unwind);
-                    }
+                    work_list.push(unwind);
+                }
             } else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
                 && matches!(term.kind, TerminatorKind::InlineAsm { .. })
             {
@@ -790,7 +790,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 // If the place doesn't actually need dropping, treat it like a regular goto.
                 let ty = self
                     .instance
-                    .subst_mir(tcx, ty::EarlyBinder(&place.ty(self.callee_body, tcx).ty));
+                    .subst_mir(tcx, ty::EarlyBinder::new(&place.ty(self.callee_body, tcx).ty));
                 if ty.needs_drop(tcx, self.param_env) {
                     self.cost += CALL_PENALTY;
                     if let UnwindAction::Cleanup(_) = unwind {
@@ -801,7 +801,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
             }
             TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
-                let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder(&f.literal.ty()));
+                let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::new(&f.literal.ty()));
                 self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
                     // Don't give intrinsics the extra penalty for calls
                     INSTR_COST
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 1ccf06f..00842e9 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -47,7 +47,7 @@ fn process<'tcx>(
             let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions(
                 tcx,
                 param_env,
-                ty::EarlyBinder(substs),
+                ty::EarlyBinder::new(substs),
             ) else {
                 trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping");
                 continue;
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 65864dc..54c138b 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -3,6 +3,7 @@
 #![deny(rustc::diagnostic_outside_of_impl)]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
+#![feature(is_sorted)]
 #![feature(let_chains)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
@@ -84,6 +85,7 @@
 mod multiple_return_terminators;
 mod normalize_array_len;
 mod nrvo;
+mod prettify;
 mod ref_prop;
 mod remove_noop_landing_pads;
 mod remove_storage_markers;
@@ -581,6 +583,9 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &large_enums::EnumSizeOpt { discrepancy: 128 },
             // Some cleanup necessary at least for LLVM and potentially other codegen backends.
             &add_call_guards::CriticalCallEdges,
+            // Cleanup for human readability, off by default.
+            &prettify::ReorderBasicBlocks,
+            &prettify::ReorderLocals,
             // Dump the end result for testing and debugging purposes.
             &dump_mir::Marker("PreCodegen"),
         ],
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 59942dc..6eb4849 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -41,7 +41,7 @@
 
 impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.mir_opt_level() >= 3
+        sess.mir_opt_level() >= 1
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -62,7 +62,12 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                     ..
                 } if targets.iter().len() == 1 => {
                     let (value, target) = targets.iter().next().unwrap();
-                    if target == targets.otherwise() {
+                    // We require that this block and the two possible target blocks all be
+                    // distinct.
+                    if target == targets.otherwise()
+                        || bb_idx == target
+                        || bb_idx == targets.otherwise()
+                    {
                         continue;
                     }
                     (discr, value, target, targets.otherwise())
diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs
new file mode 100644
index 0000000..6f46974
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/prettify.rs
@@ -0,0 +1,150 @@
+//! These two passes provide no value to the compiler, so are off at every level.
+//!
+//! However, they can be enabled on the command line
+//! (`-Zmir-enable-passes=+ReorderBasicBlocks,+ReorderLocals`)
+//! to make the MIR easier to read for humans.
+
+use crate::MirPass;
+use rustc_index::{bit_set::BitSet, IndexSlice, IndexVec};
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
+
+/// Rearranges the basic blocks into a *reverse post-order*.
+///
+/// Thus after this pass, all the successors of a block are later than it in the
+/// `IndexVec`, unless that successor is a back-edge (such as from a loop).
+pub struct ReorderBasicBlocks;
+
+impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
+    fn is_enabled(&self, _session: &Session) -> bool {
+        false
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let rpo: IndexVec<BasicBlock, BasicBlock> =
+            body.basic_blocks.postorder().iter().copied().rev().collect();
+        if rpo.iter().is_sorted() {
+            return;
+        }
+
+        let mut updater = BasicBlockUpdater { map: rpo.invert_bijective_mapping(), tcx };
+        debug_assert_eq!(updater.map[START_BLOCK], START_BLOCK);
+        updater.visit_body(body);
+
+        permute(body.basic_blocks.as_mut(), &updater.map);
+    }
+}
+
+/// Rearranges the locals into *use* order.
+///
+/// Thus after this pass, a local with a smaller [`Location`] where it was first
+/// assigned or referenced will have a smaller number.
+///
+/// (Does not reorder arguments nor the [`RETURN_PLACE`].)
+pub struct ReorderLocals;
+
+impl<'tcx> MirPass<'tcx> for ReorderLocals {
+    fn is_enabled(&self, _session: &Session) -> bool {
+        false
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let mut finder =
+            LocalFinder { map: IndexVec::new(), seen: BitSet::new_empty(body.local_decls.len()) };
+
+        // We can't reorder the return place or the arguments
+        for local in (0..=body.arg_count).map(Local::from_usize) {
+            finder.track(local);
+        }
+
+        for (bb, bbd) in body.basic_blocks.iter_enumerated() {
+            finder.visit_basic_block_data(bb, bbd);
+        }
+
+        // track everything in case there are some locals that we never saw,
+        // such as in non-block things like debug info or in non-uses.
+        for local in body.local_decls.indices() {
+            finder.track(local);
+        }
+
+        if finder.map.iter().is_sorted() {
+            return;
+        }
+
+        let mut updater = LocalUpdater { map: finder.map.invert_bijective_mapping(), tcx };
+
+        for local in (0..=body.arg_count).map(Local::from_usize) {
+            debug_assert_eq!(updater.map[local], local);
+        }
+
+        updater.visit_body_preserves_cfg(body);
+
+        permute(&mut body.local_decls, &updater.map);
+    }
+}
+
+fn permute<I: rustc_index::Idx + Ord, T>(data: &mut IndexVec<I, T>, map: &IndexSlice<I, I>) {
+    // FIXME: It would be nice to have a less-awkward way to apply permutations,
+    // but I don't know one that exists.  `sort_by_cached_key` has logic for it
+    // internally, but not in a way that we're allowed to use here.
+    let mut enumerated: Vec<_> = std::mem::take(data).into_iter_enumerated().collect();
+    enumerated.sort_by_key(|p| map[p.0]);
+    *data = enumerated.into_iter().map(|p| p.1).collect();
+}
+
+struct BasicBlockUpdater<'tcx> {
+    map: IndexVec<BasicBlock, BasicBlock>,
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for BasicBlockUpdater<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, _location: Location) {
+        for succ in terminator.successors_mut() {
+            *succ = self.map[*succ];
+        }
+    }
+}
+
+struct LocalFinder {
+    map: IndexVec<Local, Local>,
+    seen: BitSet<Local>,
+}
+
+impl LocalFinder {
+    fn track(&mut self, l: Local) {
+        if self.seen.insert(l) {
+            self.map.push(l);
+        }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for LocalFinder {
+    fn visit_local(&mut self, l: Local, context: PlaceContext, _location: Location) {
+        // Exclude non-uses to keep `StorageLive` from controlling where we put
+        // a `Local`, since it might not actually be assigned until much later.
+        if context.is_use() {
+            self.track(l);
+        }
+    }
+}
+
+struct LocalUpdater<'tcx> {
+    pub map: IndexVec<Local, Local>,
+    pub tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
+        *l = self.map[*l];
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 7c47d88..522220f 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -69,7 +69,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
             // of this function. Is this intentional?
             if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) {
                 let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap();
-                let body = EarlyBinder(body.clone()).subst(tcx, substs);
+                let body = EarlyBinder::new(body.clone()).subst(tcx, substs);
                 debug!("make_shim({:?}) = {:?}", instance, body);
                 return body;
             }
@@ -544,6 +544,7 @@ fn clone_fields<I>(
                     place: dest_field,
                     target: unwind,
                     unwind: UnwindAction::Terminate,
+                    replace: false,
                 },
                 true,
             );
@@ -643,8 +644,11 @@ fn build_call_shim<'tcx>(
     let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig));
 
     assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
-    let mut sig =
-        if let Some(sig_substs) = sig_substs { sig.subst(tcx, &sig_substs) } else { sig.0 };
+    let mut sig = if let Some(sig_substs) = sig_substs {
+        sig.subst(tcx, &sig_substs)
+    } else {
+        sig.skip_binder()
+    };
 
     if let CallKind::Indirect(fnty) = call_kind {
         // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
@@ -800,6 +804,7 @@ fn build_call_shim<'tcx>(
                 place: rcvr_place(),
                 target: BasicBlock::new(2),
                 unwind: UnwindAction::Continue,
+                replace: false,
             },
             false,
         );
@@ -815,6 +820,7 @@ fn build_call_shim<'tcx>(
                 place: rcvr_place(),
                 target: BasicBlock::new(4),
                 unwind: UnwindAction::Terminate,
+                replace: false,
             },
             true,
         );
diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl
index 6cea6a6..fdd47e6 100644
--- a/compiler/rustc_monomorphize/messages.ftl
+++ b/compiler/rustc_monomorphize/messages.ftl
@@ -1,32 +1,32 @@
-monomorphize_recursion_limit =
-    reached the recursion limit while instantiating `{$shrunk}`
-    .note = `{$def_path_str}` defined here
-
-monomorphize_written_to_path = the full type name has been written to '{$path}'
-
-monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
-
 monomorphize_consider_type_length_limit =
     consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate
 
-monomorphize_fatal_error = {$error_message}
-
-monomorphize_unknown_partition_strategy = unknown partitioning strategy
-
-monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
-
-monomorphize_unused_generic_params = item has unused generic parameters
-
-monomorphize_large_assignments =
-    moving {$size} bytes
-    .label = value moved from here
-    .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
 monomorphize_couldnt_dump_mono_stats =
     unexpected error occurred while dumping monomorphization stats: {$error}
 
 monomorphize_encountered_error_while_instantiating =
     the above error was encountered while instantiating `{$formatted_item}`
 
+monomorphize_fatal_error = {$error_message}
+
+monomorphize_large_assignments =
+    moving {$size} bytes
+    .label = value moved from here
+    .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+monomorphize_recursion_limit =
+    reached the recursion limit while instantiating `{$shrunk}`
+    .note = `{$def_path_str}` defined here
+
+monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
+
+monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
+
 monomorphize_unknown_cgu_collection_mode =
     unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
+
+monomorphize_unknown_partition_strategy = unknown partitioning strategy
+
+monomorphize_unused_generic_params = item has unused generic parameters
+
+monomorphize_written_to_path = the full type name has been written to '{$path}'
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 35b154b..8874aa7 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -677,7 +677,7 @@ pub fn monomorphize<T>(&self, value: T) -> T
         self.instance.subst_mir_and_normalize_erasing_regions(
             self.tcx,
             ty::ParamEnv::reveal_all(),
-            ty::EarlyBinder(value),
+            ty::EarlyBinder::new(value),
         )
     }
 }
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index 37b7f6b..603b3dd 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -1,3 +1,4 @@
+use std::cmp;
 use std::collections::hash_map::Entry;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -14,10 +15,7 @@
 
 use super::PartitioningCx;
 use crate::collector::InliningMap;
-use crate::partitioning::merging;
-use crate::partitioning::{
-    MonoItemPlacement, Partition, PostInliningPartitioning, PreInliningPartitioning,
-};
+use crate::partitioning::{MonoItemPlacement, Partition, PlacedRootMonoItems};
 
 pub struct DefaultPartitioning;
 
@@ -26,7 +24,7 @@ fn place_root_mono_items<I>(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
         mono_items: &mut I,
-    ) -> PreInliningPartitioning<'tcx>
+    ) -> PlacedRootMonoItems<'tcx>
     where
         I: Iterator<Item = MonoItem<'tcx>>,
     {
@@ -91,38 +89,120 @@ fn place_root_mono_items<I>(
             codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name));
         }
 
-        PreInliningPartitioning {
-            codegen_units: codegen_units.into_values().collect(),
-            roots,
-            internalization_candidates,
-        }
+        let codegen_units = codegen_units.into_values().collect();
+        PlacedRootMonoItems { codegen_units, roots, internalization_candidates }
     }
 
     fn merge_codegen_units(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        initial_partitioning: &mut PreInliningPartitioning<'tcx>,
+        codegen_units: &mut Vec<CodegenUnit<'tcx>>,
     ) {
-        merging::merge_codegen_units(cx, initial_partitioning);
+        assert!(cx.target_cgu_count >= 1);
+
+        // Note that at this point in time the `codegen_units` here may not be
+        // in a deterministic order (but we know they're deterministically the
+        // same set). We want this merging to produce a deterministic ordering
+        // of codegen units from the input.
+        //
+        // Due to basically how we've implemented the merging below (merge the
+        // two smallest into each other) we're sure to start off with a
+        // deterministic order (sorted by name). This'll mean that if two cgus
+        // have the same size the stable sort below will keep everything nice
+        // and deterministic.
+        codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
+
+        // This map keeps track of what got merged into what.
+        let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> =
+            codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect();
+
+        // Merge the two smallest codegen units until the target size is
+        // reached.
+        while codegen_units.len() > cx.target_cgu_count {
+            // Sort small cgus to the back
+            codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
+            let mut smallest = codegen_units.pop().unwrap();
+            let second_smallest = codegen_units.last_mut().unwrap();
+
+            // Move the mono-items from `smallest` to `second_smallest`
+            second_smallest.modify_size_estimate(smallest.size_estimate());
+            for (k, v) in smallest.items_mut().drain() {
+                second_smallest.items_mut().insert(k, v);
+            }
+
+            // Record that `second_smallest` now contains all the stuff that was
+            // in `smallest` before.
+            let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap();
+            cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names);
+
+            debug!(
+                "CodegenUnit {} merged into CodegenUnit {}",
+                smallest.name(),
+                second_smallest.name()
+            );
+        }
+
+        let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
+
+        if cx.tcx.sess.opts.incremental.is_some() {
+            // If we are doing incremental compilation, we want CGU names to
+            // reflect the path of the source level module they correspond to.
+            // For CGUs that contain the code of multiple modules because of the
+            // merging done above, we use a concatenation of the names of all
+            // contained CGUs.
+            let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents
+                .into_iter()
+                // This `filter` makes sure we only update the name of CGUs that
+                // were actually modified by merging.
+                .filter(|(_, cgu_contents)| cgu_contents.len() > 1)
+                .map(|(current_cgu_name, cgu_contents)| {
+                    let mut cgu_contents: Vec<&str> =
+                        cgu_contents.iter().map(|s| s.as_str()).collect();
+
+                    // Sort the names, so things are deterministic and easy to
+                    // predict. We are sorting primitive `&str`s here so we can
+                    // use unstable sort.
+                    cgu_contents.sort_unstable();
+
+                    (current_cgu_name, cgu_contents.join("--"))
+                })
+                .collect();
+
+            for cgu in codegen_units.iter_mut() {
+                if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) {
+                    if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names {
+                        cgu.set_name(Symbol::intern(&new_cgu_name));
+                    } else {
+                        // If we don't require CGU names to be human-readable,
+                        // we use a fixed length hash of the composite CGU name
+                        // instead.
+                        let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name);
+                        cgu.set_name(Symbol::intern(&new_cgu_name));
+                    }
+                }
+            }
+        } else {
+            // If we are compiling non-incrementally we just generate simple CGU
+            // names containing an index.
+            for (index, cgu) in codegen_units.iter_mut().enumerate() {
+                let numbered_codegen_unit_name =
+                    cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index));
+                cgu.set_name(numbered_codegen_unit_name);
+            }
+        }
     }
 
     fn place_inlined_mono_items(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        initial_partitioning: PreInliningPartitioning<'tcx>,
-    ) -> PostInliningPartitioning<'tcx> {
-        let mut new_partitioning = Vec::new();
+        codegen_units: &mut [CodegenUnit<'tcx>],
+        roots: FxHashSet<MonoItem<'tcx>>,
+    ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> {
         let mut mono_item_placements = FxHashMap::default();
 
-        let PreInliningPartitioning {
-            codegen_units: initial_cgus,
-            roots,
-            internalization_candidates,
-        } = initial_partitioning;
+        let single_codegen_unit = codegen_units.len() == 1;
 
-        let single_codegen_unit = initial_cgus.len() == 1;
-
-        for old_codegen_unit in initial_cgus {
+        for old_codegen_unit in codegen_units.iter_mut() {
             // Collect all items that need to be available in this codegen unit.
             let mut reachable = FxHashSet::default();
             for root in old_codegen_unit.items().keys() {
@@ -174,14 +254,10 @@ fn place_inlined_mono_items(
                 }
             }
 
-            new_partitioning.push(new_codegen_unit);
+            *old_codegen_unit = new_codegen_unit;
         }
 
-        return PostInliningPartitioning {
-            codegen_units: new_partitioning,
-            mono_item_placements,
-            internalization_candidates,
-        };
+        return mono_item_placements;
 
         fn follow_inlining<'tcx>(
             mono_item: MonoItem<'tcx>,
@@ -201,14 +277,16 @@ fn follow_inlining<'tcx>(
     fn internalize_symbols(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        partitioning: &mut PostInliningPartitioning<'tcx>,
+        codegen_units: &mut [CodegenUnit<'tcx>],
+        mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
+        internalization_candidates: FxHashSet<MonoItem<'tcx>>,
     ) {
-        if partitioning.codegen_units.len() == 1 {
+        if codegen_units.len() == 1 {
             // Fast path for when there is only one codegen unit. In this case we
             // can internalize all candidates, since there is nowhere else they
             // could be accessed from.
-            for cgu in &mut partitioning.codegen_units {
-                for candidate in &partitioning.internalization_candidates {
+            for cgu in codegen_units {
+                for candidate in &internalization_candidates {
                     cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default));
                 }
             }
@@ -225,15 +303,13 @@ fn internalize_symbols(
             }
         });
 
-        let mono_item_placements = &partitioning.mono_item_placements;
-
         // For each internalization candidates in each codegen unit, check if it is
         // accessed from outside its defining codegen unit.
-        for cgu in &mut partitioning.codegen_units {
+        for cgu in codegen_units {
             let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() };
 
             for (accessee, linkage_and_visibility) in cgu.items_mut() {
-                if !partitioning.internalization_candidates.contains(accessee) {
+                if !internalization_candidates.contains(accessee) {
                     // This item is no candidate for internalizing, so skip it.
                     continue;
                 }
diff --git a/compiler/rustc_monomorphize/src/partitioning/merging.rs b/compiler/rustc_monomorphize/src/partitioning/merging.rs
deleted file mode 100644
index 5c524a1..0000000
--- a/compiler/rustc_monomorphize/src/partitioning/merging.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-use std::cmp;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder};
-use rustc_span::symbol::Symbol;
-
-use super::PartitioningCx;
-use crate::partitioning::PreInliningPartitioning;
-
-pub fn merge_codegen_units<'tcx>(
-    cx: &PartitioningCx<'_, 'tcx>,
-    initial_partitioning: &mut PreInliningPartitioning<'tcx>,
-) {
-    assert!(cx.target_cgu_count >= 1);
-    let codegen_units = &mut initial_partitioning.codegen_units;
-
-    // Note that at this point in time the `codegen_units` here may not be in a
-    // deterministic order (but we know they're deterministically the same set).
-    // We want this merging to produce a deterministic ordering of codegen units
-    // from the input.
-    //
-    // Due to basically how we've implemented the merging below (merge the two
-    // smallest into each other) we're sure to start off with a deterministic
-    // order (sorted by name). This'll mean that if two cgus have the same size
-    // the stable sort below will keep everything nice and deterministic.
-    codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
-
-    // This map keeps track of what got merged into what.
-    let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> =
-        codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect();
-
-    // Merge the two smallest codegen units until the target size is reached.
-    while codegen_units.len() > cx.target_cgu_count {
-        // Sort small cgus to the back
-        codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
-        let mut smallest = codegen_units.pop().unwrap();
-        let second_smallest = codegen_units.last_mut().unwrap();
-
-        // Move the mono-items from `smallest` to `second_smallest`
-        second_smallest.modify_size_estimate(smallest.size_estimate());
-        for (k, v) in smallest.items_mut().drain() {
-            second_smallest.items_mut().insert(k, v);
-        }
-
-        // Record that `second_smallest` now contains all the stuff that was in
-        // `smallest` before.
-        let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap();
-        cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names);
-
-        debug!(
-            "CodegenUnit {} merged into CodegenUnit {}",
-            smallest.name(),
-            second_smallest.name()
-        );
-    }
-
-    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
-
-    if cx.tcx.sess.opts.incremental.is_some() {
-        // If we are doing incremental compilation, we want CGU names to
-        // reflect the path of the source level module they correspond to.
-        // For CGUs that contain the code of multiple modules because of the
-        // merging done above, we use a concatenation of the names of
-        // all contained CGUs.
-        let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents
-            .into_iter()
-            // This `filter` makes sure we only update the name of CGUs that
-            // were actually modified by merging.
-            .filter(|(_, cgu_contents)| cgu_contents.len() > 1)
-            .map(|(current_cgu_name, cgu_contents)| {
-                let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect();
-
-                // Sort the names, so things are deterministic and easy to
-                // predict.
-
-                // We are sorting primitive &strs here so we can use unstable sort
-                cgu_contents.sort_unstable();
-
-                (current_cgu_name, cgu_contents.join("--"))
-            })
-            .collect();
-
-        for cgu in codegen_units.iter_mut() {
-            if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) {
-                if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names {
-                    cgu.set_name(Symbol::intern(&new_cgu_name));
-                } else {
-                    // If we don't require CGU names to be human-readable, we
-                    // use a fixed length hash of the composite CGU name
-                    // instead.
-                    let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name);
-                    cgu.set_name(Symbol::intern(&new_cgu_name));
-                }
-            }
-        }
-    } else {
-        // If we are compiling non-incrementally we just generate simple CGU
-        // names containing an index.
-        for (index, cgu) in codegen_units.iter_mut().enumerate() {
-            cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index));
-        }
-    }
-}
-
-fn numbered_codegen_unit_name(
-    name_builder: &mut CodegenUnitNameBuilder<'_>,
-    index: usize,
-) -> Symbol {
-    name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index))
-}
diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs
index eafe57a..d0b23ca 100644
--- a/compiler/rustc_monomorphize/src/partitioning/mod.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs
@@ -93,7 +93,6 @@
 //! inlining, even when they are not marked `#[inline]`.
 
 mod default;
-mod merging;
 
 use std::cmp;
 use std::fs::{self, File};
@@ -129,7 +128,7 @@ fn place_root_mono_items<I>(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
         mono_items: &mut I,
-    ) -> PreInliningPartitioning<'tcx>
+    ) -> PlacedRootMonoItems<'tcx>
     where
         I: Iterator<Item = MonoItem<'tcx>>,
     {
@@ -142,12 +141,10 @@ fn place_root_mono_items<I>(
     fn merge_codegen_units(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        initial_partitioning: &mut PreInliningPartitioning<'tcx>,
+        codegen_units: &mut Vec<CodegenUnit<'tcx>>,
     ) {
         match self {
-            Partitioner::Default(partitioner) => {
-                partitioner.merge_codegen_units(cx, initial_partitioning)
-            }
+            Partitioner::Default(partitioner) => partitioner.merge_codegen_units(cx, codegen_units),
             Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy),
         }
     }
@@ -155,11 +152,12 @@ fn merge_codegen_units(
     fn place_inlined_mono_items(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        initial_partitioning: PreInliningPartitioning<'tcx>,
-    ) -> PostInliningPartitioning<'tcx> {
+        codegen_units: &mut [CodegenUnit<'tcx>],
+        roots: FxHashSet<MonoItem<'tcx>>,
+    ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> {
         match self {
             Partitioner::Default(partitioner) => {
-                partitioner.place_inlined_mono_items(cx, initial_partitioning)
+                partitioner.place_inlined_mono_items(cx, codegen_units, roots)
             }
             Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy),
         }
@@ -168,48 +166,62 @@ fn place_inlined_mono_items(
     fn internalize_symbols(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        post_inlining_partitioning: &mut PostInliningPartitioning<'tcx>,
+        codegen_units: &mut [CodegenUnit<'tcx>],
+        mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
+        internalization_candidates: FxHashSet<MonoItem<'tcx>>,
     ) {
         match self {
-            Partitioner::Default(partitioner) => {
-                partitioner.internalize_symbols(cx, post_inlining_partitioning)
-            }
+            Partitioner::Default(partitioner) => partitioner.internalize_symbols(
+                cx,
+                codegen_units,
+                mono_item_placements,
+                internalization_candidates,
+            ),
             Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy),
         }
     }
 }
 
-pub struct PartitioningCx<'a, 'tcx> {
+struct PartitioningCx<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     target_cgu_count: usize,
     inlining_map: &'a InliningMap<'tcx>,
 }
 
+pub struct PlacedRootMonoItems<'tcx> {
+    codegen_units: Vec<CodegenUnit<'tcx>>,
+    roots: FxHashSet<MonoItem<'tcx>>,
+    internalization_candidates: FxHashSet<MonoItem<'tcx>>,
+}
+
 trait Partition<'tcx> {
     fn place_root_mono_items<I>(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
         mono_items: &mut I,
-    ) -> PreInliningPartitioning<'tcx>
+    ) -> PlacedRootMonoItems<'tcx>
     where
         I: Iterator<Item = MonoItem<'tcx>>;
 
     fn merge_codegen_units(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        initial_partitioning: &mut PreInliningPartitioning<'tcx>,
+        codegen_units: &mut Vec<CodegenUnit<'tcx>>,
     );
 
     fn place_inlined_mono_items(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        initial_partitioning: PreInliningPartitioning<'tcx>,
-    ) -> PostInliningPartitioning<'tcx>;
+        codegen_units: &mut [CodegenUnit<'tcx>],
+        roots: FxHashSet<MonoItem<'tcx>>,
+    ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement>;
 
     fn internalize_symbols(
         &mut self,
         cx: &PartitioningCx<'_, 'tcx>,
-        partitioning: &mut PostInliningPartitioning<'tcx>,
+        codegen_units: &mut [CodegenUnit<'tcx>],
+        mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
+        internalization_candidates: FxHashSet<MonoItem<'tcx>>,
     );
 }
 
@@ -225,7 +237,7 @@ fn get_partitioner(tcx: TyCtxt<'_>) -> Partitioner {
     }
 }
 
-pub fn partition<'tcx, I>(
+fn partition<'tcx, I>(
     tcx: TyCtxt<'tcx>,
     mono_items: &mut I,
     max_cgu_count: usize,
@@ -241,44 +253,51 @@ pub fn partition<'tcx, I>(
     // In the first step, we place all regular monomorphizations into their
     // respective 'home' codegen unit. Regular monomorphizations are all
     // functions and statics defined in the local crate.
-    let mut initial_partitioning = {
+    let PlacedRootMonoItems { mut codegen_units, roots, internalization_candidates } = {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
         partitioner.place_root_mono_items(cx, mono_items)
     };
 
-    for cgu in &mut initial_partitioning.codegen_units {
+    for cgu in &mut codegen_units {
         cgu.create_size_estimate(tcx);
     }
 
-    debug_dump(tcx, "INITIAL PARTITIONING", &initial_partitioning.codegen_units);
+    debug_dump(tcx, "INITIAL PARTITIONING", &codegen_units);
 
     // Merge until we have at most `max_cgu_count` codegen units.
+    // `merge_codegen_units` is responsible for updating the CGU size
+    // estimates.
     {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
-        partitioner.merge_codegen_units(cx, &mut initial_partitioning);
-        debug_dump(tcx, "POST MERGING", &initial_partitioning.codegen_units);
+        partitioner.merge_codegen_units(cx, &mut codegen_units);
+        debug_dump(tcx, "POST MERGING", &codegen_units);
     }
 
     // In the next step, we use the inlining map to determine which additional
     // monomorphizations have to go into each codegen unit. These additional
     // monomorphizations can be drop-glue, functions from external crates, and
     // local functions the definition of which is marked with `#[inline]`.
-    let mut post_inlining = {
+    let mono_item_placements = {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
-        partitioner.place_inlined_mono_items(cx, initial_partitioning)
+        partitioner.place_inlined_mono_items(cx, &mut codegen_units, roots)
     };
 
-    for cgu in &mut post_inlining.codegen_units {
+    for cgu in &mut codegen_units {
         cgu.create_size_estimate(tcx);
     }
 
-    debug_dump(tcx, "POST INLINING", &post_inlining.codegen_units);
+    debug_dump(tcx, "POST INLINING", &codegen_units);
 
     // Next we try to make as many symbols "internal" as possible, so LLVM has
     // more freedom to optimize.
     if !tcx.sess.link_dead_code() {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
-        partitioner.internalize_symbols(cx, &mut post_inlining);
+        partitioner.internalize_symbols(
+            cx,
+            &mut codegen_units,
+            mono_item_placements,
+            internalization_candidates,
+        );
     }
 
     let instrument_dead_code =
@@ -286,7 +305,7 @@ pub fn partition<'tcx, I>(
 
     if instrument_dead_code {
         assert!(
-            post_inlining.codegen_units.len() > 0,
+            codegen_units.len() > 0,
             "There must be at least one CGU that code coverage data can be generated in."
         );
 
@@ -297,7 +316,7 @@ pub fn partition<'tcx, I>(
         // the object file (CGU) containing the dead function stubs is included
         // in the final binary. This will probably require forcing these
         // function symbols to be included via `-u` or `/include` linker args.
-        let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect();
+        let mut cgus: Vec<_> = codegen_units.iter_mut().collect();
         cgus.sort_by_key(|cgu| cgu.size_estimate());
 
         let dead_code_cgu =
@@ -308,29 +327,17 @@ pub fn partition<'tcx, I>(
             } else {
                 // If there are no CGUs that have externally linked items,
                 // then we just pick the first CGU as a fallback.
-                &mut post_inlining.codegen_units[0]
+                &mut codegen_units[0]
             };
         dead_code_cgu.make_code_coverage_dead_code_cgu();
     }
 
     // Finally, sort by codegen unit name, so that we get deterministic results.
-    let PostInliningPartitioning {
-        codegen_units: mut result,
-        mono_item_placements: _,
-        internalization_candidates: _,
-    } = post_inlining;
+    codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
 
-    result.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
+    debug_dump(tcx, "FINAL", &codegen_units);
 
-    debug_dump(tcx, "FINAL", &result);
-
-    result
-}
-
-pub struct PreInliningPartitioning<'tcx> {
-    codegen_units: Vec<CodegenUnit<'tcx>>,
-    roots: FxHashSet<MonoItem<'tcx>>,
-    internalization_candidates: FxHashSet<MonoItem<'tcx>>,
+    codegen_units
 }
 
 /// For symbol internalization, we need to know whether a symbol/mono-item is
@@ -342,12 +349,6 @@ enum MonoItemPlacement {
     MultipleCgus,
 }
 
-struct PostInliningPartitioning<'tcx> {
-    codegen_units: Vec<CodegenUnit<'tcx>>,
-    mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
-    internalization_candidates: FxHashSet<MonoItem<'tcx>>,
-}
-
 fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) {
     let dump = move || {
         use std::fmt::Write;
diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs
index d12bfc6..772f152 100644
--- a/compiler/rustc_monomorphize/src/util.rs
+++ b/compiler/rustc_monomorphize/src/util.rs
@@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
         let before_feature_tys = tcx.subst_and_normalize_erasing_regions(
             closure_instance.substs,
             param_env,
-            ty::EarlyBinder(before_feature_tys),
+            ty::EarlyBinder::new(before_feature_tys),
         );
         let after_feature_tys = tcx.subst_and_normalize_erasing_regions(
             closure_instance.substs,
             param_env,
-            ty::EarlyBinder(after_feature_tys),
+            ty::EarlyBinder::new(after_feature_tys),
         );
 
         let new_size = tcx
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 2d0f466..9263394 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -1,230 +1,298 @@
-parse_struct_literal_body_without_path =
-    struct literal body without path
-    .suggestion = you might have forgotten to add the struct literal inside the block
-
-parse_struct_literal_needing_parens =
-    invalid struct literal
-    .suggestion = you might need to surround the struct literal in parentheses
-
-parse_maybe_report_ambiguous_plus =
-    ambiguous `+` in a type
-    .suggestion = use parentheses to disambiguate
-
-parse_maybe_recover_from_bad_type_plus =
-    expected a path on the left-hand side of `+`, not `{$ty}`
-
 parse_add_paren = try adding parentheses
 
-parse_forgot_paren = perhaps you forgot parentheses?
+parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition
+    .suggestion = if you meant to call a macro, try
+    .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier
 
-parse_expect_path = expected a path
+parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
+    .suggestion = add parentheses to clarify the precedence
 
-parse_maybe_recover_from_bad_qpath_stage_2 =
-    missing angle brackets in associated item path
-    .suggestion = try: `{$ty}`
+parse_array_brackets_instead_of_braces = this is a block expression, not an array
+    .suggestion = to make an array, use square brackets instead of curly braces
 
-parse_incorrect_semicolon =
-    expected item, found `;`
-    .suggestion = remove this semicolon
-    .help = {$name} declarations are not followed by a semicolon
+parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
 
-parse_incorrect_use_of_await =
-    incorrect use of `await`
-    .parentheses_suggestion = `await` is not a method call, remove the parentheses
-    .postfix_suggestion = `await` is a postfix operation
+parse_assoc_lifetime = associated lifetimes are not supported
+    .label = the lifetime is given here
+    .help = if you meant to specify a trait object, write `dyn Trait + 'lifetime`
 
-parse_in_in_typo =
-    expected iterable, found keyword `in`
-    .suggestion = remove the duplicated `in`
+parse_associated_static_item_not_allowed = associated `static` items are not allowed
 
-parse_invalid_variable_declaration =
-    invalid variable declaration
+parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
 
-parse_switch_mut_let_order =
-    switch the order of `mut` and `let`
-parse_missing_let_before_mut = missing keyword
-parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
-parse_use_let_not_var = write `let` instead of `var` to introduce a new variable
+parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
+    .label = to use `async fn`, switch to Rust 2018 or later
 
-parse_invalid_comparison_operator = invalid comparison operator `{$invalid}`
-    .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}`
-    .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
+parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
+    .suggestion = try switching the order
 
-parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
-    .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
-    .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
-    .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
+parse_attr_after_generic = trailing attribute after generic parameter
+    .label = attributes must go before parameters
 
-parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
-    .suggestion = use `!` to perform bitwise not
+parse_attr_without_generics = attribute without generic parameters
+    .label = attributes are only permitted when preceding parameters
 
-parse_unexpected_if_with_if = unexpected `if` in the condition expression
-    .suggestion = remove the `if`
+parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type
+    .label = attributes are not allowed here
 
-parse_unexpected_token_after_not = unexpected {$negated_desc} after identifier
-parse_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
-parse_unexpected_token_after_not_logical = use `!` to perform logical negation
-parse_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not
+parse_bad_assoc_type_bounds = bounds on associated types do not belong here
+    .label = belongs in `where` clause
 
-parse_malformed_loop_label = malformed loop label
-    .suggestion = use the correct loop label format
+parse_bad_item_kind = {$descr} is not supported in {$ctx}
+    .help = consider moving the {$descr} out to a nearby module scope
 
-parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes
-    .suggestion = remove the lifetime annotation
-    .label = annotated with lifetime here
+parse_bad_return_type_notation_dotdot =
+    return type notation uses `()` instead of `(..)` for elided arguments
+    .suggestion = remove the `..`
 
-parse_field_expression_with_generic = field expressions cannot have generic arguments
+parse_bad_return_type_notation_output =
+    return type not allowed with return type notation
+    .suggestion = remove the return type
 
-parse_macro_invocation_with_qualified_path = macros cannot use qualified paths
+parse_bare_cr = {$double_quotes ->
+    [true] bare CR not allowed in string, use `\r` instead
+    *[false] character constant must be escaped: `\r`
+    }
+    .escape = escape the character
 
-parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
-    .suggestion_remove_label = consider removing the label
-    .suggestion_enclose_in_block = consider enclosing expression in a block
+parse_bare_cr_in_raw_string = bare CR not allowed in raw string
 
-parse_require_colon_after_labeled_expression = labeled expression must be followed by `:`
-    .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
-    .label = the label
-    .suggestion = add `:` after the label
+parse_binary_float_literal_not_supported = binary float literal is not supported
+parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
 
-parse_do_catch_syntax_removed = found removed `do catch` syntax
-    .note = following RFC #2388, the new non-placeholder syntax is `try`
-    .suggestion = replace with the new syntax
+parse_box_not_pat = expected pattern, found {$descr}
+    .note = `box` is a reserved keyword
+    .suggestion = escape `box` to use it as an identifier
 
-parse_float_literal_requires_integer_part = float literals must have an integer part
-    .suggestion = must have an integer part
+parse_box_syntax_removed = `box_syntax` has been removed
+    .suggestion = use `Box::new()` instead
 
-parse_invalid_int_literal_width = invalid width `{$width}` for integer literal
-    .help = valid widths are 8, 16, 32, 64 and 128
-
-parse_invalid_num_literal_base_prefix = invalid base prefix for number literal
-    .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
-    .suggestion = try making the prefix lowercase
-
-parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
-    .label = invalid suffix `{$suffix}`
-    .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
-
-parse_invalid_float_literal_width = invalid width `{$width}` for float literal
-    .help = valid widths are 32 and 64
-
-parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
-    .label = invalid suffix `{$suffix}`
-    .help = valid suffixes are `f32` and `f64`
-
-parse_int_literal_too_large = integer literal is too large
-
-parse_missing_semicolon_before_array = expected `;`, found `[`
-    .suggestion = consider adding `;` here
-
-parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
-    .label = the `block` fragment is within this context
-
-parse_expect_dotdot_not_dotdotdot = expected `..`, found `...`
-    .suggestion = use `..` to fill in the rest of the fields
-
-parse_if_expression_missing_then_block = this `if` expression is missing a block after the condition
-    .add_then_block = add a block here
-    .condition_possibly_unfinished = this binary operation is possibly unfinished
-
-parse_if_expression_missing_condition = missing condition for `if` expression
-    .condition_label = expected condition here
-    .block_label = if this block is the condition of the `if` expression, then it must be followed by another block
-
-parse_expected_expression_found_let = expected expression, found `let` statement
-
-parse_expect_eq_instead_of_eqeq = expected `=`, found `==`
-    .suggestion = consider using `=` here
-
-parse_expected_else_block = expected `{"{"}`, found {$first_tok}
-    .label = expected an `if` or a block after this `else`
-    .suggestion = add an `if` if this is the condition of a chained `else if` statement
-
-parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches
-    .branch_label = the attributes are attached to this branch
-    .ctx_label = the branch belongs to this `{$ctx}`
-    .suggestion = remove the attributes
-
-parse_missing_in_in_for_loop = missing `in` in `for` loop
-    .use_in_not_of = try using `in` here instead
-    .add_in = try adding `in` here
-
-parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop
-    .suggestion = try adding an expression to the `for` loop
-
-parse_loop_else = `{$loop_kind}...else` loops are not supported
-    .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
-    .loop_keyword = `else` is attached to this loop
-
-parse_missing_comma_after_match_arm = expected `,` following `match` arm
-    .suggestion = missing a comma here to end this `match` arm
+parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
 
 parse_catch_after_try = keyword `catch` cannot follow a `try` block
     .help = try using `match` on the result of the `try` block instead
 
+parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
+parse_colon_as_semi = statements are terminated with a semicolon
+    .suggestion = use a semicolon instead
+
 parse_comma_after_base_struct = cannot use a comma after the base struct
     .note = the base struct must always be the last field
     .suggestion = remove this comma
 
-parse_eq_field_init = expected `:`, found `=`
-    .suggestion = replace equals symbol with a colon
-
-parse_dotdotdot = unexpected token: `...`
-    .suggest_exclusive_range = use `..` for an exclusive range
-    .suggest_inclusive_range = or `..=` for an inclusive range
-
-parse_left_arrow_operator = unexpected token: `<-`
-    .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
-
-parse_remove_let = expected pattern, found `let`
-    .suggestion = remove the unnecessary `let` keyword
-
-parse_use_eq_instead = unexpected `==`
-    .suggestion = try using `=` instead
-
-parse_use_empty_block_not_semi = expected { "`{}`" }, found `;`
-    .suggestion = try using { "`{}`" } instead
-
 parse_comparison_interpreted_as_generic =
     `<` is interpreted as a start of generic arguments for `{$type}`, not a comparison
     .label_args = interpreted as generic arguments
     .label_comparison = not interpreted as comparison
     .suggestion = try comparing the cast value
 
-parse_shift_interpreted_as_generic =
-    `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift
-    .label_args = interpreted as generic arguments
-    .label_comparison = not interpreted as shift
-    .suggestion = try shifting the cast value
+parse_comparison_operators_cannot_be_chained = comparison operators cannot be chained
+    .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments
+    .sugg_split_comparison = split the comparison into two
+    .sugg_parenthesize = parenthesize the comparison
+parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
+    .suggestion = initialize the variable
+    .help = if you meant to overwrite, remove the `let` binding
+
+parse_const_bounds_missing_tilde = const bounds must start with `~`
+    .suggestion = add `~`
+
+parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
+    .suggestion = enclose the `const` expression in braces
+
+parse_const_global_cannot_be_mutable = const globals cannot be mutable
+    .label = cannot be mutable
+    .suggestion = you might want to declare a static instead
+
+parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
+    .suggestion = remove `let`
+
+parse_cr_doc_comment = bare CR not allowed in {$block ->
+    [true] block doc-comment
+    *[false] doc-comment
+}
+
+parse_default_not_followed_by_item = `default` is not followed by an item
+    .label = the `default` qualifier
+    .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
+
+parse_do_catch_syntax_removed = found removed `do catch` syntax
+    .note = following RFC #2388, the new non-placeholder syntax is `try`
+    .suggestion = replace with the new syntax
+
+parse_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything
+    .help = doc comments must come before what they document, if a comment was intended use `//`
+    .suggestion = missing comma here
+
+parse_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type
+    .label = doc comments are not allowed here
+
+parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}`
+    .suggestion = to omit remaining fields, use `..`
+
+parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed
+    .suggestion = use `..=` instead
+
+parse_dotdotdot = unexpected token: `...`
+    .suggest_exclusive_range = use `..` for an exclusive range
+    .suggest_inclusive_range = or `..=` for an inclusive range
+
+parse_dotdotdot_rest_pattern = unexpected `...`
+    .label = not a valid pattern
+    .suggestion = for a rest pattern, use `..` instead of `...`
+
+parse_double_colon_in_bound = expected `:` followed by trait or lifetime
+    .suggestion = use single colon
+
+parse_dyn_after_mut = `mut` must precede `dyn`
+    .suggestion = place `mut` before `dyn`
+
+parse_empty_exponent_float = expected at least one digit in exponent
+
+parse_empty_unicode_escape = empty unicode escape
+    .label = this escape must have at least 1 hex digit
+
+parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern
+
+parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive
+    .suggestion = replace `enum struct` with
+
+parse_eq_field_init = expected `:`, found `=`
+    .suggestion = replace equals symbol with a colon
+
+parse_equals_struct_default = default values on `struct` fields aren't supported
+    .suggestion = remove this unsupported default value
+
+parse_escape_only_char = {$byte ->
+    [true] byte
+    *[false] character
+    } constant must be escaped: `{$escaped_msg}`
+    .escape = escape the character
+
+parse_expect_dotdot_not_dotdotdot = expected `..`, found `...`
+    .suggestion = use `..` to fill in the rest of the fields
+
+parse_expect_eq_instead_of_eqeq = expected `=`, found `==`
+    .suggestion = consider using `=` here
+
+parse_expect_label_found_ident = expected a label, found an identifier
+    .suggestion = labels start with a tick
+
+parse_expect_path = expected a path
+
+parse_expected_binding_left_of_at = left-hand side of `@` must be a binding
+    .label_lhs = interpreted as a pattern, not a binding
+    .label_rhs = also a pattern
+    .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+parse_expected_builtin_ident = expected identifier after `builtin #`
+
+parse_expected_comma_after_pattern_field = expected `,`
+
+parse_expected_else_block = expected `{"{"}`, found {$first_tok}
+    .label = expected an `if` or a block after this `else`
+    .suggestion = add an `if` if this is the condition of a chained `else if` statement
+
+parse_expected_expression_found_let = expected expression, found `let` statement
+
+parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
+    .suggestion = use `Fn` to refer to the trait
+
+parse_expected_identifier = expected identifier
+
+parse_expected_identifier_found_doc_comment = expected identifier, found doc comment
+parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
+parse_expected_identifier_found_keyword = expected identifier, found keyword
+parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
+parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
+parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
+parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
+parse_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}`
+parse_expected_identifier_found_str = expected identifier, found `{$token}`
+
+parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type
+    .suggestion = add `mut` or `const` here
+
+parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
+parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
+parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
+parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
+parse_expected_semi_found_str = expected `;`, found `{$token}`
+
+parse_expected_statement_after_outer_attr = expected statement after outer attribute
+
+parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
+
+parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
+    .label = dash-separated idents are not valid
+    .suggestion = if the original crate name uses dashes you need to use underscores in the code
+
+parse_extern_item_cannot_be_const = extern items cannot be `const`
+    .suggestion = try using a static value
+    .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
+
+parse_extra_impl_keyword_in_trait_impl = unexpected `impl` keyword
+    .suggestion = remove the extra `impl`
+    .note = this is parsed as an `impl Trait` type, but a trait is expected at this position
+
+
+parse_field_expression_with_generic = field expressions cannot have generic arguments
+
+parse_float_literal_requires_integer_part = float literals must have an integer part
+    .suggestion = must have an integer part
+
+parse_float_literal_unsupported_base = {$base} float literal is not supported
+
+parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
+    .label = `async` because of this
+    .suggestion = remove the `async` qualifier
+
+parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
+    .label = `const` because of this
+    .suggestion = remove the `const` qualifier
+
+parse_fn_ptr_with_generics = function pointer types may not have generic parameters
+    .suggestion = consider moving the lifetime {$arity ->
+        [one] parameter
+        *[other] parameters
+    } to {$for_param_list_exists ->
+        [true] the
+        *[false] a
+    } `for` parameter list
+
+parse_forgot_paren = perhaps you forgot parentheses?
 
 parse_found_expr_would_be_stmt = expected expression, found `{$token}`
     .label = expected expression
 
-parse_leading_plus_not_supported = leading `+` is not supported
-    .label = unexpected `+`
-    .suggestion_remove_plus = try removing the `+`
+parse_function_body_equals_expr = function body cannot be `= expression;`
+    .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
 
-parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments
-    .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
-    .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
+parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
+    .suggestion = surround the type parameters with angle brackets
 
-parse_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
+parse_generics_in_path = unexpected generic arguments in path
 
-parse_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses
+parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
+parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
+parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+parse_if_expression_missing_condition = missing condition for `if` expression
+    .condition_label = expected condition here
+    .block_label = if this block is the condition of the `if` expression, then it must be followed by another block
 
-parse_array_brackets_instead_of_braces = this is a block expression, not an array
-    .suggestion = to make an array, use square brackets instead of curly braces
+parse_if_expression_missing_then_block = this `if` expression is missing a block after the condition
+    .add_then_block = add a block here
+    .condition_possibly_unfinished = this binary operation is possibly unfinished
 
-parse_match_arm_body_without_braces = `match` arm body without braces
-    .label_statements = {$num_statements ->
-            [one] this statement is not surrounded by a body
-           *[other] these statements are not surrounded by a body
-        }
-    .label_arrow = while parsing the `match` arm starting here
-    .suggestion_add_braces = surround the {$num_statements ->
-            [one] statement
-           *[other] statements
-        } with a body
-    .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression
+parse_in_in_typo =
+    expected iterable, found keyword `in`
+    .suggestion = remove the duplicated `in`
+
+parse_inappropriate_default = {$article} {$descr} cannot be `default`
+    .label = `default` because of this
+    .note = only associated `fn`, `const`, and `type` items can be `default`
 
 parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
     .suggestion_remove_eq = use `..=` instead
@@ -238,16 +306,88 @@
     .suggestion_open_range = use `..` instead
     .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-parse_struct_literal_not_allowed_here = struct literals are not allowed here
-    .suggestion = surround the struct literal with parentheses
+parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds
+    .suggestion = remove the parentheses
+
+parse_incorrect_semicolon =
+    expected item, found `;`
+    .suggestion = remove this semicolon
+    .help = {$name} declarations are not followed by a semicolon
+
+parse_incorrect_use_of_await =
+    incorrect use of `await`
+    .parentheses_suggestion = `await` is not a method call, remove the parentheses
+    .postfix_suggestion = `await` is a postfix operation
+
+parse_incorrect_visibility_restriction = incorrect visibility restriction
+    .help = some possible visibility restrictions are:
+            `pub(crate)`: visible only on the current crate
+            `pub(super)`: visible only in the current module's parent
+            `pub(in path::to::module)`: visible only on the specified path
+    .suggestion = make this visible only to module `{$inner_str}` with `in`
+
+parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+parse_inner_attr_not_permitted = an inner attribute is not permitted in this context
+    .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
+    .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
+
+parse_inner_attr_not_permitted_after_outer_attr = an inner attribute is not permitted following an outer attribute
+    .label_attr = not permitted following an outer attribute
+    .label_prev_attr = previous outer attribute
+    .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
+    .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
+
+parse_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
+    .label_attr = not permitted following an outer doc comment
+    .label_prev_doc_comment = previous doc comment
+    .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
+    .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
+
+parse_inner_doc_comment_not_permitted = expected outer doc comment
+    .note = inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
+    .suggestion = you might have meant to write a regular comment
+    .label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
+    .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
+
+parse_int_literal_too_large = integer literal is too large
+
+parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
+    .label = the `block` fragment is within this context
+
+parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}`
+    .label = {parse_invalid_char_in_escape_msg}
+
+parse_invalid_char_in_escape_msg = invalid character in {$is_hex ->
+    [true] numeric character
+    *[false] unicode
+    } escape
+
+parse_invalid_comparison_operator = invalid comparison operator `{$invalid}`
+    .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}`
+    .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
+
+parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
+parse_invalid_digit_literal = invalid digit for a base {$base} literal
+
+parse_invalid_dyn_keyword = invalid `dyn` keyword
+    .help = `dyn` is only needed at the start of a trait `+`-separated list
+    .suggestion = remove this keyword
+
+parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
+parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
+    .label = invalid suffix `{$suffix}`
+    .help = valid suffixes are `f32` and `f64`
+
+parse_invalid_float_literal_width = invalid width `{$width}` for float literal
+    .help = valid widths are 32 and 64
+
+parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
+
+parse_invalid_int_literal_width = invalid width `{$width}` for integer literal
+    .help = valid widths are 8, 16, 32, 64 and 128
 
 parse_invalid_interpolated_expression = invalid interpolated expression
 
-parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
-parse_octal_float_literal_not_supported = octal float literal is not supported
-parse_binary_float_literal_not_supported = binary float literal is not supported
-parse_not_supported = not supported
-
 parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid
     .label = invalid suffix `{$suffix}`
 
@@ -257,207 +397,129 @@
     .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access
     .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
 
-parse_expected_builtin_ident = expected identifier after `builtin #`
+parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
+    .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+    .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
+    .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
 
-parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}`
+parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
 
-parse_non_string_abi_literal = non-string ABI literal
-    .suggestion = specify the ABI with a string literal
+parse_invalid_num_literal_base_prefix = invalid base prefix for number literal
+    .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
+    .suggestion = try making the prefix lowercase
+
+parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
+    .label = invalid suffix `{$suffix}`
+    .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+parse_invalid_unicode_escape = invalid unicode character escape
+    .label = invalid escape
+    .help = unicode escape must {$surrogate ->
+    [true] not be a surrogate
+    *[false] be at most 10FFFF
+    }
+
+parse_invalid_variable_declaration =
+    invalid variable declaration
+
+parse_kw_bad_case = keyword `{$kw}` is written in the wrong case
+    .suggestion = write it in the correct case
+
+parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
+parse_label_unexpected_token = unexpected token
+
+parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here
+
+parse_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
+
+parse_leading_plus_not_supported = leading `+` is not supported
+    .label = unexpected `+`
+    .suggestion_remove_plus = try removing the `+`
+
+parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_`
+parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
+
+parse_left_arrow_operator = unexpected token: `<-`
+    .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
+
+parse_lifetime_after_mut = lifetime must precede `mut`
+    .suggestion = place the lifetime before `mut`
+
+parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes
+    .suggestion = remove the lifetime annotation
+    .label = annotated with lifetime here
+
+parse_lone_slash = invalid trailing slash in literal
+    .label = {parse_lone_slash}
+
+parse_loop_else = `{$loop_kind}...else` loops are not supported
+    .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
+    .loop_keyword = `else` is attached to this loop
+
+parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
+    .suggestion = remove the visibility
+    .help = try adjusting the macro to put `{$vis}` inside the invocation
+
+parse_macro_invocation_with_qualified_path = macros cannot use qualified paths
+
+parse_macro_name_remove_bang = macro names aren't followed by a `!`
+    .suggestion = remove the `!`
+
+parse_macro_rules_missing_bang = expected `!` after `macro_rules`
+    .suggestion = add a `!`
+
+parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}`
+    .suggestion = try exporting the macro
+
+parse_malformed_cfg_attr = malformed `cfg_attr` attribute input
+    .suggestion = missing condition and attribute
+    .note = for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+parse_malformed_loop_label = malformed loop label
+    .suggestion = use the correct loop label format
+
+parse_match_arm_body_without_braces = `match` arm body without braces
+    .label_statements = {$num_statements ->
+            [one] this statement is not surrounded by a body
+           *[other] these statements are not surrounded by a body
+        }
+    .label_arrow = while parsing the `match` arm starting here
+    .suggestion_add_braces = surround the {$num_statements ->
+            [one] statement
+           *[other] statements
+        } with a body
+    .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression
+
+parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
+    .suggestion = replace `fn` with `impl` here
+
+parse_maybe_recover_from_bad_qpath_stage_2 =
+    missing angle brackets in associated item path
+    .suggestion = try: `{$ty}`
+
+parse_maybe_recover_from_bad_type_plus =
+    expected a path on the left-hand side of `+`, not `{$ty}`
+
+parse_maybe_report_ambiguous_plus =
+    ambiguous `+` in a type
+    .suggestion = use parentheses to disambiguate
+
+parse_meta_bad_delim = wrong meta list delimiters
+parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
 
 parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
     .label_unmatched = mismatched closing delimiter
     .label_opening_candidate = closing delimiter possibly meant for this
     .label_unclosed = unclosed delimiter
 
-parse_incorrect_visibility_restriction = incorrect visibility restriction
-    .help = some possible visibility restrictions are:
-            `pub(crate)`: visible only on the current crate
-            `pub(super)`: visible only in the current module's parent
-            `pub(in path::to::module)`: visible only on the specified path
-    .suggestion = make this visible only to module `{$inner_str}` with `in`
+parse_missing_comma_after_match_arm = expected `,` following `match` arm
+    .suggestion = missing a comma here to end this `match` arm
 
-parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
+parse_missing_const_type = missing type for `{$kind}` item
+    .suggestion = provide a type for the item
 
-parse_expected_statement_after_outer_attr = expected statement after outer attribute
-
-parse_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything
-    .help = doc comments must come before what they document, if a comment was intended use `//`
-    .suggestion = missing comma here
-
-parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
-    .suggestion = remove `let`
-
-parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
-parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
-parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
-
-parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
-    .suggestion = initialize the variable
-    .help = if you meant to overwrite, remove the `let` binding
-
-parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
-    .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
-
-parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
-parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
-
-parse_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
-    .label_attr = not permitted following an outer doc comment
-    .label_prev_doc_comment = previous doc comment
-    .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
-    .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
-
-parse_inner_attr_not_permitted_after_outer_attr = an inner attribute is not permitted following an outer attribute
-    .label_attr = not permitted following an outer attribute
-    .label_prev_attr = previous outer attribute
-    .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
-    .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
-
-parse_inner_attr_not_permitted = an inner attribute is not permitted in this context
-    .label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
-    .sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
-
-parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
-
-parse_inner_doc_comment_not_permitted = expected outer doc comment
-    .note = inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
-    .suggestion = you might have meant to write a regular comment
-    .label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
-    .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
-
-parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
-parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
-parse_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}`
-parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
-parse_expected_identifier_found_str = expected identifier, found `{$token}`
-
-parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
-parse_expected_identifier_found_keyword = expected identifier, found keyword
-parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
-parse_expected_identifier_found_doc_comment = expected identifier, found doc comment
-parse_expected_identifier = expected identifier
-
-parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier
-
-parse_sugg_remove_comma = remove this comma
-parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding
-
-parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
-parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
-parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
-parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
-parse_expected_semi_found_str = expected `;`, found `{$token}`
-
-parse_sugg_change_this_to_semi = change this to `;`
-parse_sugg_add_semi = add `;` here
-parse_label_unexpected_token = unexpected token
-
-parse_unmatched_angle_brackets = {$num_extra_brackets ->
-        [one] unmatched angle bracket
-       *[other] unmatched angle brackets
-    }
-    .suggestion = {$num_extra_brackets ->
-            [one] remove extra angle bracket
-           *[other] remove extra angle brackets
-        }
-
-parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
-    .suggestion = surround the type parameters with angle brackets
-
-parse_comparison_operators_cannot_be_chained = comparison operators cannot be chained
-    .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments
-    .sugg_split_comparison = split the comparison into two
-    .sugg_parenthesize = parenthesize the comparison
-parse_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
-
-parse_question_mark_in_type = invalid `?` in type
-    .label = `?` is only allowed on expressions, not types
-    .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type
-
-parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
-    .suggestion = remove parentheses in `for` loop
-
-parse_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type
-    .label = doc comments are not allowed here
-
-parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type
-    .label = attributes are not allowed here
-
-parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
-    .suggestion = give this argument a name or use an underscore to ignore it
-
-parse_self_param_not_first = unexpected `self` parameter in function
-    .label = must be the first parameter of an associated function
-
-parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
-    .suggestion = enclose the `const` expression in braces
-
-parse_unexpected_const_param_declaration = unexpected `const` parameter declaration
-    .label = expected a `const` expression, not a parameter declaration
-    .suggestion = `const` parameters must be declared for the `impl`
-
-parse_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const`
-    .suggestion = the `const` keyword is only needed in the definition of the type
-
-parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
-    .suggestion = try switching the order
-
-parse_double_colon_in_bound = expected `:` followed by trait or lifetime
-    .suggestion = use single colon
-
-parse_fn_ptr_with_generics = function pointer types may not have generic parameters
-    .suggestion = consider moving the lifetime {$arity ->
-        [one] parameter
-        *[other] parameters
-    } to {$for_param_list_exists ->
-        [true] the
-        *[false] a
-    } `for` parameter list
-
-parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
-
-parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
-    .suggestion = replace `fn` with `impl` here
-
-parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
-    .suggestion = use `Fn` to refer to the trait
-
-parse_path_single_colon = path separator must be a double colon
-    .suggestion = use a double colon instead
-
-parse_colon_as_semi = statements are terminated with a semicolon
-    .suggestion = use a semicolon instead
-
-parse_type_ascription_removed =
-    if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
-
-parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies
-    .label = unexpected where clause
-    .name_label = while parsing this tuple struct
-    .body_label = the struct body
-    .suggestion = move the body before the where clause
-
-parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
-    .label = to use `async fn`, switch to Rust 2018 or later
-
-parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
-
-parse_self_argument_pointer = cannot pass `self` by raw pointer
-    .label = cannot pass `self` by raw pointer
-
-parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item
-    .label = the visibility
-    .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
-
-parse_default_not_followed_by_item = `default` is not followed by an item
-    .label = the `default` qualifier
-    .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
-
-parse_missing_struct_for_struct_definition = missing `struct` for struct definition
-    .suggestion = add `struct` here to parse `{$ident}` as a public struct
+parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop
+    .suggestion = try adding an expression to the `for` loop
 
 parse_missing_fn_for_function_definition = missing `fn` for function definition
     .suggestion = add `fn` here to parse `{$ident}` as a public function
@@ -465,186 +527,29 @@
 parse_missing_fn_for_method_definition = missing `fn` for method definition
     .suggestion = add `fn` here to parse `{$ident}` as a public method
 
-parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition
-    .suggestion = if you meant to call a macro, try
-    .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier
+parse_missing_for_in_trait_impl = missing `for` in a trait impl
+    .suggestion = add `for` here
+
+parse_missing_in_in_for_loop = missing `in` in `for` loop
+    .use_in_not_of = try using `in` here instead
+    .add_in = try adding `in` here
+
+parse_missing_let_before_mut = missing keyword
+parse_missing_plus_in_bounds = expected `+` between lifetime and {$sym}
+    .suggestion = add `+`
+
+parse_missing_semicolon_before_array = expected `;`, found `[`
+    .suggestion = consider adding `;` here
+
+parse_missing_struct_for_struct_definition = missing `struct` for struct definition
+    .suggestion = add `struct` here to parse `{$ident}` as a public struct
 
 parse_missing_trait_in_trait_impl = missing trait in a trait impl
     .suggestion_add_trait = add a trait here
     .suggestion_remove_for = for an inherent impl, drop this `for`
 
-parse_missing_for_in_trait_impl = missing `for` in a trait impl
-    .suggestion = add `for` here
-
-parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
-
-parse_extra_impl_keyword_in_trait_impl = unexpected `impl` keyword
-    .suggestion = remove the extra `impl`
-    .note = this is parsed as an `impl Trait` type, but a trait is expected at this position
-
-
-parse_non_item_in_item_list = non-item in item list
-    .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const
-    .label_list_start = item list starts here
-    .label_non_item = non-item starts here
-    .label_list_end = item list ends here
-    .suggestion_remove_semicolon = consider removing this semicolon
-
-parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
-
-parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
-parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
-
-parse_associated_static_item_not_allowed = associated `static` items are not allowed
-
-parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
-    .label = dash-separated idents are not valid
-    .suggestion = if the original crate name uses dashes you need to use underscores in the code
-
-parse_extern_item_cannot_be_const = extern items cannot be `const`
-    .suggestion = try using a static value
-    .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
-
-parse_const_global_cannot_be_mutable = const globals cannot be mutable
-    .label = cannot be mutable
-    .suggestion = you might want to declare a static instead
-
-parse_missing_const_type = missing type for `{$kind}` item
-    .suggestion = provide a type for the item
-
-parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive
-    .suggestion = replace `enum struct` with
-
-parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
-parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
-parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
-parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`
-parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
-parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
-
-parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
-    .note = you cannot use `Self` as a generic parameter because it is reserved for associated items
-
-parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
-    .label = lifetime parameters cannot have default values
-
-parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item
-    .label = previous `where` clause starts here
-    .suggestion = consider joining the two `where` clauses into one
-
-parse_nonterminal_expected_item_keyword = expected an item keyword
-parse_nonterminal_expected_statement = expected a statement
-parse_nonterminal_expected_ident = expected ident, found `{$token}`
-parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
-
-parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
-parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
-parse_sugg_remove_leading_vert_in_pattern = remove the `|`
-parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
-
-parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
-
-parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter
-    .suggestion = remove the `||`
-
-parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here
-
-parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern
-    .suggestion = use a single `|` to separate multiple alternative patterns
-
-parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
-    .suggestion = remove the `{$token}`
-
-parse_dotdotdot_rest_pattern = unexpected `...`
-    .label = not a valid pattern
-    .suggestion = for a rest pattern, use `..` instead of `...`
-
-parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@`
-    .label_pattern = pattern on the left, should be on the right
-    .label_binding = binding on the right, should be on the left
-    .suggestion = switch the order
-
-parse_expected_binding_left_of_at = left-hand side of `@` must be a binding
-    .label_lhs = interpreted as a pattern, not a binding
-    .label_rhs = also a pattern
-    .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x`
-
-parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
-    .suggestion = add parentheses to clarify the precedence
-
-parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern
-    .suggestion = remove the lifetime
-
-parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect
-    .suggestion = try switching the order
-
-parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding
-    .suggestion = add `mut` to each binding
-parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
-    .suggestion = remove the `mut` prefix
-parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern`
-
-parse_repeated_mut_in_pattern = `mut` on a binding may not be repeated
-    .suggestion = remove the additional `mut`s
-
-parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed
-    .suggestion = use `..=` instead
-
-parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern
-
-parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}`
-    .suggestion = to omit remaining fields, use `..`
-
-parse_expected_comma_after_pattern_field = expected `,`
-
-parse_return_types_use_thin_arrow = return types are denoted using `->`
-    .suggestion = use `->` instead
-
-parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
-
-parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type
-    .suggestion = add `mut` or `const` here
-
-parse_lifetime_after_mut = lifetime must precede `mut`
-    .suggestion = place the lifetime before `mut`
-
-parse_dyn_after_mut = `mut` must precede `dyn`
-    .suggestion = place `mut` before `dyn`
-
-parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
-    .label = `const` because of this
-    .suggestion = remove the `const` qualifier
-
-parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
-    .label = `async` because of this
-    .suggestion = remove the `async` qualifier
-
-parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type
-
-parse_invalid_dyn_keyword = invalid `dyn` keyword
-    .help = `dyn` is only needed at the start of a trait `+`-separated list
-    .suggestion = remove this keyword
-
-parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
-parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
-parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
-
-parse_unexpected_token_after_dot = unexpected token: `{$actual}`
-
-parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
-
-parse_cr_doc_comment = bare CR not allowed in {$block ->
-    [true] block doc-comment
-    *[false] doc-comment
-}
-
-parse_no_digits_literal = no valid digits found for number
-
-parse_invalid_digit_literal = invalid digit for a base {$base} literal
-
-parse_empty_exponent_float = expected at least one digit in exponent
-
-parse_float_literal_unsupported_base = {$base} float literal is not supported
+parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
+    .suggestion = remove the `{$sigil}`
 
 parse_more_than_one_char = character literal may only contain one codepoint
     .followed_by = this `{$chr}` is followed by the combining {$len ->
@@ -659,73 +564,238 @@
         *[false] `str`
         } literal, use double quotes
 
+parse_multiple_skipped_lines = multiple lines skipped by escaped newline
+    .label = skipping everything up to and including this point
+
+parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item
+    .label = previous `where` clause starts here
+    .suggestion = consider joining the two `where` clauses into one
+
+parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding
+    .suggestion = add `mut` to each binding
+parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
+    .suggestion = remove the `mut` prefix
+parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
+
+parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}`
+    .suggestion = consider creating a new `{$kw_str}` definition instead of nesting
+
+parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type
+
 parse_no_brace_unicode_escape = incorrect unicode escape sequence
     .label = {parse_no_brace_unicode_escape}
     .use_braces = format of unicode escape sequences uses braces
     .format_of_unicode = format of unicode escape sequences is `\u{"{...}"}`
 
-parse_invalid_unicode_escape = invalid unicode character escape
-    .label = invalid escape
-    .help = unicode escape must {$surrogate ->
-    [true] not be a surrogate
-    *[false] be at most 10FFFF
-    }
+parse_no_digits_literal = no valid digits found for number
 
-parse_escape_only_char = {$byte ->
-    [true] byte
-    *[false] character
-    } constant must be escaped: `{$escaped_msg}`
-    .escape = escape the character
+parse_non_item_in_item_list = non-item in item list
+    .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const
+    .label_list_start = item list starts here
+    .label_non_item = non-item starts here
+    .label_list_end = item list ends here
+    .suggestion_remove_semicolon = consider removing this semicolon
 
-parse_bare_cr = {$double_quotes ->
-    [true] bare CR not allowed in string, use `\r` instead
-    *[false] character constant must be escaped: `\r`
-    }
-    .escape = escape the character
+parse_non_string_abi_literal = non-string ABI literal
+    .suggestion = specify the ABI with a string literal
 
-parse_bare_cr_in_raw_string = bare CR not allowed in raw string
+parse_nonterminal_expected_ident = expected ident, found `{$token}`
+parse_nonterminal_expected_item_keyword = expected an item keyword
+parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
 
-parse_too_short_hex_escape = numeric character escape is too short
+parse_nonterminal_expected_statement = expected a statement
+parse_not_supported = not supported
 
-parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}`
-    .label = {parse_invalid_char_in_escape_msg}
+parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
 
-parse_invalid_char_in_escape_msg = invalid character in {$is_hex ->
-    [true] numeric character
-    *[false] unicode
-    } escape
+parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern`
 
+parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
+
+parse_octal_float_literal_not_supported = octal float literal is not supported
+parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
+parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
 parse_out_of_range_hex_escape = out of range hex escape
     .label = must be a character in the range [\x00-\x7f]
 
-parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_`
-parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
+parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
+
+parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches
+    .branch_label = the attributes are attached to this branch
+    .ctx_label = the branch belongs to this `{$ctx}`
+    .suggestion = remove the attributes
 
 parse_overlong_unicode_escape = overlong unicode escape
     .label = must have at most 6 hex digits
 
+parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments
+    .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
+    .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
+
+parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
+    .suggestion = remove the parentheses
+
+parse_path_single_colon = path separator must be a double colon
+    .suggestion = use a double colon instead
+
+parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
+    .suggestion = give this argument a name or use an underscore to ignore it
+
+parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@`
+    .label_pattern = pattern on the left, should be on the right
+    .label_binding = binding on the right, should be on the left
+    .suggestion = switch the order
+
+parse_question_mark_in_type = invalid `?` in type
+    .label = `?` is only allowed on expressions, not types
+    .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type
+
+parse_recover_import_as_use = expected item, found {$token_name}
+    .suggestion = items are imported using the `use` keyword
+
+parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect
+    .suggestion = try switching the order
+
+parse_remove_let = expected pattern, found `let`
+    .suggestion = remove the unnecessary `let` keyword
+
+parse_repeated_mut_in_pattern = `mut` on a binding may not be repeated
+    .suggestion = remove the additional `mut`s
+
+parse_require_colon_after_labeled_expression = labeled expression must be followed by `:`
+    .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
+    .label = the label
+    .suggestion = add `:` after the label
+
+parse_return_types_use_thin_arrow = return types are denoted using `->`
+    .suggestion = use `->` instead
+
+parse_self_argument_pointer = cannot pass `self` by raw pointer
+    .label = cannot pass `self` by raw pointer
+
+parse_self_param_not_first = unexpected `self` parameter in function
+    .label = must be the first parameter of an associated function
+
+parse_shift_interpreted_as_generic =
+    `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift
+    .label_args = interpreted as generic arguments
+    .label_comparison = not interpreted as shift
+    .suggestion = try shifting the cast value
+
+parse_single_colon_import_path = expected `::`, found `:`
+    .suggestion = use double colon
+    .note = import paths are delimited using `::`
+
+parse_single_colon_struct_type = found single colon in a struct field type path
+    .suggestion = write a path separator here
+
+parse_struct_literal_body_without_path =
+    struct literal body without path
+    .suggestion = you might have forgotten to add the struct literal inside the block
+
+parse_struct_literal_needing_parens =
+    invalid struct literal
+    .suggestion = you might need to surround the struct literal in parentheses
+
+parse_struct_literal_not_allowed_here = struct literals are not allowed here
+    .suggestion = surround the struct literal with parentheses
+
+parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
+    .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
+
+parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding
+
+parse_sugg_add_semi = add `;` here
+parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
+
+parse_sugg_change_this_to_semi = change this to `;`
+parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier
+
+parse_sugg_remove_comma = remove this comma
+parse_sugg_remove_leading_vert_in_pattern = remove the `|`
+parse_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+
+parse_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses
+
+parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
+
+parse_switch_mut_let_order =
+    switch the order of `mut` and `let`
+parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
+
+parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
+    .suggestion = use `!` to perform bitwise not
+
+parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num}
+
+parse_too_short_hex_escape = numeric character escape is too short
+
+parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
+    .suggestion = remove the `{$token}`
+
+parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
+parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
+
+parse_type_ascription_removed =
+    if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+
 parse_unclosed_unicode_escape = unterminated unicode escape
     .label = missing a closing `{"}"}`
     .terminate = terminate the unicode escape
 
+parse_underscore_literal_suffix = underscore literal suffix is not allowed
+
+parse_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const`
+    .suggestion = the `const` keyword is only needed in the definition of the type
+
+parse_unexpected_const_param_declaration = unexpected `const` parameter declaration
+    .label = expected a `const` expression, not a parameter declaration
+    .suggestion = `const` parameters must be declared for the `impl`
+
+parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
+    .label = lifetime parameters cannot have default values
+
+parse_unexpected_if_with_if = unexpected `if` in the condition expression
+    .suggestion = remove the `if`
+
+parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern
+    .suggestion = remove the lifetime
+
+parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
+    .suggestion = remove parentheses in `for` loop
+
+parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
+    .note = you cannot use `Self` as a generic parameter because it is reserved for associated items
+
+parse_unexpected_token_after_dot = unexpected token: `{$actual}`
+
+parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
+    .suggestion_remove_label = consider removing the label
+    .suggestion_enclose_in_block = consider enclosing expression in a block
+
+parse_unexpected_token_after_not = unexpected {$negated_desc} after identifier
+parse_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
+parse_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not
+
+parse_unexpected_token_after_not_logical = use `!` to perform logical negation
+parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
+parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
+parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
+parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
+
+parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
+parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`
+parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter
+    .suggestion = remove the `||`
+
+parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern
+    .suggestion = use a single `|` to separate multiple alternative patterns
+
 parse_unicode_escape_in_byte = unicode escape in byte string
     .label = {parse_unicode_escape_in_byte}
     .help = unicode escape sequences cannot be used as a byte or in a byte string
 
-parse_empty_unicode_escape = empty unicode escape
-    .label = this escape must have at least 1 hex digit
-
-parse_zero_chars = empty character literal
-    .label = {parse_zero_chars}
-
-parse_lone_slash = invalid trailing slash in literal
-    .label = {parse_lone_slash}
-
-parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
-    .label = {parse_unskipped_whitespace}
-
-parse_multiple_skipped_lines = multiple lines skipped by escaped newline
-    .label = skipping everything up to and including this point
+parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}`
 
 parse_unknown_prefix = prefix `{$prefix}` is unknown
     .label = unknown prefix
@@ -733,8 +803,6 @@
     .suggestion_br = use `br` for a raw byte string
     .suggestion_whitespace = consider inserting whitespace here
 
-parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num}
-
 parse_unknown_start_of_token = unknown start of token: {$escaped}
     .sugg_quotes = Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '{$ascii_str}' ({$ascii_name}), but are not
     .sugg_other = Unicode character '{$ch}' ({$u_name}) looks like '{$ascii_str}' ({$ascii_name}), but it is not
@@ -744,94 +812,6 @@
         *[other] {$repeats} more times
     }
 
-parse_box_syntax_removed = `box_syntax` has been removed
-    .suggestion = use `Box::new()` instead
-
-parse_bad_return_type_notation_output =
-    return type not allowed with return type notation
-    .suggestion = remove the return type
-
-parse_bad_return_type_notation_dotdot =
-    return type notation uses `()` instead of `(..)` for elided arguments
-    .suggestion = remove the `..`
-
-parse_bad_assoc_type_bounds = bounds on associated types do not belong here
-    .label = belongs in `where` clause
-
-parse_attr_after_generic = trailing attribute after generic parameter
-    .label = attributes must go before parameters
-
-parse_attr_without_generics = attribute without generic parameters
-    .label = attributes are only permitted when preceding parameters
-
-parse_where_generics = generic parameters on `where` clauses are reserved for future use
-    .label = currently unsupported
-
-parse_generics_in_path = unexpected generic arguments in path
-
-parse_assoc_lifetime = associated lifetimes are not supported
-    .label = the lifetime is given here
-    .help = if you meant to specify a trait object, write `dyn Trait + 'lifetime`
-
-parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
-
-parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
-    .suggestion = remove the `{$sigil}`
-
-parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
-    .suggestion = remove the parentheses
-
-parse_const_bounds_missing_tilde = const bounds must start with `~`
-    .suggestion = add `~`
-
-parse_underscore_literal_suffix = underscore literal suffix is not allowed
-
-parse_expect_label_found_ident = expected a label, found an identifier
-    .suggestion = labels start with a tick
-
-parse_inappropriate_default = {$article} {$descr} cannot be `default`
-    .label = `default` because of this
-    .note = only associated `fn`, `const`, and `type` items can be `default`
-
-parse_recover_import_as_use = expected item, found {$token_name}
-    .suggestion = items are imported using the `use` keyword
-
-parse_single_colon_import_path = expected `::`, found `:`
-    .suggestion = use double colon
-    .note = import paths are delimited using `::`
-
-parse_bad_item_kind = {$descr} is not supported in {$ctx}
-    .help = consider moving the {$descr} out to a nearby module scope
-
-parse_single_colon_struct_type = found single colon in a struct field type path
-    .suggestion = write a path separator here
-
-parse_equals_struct_default = default values on `struct` fields aren't supported
-    .suggestion = remove this unsupported default value
-
-parse_macro_rules_missing_bang = expected `!` after `macro_rules`
-    .suggestion = add a `!`
-
-parse_macro_name_remove_bang = macro names aren't followed by a `!`
-    .suggestion = remove the `!`
-
-parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}`
-    .suggestion = try exporting the macro
-
-parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
-    .suggestion = remove the visibility
-    .help = try adjusting the macro to put `{$vis}` inside the invocation
-
-parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}`
-    .suggestion = consider creating a new `{$kw_str}` definition instead of nesting
-
-parse_function_body_equals_expr = function body cannot be `= expression;`
-    .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
-
-parse_box_not_pat = expected pattern, found {$descr}
-    .note = `box` is a reserved keyword
-    .suggestion = escape `box` to use it as an identifier
-
 parse_unmatched_angle = unmatched angle {$plural ->
     [true] brackets
     *[false] bracket
@@ -841,19 +821,39 @@
     *[false] bracket
     }
 
-parse_missing_plus_in_bounds = expected `+` between lifetime and {$sym}
-    .suggestion = add `+`
+parse_unmatched_angle_brackets = {$num_extra_brackets ->
+        [one] unmatched angle bracket
+       *[other] unmatched angle brackets
+    }
+    .suggestion = {$num_extra_brackets ->
+            [one] remove extra angle bracket
+           *[other] remove extra angle brackets
+        }
 
-parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds
-    .suggestion = remove the parentheses
+parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
+    .label = {parse_unskipped_whitespace}
 
-parse_kw_bad_case = keyword `{$kw}` is written in the wrong case
-    .suggestion = write it in the correct case
+parse_use_empty_block_not_semi = expected { "`{}`" }, found `;`
+    .suggestion = try using { "`{}`" } instead
 
-parse_meta_bad_delim = wrong meta list delimiters
-parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
-parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
+parse_use_eq_instead = unexpected `==`
+    .suggestion = try using `=` instead
 
-parse_malformed_cfg_attr = malformed `cfg_attr` attribute input
-    .suggestion = missing condition and attribute
-    .note = for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
+parse_use_let_not_var = write `let` instead of `var` to introduce a new variable
+
+parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item
+    .label = the visibility
+    .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
+
+parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies
+    .label = unexpected where clause
+    .name_label = while parsing this tuple struct
+    .body_label = the struct body
+    .suggestion = move the body before the where clause
+
+parse_where_generics = generic parameters on `where` clauses are reserved for future use
+    .label = currently unsupported
+
+parse_zero_chars = empty character literal
+    .label = {parse_zero_chars}
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index cd779b0..8ab38c4 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -43,6 +43,15 @@ fn parse_lt_param_bounds(&mut self) -> GenericBounds {
     fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericParam> {
         let ident = self.parse_ident()?;
 
+        // We might have a typo'd `Const` that was parsed as a type parameter.
+        if self.may_recover()
+            && ident.name.as_str().to_ascii_lowercase() == kw::Const.as_str()
+            && self.check_ident()
+        // `Const` followed by IDENT
+        {
+            return Ok(self.recover_const_param_with_mistyped_const(preceding_attrs, ident)?);
+        }
+
         // Parse optional colon and param bounds.
         let mut colon_span = None;
         let bounds = if self.eat(&token::Colon) {
@@ -120,6 +129,41 @@ pub(crate) fn parse_const_param(
         })
     }
 
+    pub(crate) fn recover_const_param_with_mistyped_const(
+        &mut self,
+        preceding_attrs: AttrVec,
+        mistyped_const_ident: Ident,
+    ) -> PResult<'a, GenericParam> {
+        let ident = self.parse_ident()?;
+        self.expect(&token::Colon)?;
+        let ty = self.parse_ty()?;
+
+        // Parse optional const generics default value.
+        let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None };
+
+        let mut err = self.struct_span_err(
+            mistyped_const_ident.span,
+            format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()),
+        );
+        err.span_suggestion_verbose(
+            mistyped_const_ident.span,
+            "use the `const` keyword",
+            kw::Const.as_str(),
+            Applicability::MachineApplicable,
+        );
+        err.emit();
+
+        Ok(GenericParam {
+            ident,
+            id: ast::DUMMY_NODE_ID,
+            attrs: preceding_attrs,
+            bounds: Vec::new(),
+            kind: GenericParamKind::Const { ty, kw_span: mistyped_const_ident.span, default },
+            is_placeholder: false,
+            colon_span: None,
+        })
+    }
+
     /// Parses a (possibly empty) list of lifetime and type parameters, possibly including
     /// a trailing comma and erroneous trailing attributes.
     pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 0c265d7..c234206 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -536,7 +536,9 @@ pub fn expect_one_of(
         } else if inedible.contains(&self.token.kind) {
             // leave it in the input
             Ok(false)
-        } else if self.last_unexpected_token_span == Some(self.token.span) {
+        } else if self.token.kind != token::Eof
+            && self.last_unexpected_token_span == Some(self.token.span)
+        {
             FatalError.raise();
         } else {
             self.expected_one_of_not_found(edible, inedible)
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 4068015..7f9222d 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -4,440 +4,66 @@
 -passes_see_issue =
     see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information
 
-passes_incorrect_do_not_recommend_location =
-    `#[do_not_recommend]` can only be placed on trait implementations
-
-passes_outer_crate_level_attr =
-    crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-
-passes_inner_crate_level_attr =
-    crate-level attribute should be in the root module
-
-passes_ignored_attr_with_macro =
-    `#[{$sym}]` is ignored on struct fields, match arms and macro defs
-    .warn = {-passes_previously_accepted}
-    .note = {-passes_see_issue(issue: "80564")}
-
-passes_ignored_attr =
-    `#[{$sym}]` is ignored on struct fields and match arms
-    .warn = {-passes_previously_accepted}
-    .note = {-passes_see_issue(issue: "80564")}
-
-passes_inline_ignored_function_prototype =
-    `#[inline]` is ignored on function prototypes
-
-passes_inline_ignored_constants =
-    `#[inline]` is ignored on constants
-    .warn = {-passes_previously_accepted}
-    .note = {-passes_see_issue(issue: "65833")}
-
-passes_inline_not_fn_or_closure =
-    attribute should be applied to function or closure
-    .label = not a function or closure
-
-passes_no_coverage_ignored_function_prototype =
-    `#[no_coverage]` is ignored on function prototypes
-
-passes_no_coverage_propagate =
-    `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
-
-passes_no_coverage_fn_defn =
-    `#[no_coverage]` may only be applied to function definitions
-
-passes_no_coverage_not_coverable =
-    `#[no_coverage]` must be applied to coverable code
-    .label = not coverable code
-
-passes_should_be_applied_to_fn =
-    attribute should be applied to a function definition
-    .label = {$on_crate ->
-        [true] cannot be applied to crates
-        *[false] not a function definition
-    }
-
-passes_naked_tracked_caller =
-    cannot use `#[track_caller]` with `#[naked]`
-
-passes_should_be_applied_to_struct_enum =
-    attribute should be applied to a struct or enum
-    .label = not a struct or enum
-
-passes_should_be_applied_to_trait =
-    attribute should be applied to a trait
-    .label = not a trait
-
-passes_target_feature_on_statement =
-    {passes_should_be_applied_to_fn}
-    .warn = {-passes_previously_accepted}
-    .label = {passes_should_be_applied_to_fn.label}
-
-passes_should_be_applied_to_static =
-    attribute should be applied to a static
-    .label = not a static
-
-passes_doc_expect_str =
-    doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
-
-passes_doc_alias_empty =
-    {$attr_str} attribute cannot have empty value
-
-passes_doc_alias_bad_char =
-    {$char_} character isn't allowed in {$attr_str}
-
-passes_doc_alias_start_end =
-    {$attr_str} cannot start or end with ' '
-
-passes_doc_alias_bad_location =
-    {$attr_str} isn't allowed on {$location}
-
-passes_doc_alias_not_an_alias =
-    {$attr_str} is the same as the item's name
-
-passes_doc_alias_duplicated = doc alias is duplicated
-    .label = first defined here
-
-passes_doc_alias_not_string_literal =
-    `#[doc(alias("a"))]` expects string literals
-
-passes_doc_alias_malformed =
-    doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
-
-passes_doc_keyword_empty_mod =
-    `#[doc(keyword = "...")]` should be used on empty modules
-
-passes_doc_keyword_not_mod =
-    `#[doc(keyword = "...")]` should be used on modules
-
-passes_doc_keyword_invalid_ident =
-    `{$doc_keyword}` is not a valid identifier
-
-passes_doc_fake_variadic_not_valid =
-    `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
-
-passes_doc_keyword_only_impl =
-    `#[doc(keyword = "...")]` should be used on impl blocks
-
-passes_doc_inline_conflict_first =
-    this attribute...
-
-passes_doc_inline_conflict_second =
-    {"."}..conflicts with this attribute
-
-passes_doc_inline_conflict =
-    conflicting doc inlining attributes
-    .help = remove one of the conflicting attributes
-
-passes_doc_inline_only_use =
-    this attribute can only be applied to a `use` item
-    .label = only applicable on `use` items
-    .not_a_use_item_label = not a `use` item
-    .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
-
-passes_doc_attr_not_crate_level =
-    `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
-
-passes_attr_crate_level =
-    this attribute can only be applied at the crate level
-    .suggestion = to apply to the crate, use an inner attribute
-    .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
-
-passes_doc_test_unknown =
-    unknown `doc(test)` attribute `{$path}`
-
-passes_doc_test_takes_list =
-    `#[doc(test(...)]` takes a list of attributes
-
-passes_doc_cfg_hide_takes_list =
-    `#[doc(cfg_hide(...)]` takes a list of attributes
-
-passes_doc_test_unknown_any =
-    unknown `doc` attribute `{$path}`
-
-passes_doc_test_unknown_spotlight =
-    unknown `doc` attribute `{$path}`
-    .note = `doc(spotlight)` was renamed to `doc(notable_trait)`
-    .suggestion = use `notable_trait` instead
-    .no_op_note = `doc(spotlight)` is now a no-op
-
-passes_doc_test_unknown_include =
-    unknown `doc` attribute `{$path}`
-    .suggestion = use `doc = include_str!` instead
-
-passes_doc_invalid =
-    invalid `doc` attribute
-
-passes_pass_by_value =
-    `pass_by_value` attribute should be applied to a struct, enum or type alias
-    .label = is not a struct, enum or type alias
-
-passes_allow_incoherent_impl =
-    `rustc_allow_incoherent_impl` attribute should be applied to impl items.
-    .label = the only currently supported targets are inherent methods
-
-passes_has_incoherent_inherent_impl =
-    `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
-    .label = only adts, extern types and traits are supported
-
-passes_both_ffi_const_and_pure =
-    `#[ffi_const]` function cannot be `#[ffi_pure]`
-
-passes_ffi_pure_invalid_target =
-    `#[ffi_pure]` may only be used on foreign functions
-
-passes_ffi_const_invalid_target =
-    `#[ffi_const]` may only be used on foreign functions
-
-passes_ffi_returns_twice_invalid_target =
-    `#[ffi_returns_twice]` may only be used on foreign functions
-
-passes_must_use_async =
-    `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
-    .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
-
-passes_must_use_no_effect =
-    `#[must_use]` has no effect when applied to {$article} {$target}
-
-passes_must_not_suspend =
-    `must_not_suspend` attribute should be applied to a struct, enum, or trait
-    .label = is not a struct, enum, or trait
-
-passes_cold =
-    {passes_should_be_applied_to_fn}
-    .warn = {-passes_previously_accepted}
-    .label = {passes_should_be_applied_to_fn.label}
-
-passes_link =
-    attribute should be applied to an `extern` block with non-Rust ABI
-    .warn = {-passes_previously_accepted}
-    .label = not an `extern` block
-
-passes_link_name =
-    attribute should be applied to a foreign function or static
-    .warn = {-passes_previously_accepted}
-    .label = not a foreign function or static
-    .help = try `#[link(name = "{$value}")]` instead
-
-passes_no_link =
-    attribute should be applied to an `extern crate` item
-    .label = not an `extern crate` item
-
-passes_export_name =
-    attribute should be applied to a free function, impl method or static
-    .label = not a free function, impl method or static
-
-passes_rustc_layout_scalar_valid_range_not_struct =
-    attribute should be applied to a struct
-    .label = not a struct
-
-passes_rustc_layout_scalar_valid_range_arg =
-    expected exactly one integer literal argument
-
-passes_rustc_legacy_const_generics_only =
-    #[rustc_legacy_const_generics] functions must only have const generics
-    .label = non-const generic parameter
-
-passes_rustc_legacy_const_generics_index =
-    #[rustc_legacy_const_generics] must have one index for each generic parameter
-    .label = generic parameters
-
-passes_rustc_legacy_const_generics_index_exceed =
-    index exceeds number of arguments
-    .label = there {$arg_count ->
-        [one] is
-        *[other] are
-    } only {$arg_count} {$arg_count ->
-        [one] argument
-        *[other] arguments
-    }
-
-passes_rustc_legacy_const_generics_index_negative =
-    arguments should be non-negative integers
-
-passes_rustc_dirty_clean =
-    attribute requires -Z query-dep-graph to be enabled
-
-passes_link_section =
-    attribute should be applied to a function or static
-    .warn = {-passes_previously_accepted}
-    .label = not a function or static
-
-passes_no_mangle_foreign =
-    `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
-    .warn = {-passes_previously_accepted}
-    .label = foreign {$foreign_item_kind}
-    .note = symbol names in extern blocks are not mangled
-    .suggestion = remove this attribute
-
-passes_no_mangle =
-    attribute should be applied to a free function, impl method or static
-    .warn = {-passes_previously_accepted}
-    .label = not a free function, impl method or static
-
-passes_repr_ident =
-    meta item in `repr` must be an identifier
-
-passes_repr_conflicting =
-    conflicting representation hints
-
-passes_used_static =
-    attribute must be applied to a `static` variable
-
-passes_used_compiler_linker =
-    `used(compiler)` and `used(linker)` can't be used together
-
-passes_allow_internal_unstable =
-    attribute should be applied to a macro
-    .label = not a macro
-
-passes_debug_visualizer_placement =
-    attribute should be applied to a module
-
-passes_debug_visualizer_invalid =
-    invalid argument
-    .note_1 = expected: `natvis_file = "..."`
-    .note_2 = OR
-    .note_3 = expected: `gdb_script_file = "..."`
-
-passes_debug_visualizer_unreadable =
-    couldn't read {$file}: {$error}
-
-passes_rustc_allow_const_fn_unstable =
-    attribute should be applied to `const fn`
-    .label = not a `const fn`
-
-passes_rustc_std_internal_symbol =
-    attribute should be applied to functions or statics
-    .label = not a function or static
-
-passes_const_trait =
-    attribute should be applied to a trait
-
-passes_stability_promotable =
-    attribute cannot be applied to an expression
-
-passes_deprecated =
-    attribute is ignored here
-
-passes_macro_use =
-    `#[{$name}]` only has an effect on `extern crate` and modules
-
-passes_macro_export =
-    `#[macro_export]` only has an effect on macro definitions
-
-passes_plugin_registrar =
-    `#[plugin_registrar]` only has an effect on functions
-
-passes_unused_empty_lints_note =
-    attribute `{$name}` with an empty list has no effect
-
-passes_unused_no_lints_note =
-    attribute `{$name}` without any lints has no effect
-
-passes_unused_default_method_body_const_note =
-    `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
-
-passes_unused =
-    unused attribute
-    .suggestion = remove this attribute
-
-passes_non_exported_macro_invalid_attrs =
-    attribute should be applied to function or closure
-    .label = not a function or closure
-
-passes_unused_duplicate =
-    unused attribute
-    .suggestion = remove this attribute
-    .note = attribute also specified here
-    .warn = {-passes_previously_accepted}
-
-passes_unused_multiple =
-    multiple `{$name}` attributes
-    .suggestion = remove this attribute
-    .note = attribute also specified here
-
-passes_rustc_lint_opt_ty =
-    `#[rustc_lint_opt_ty]` should be applied to a struct
-    .label = not a struct
-
-passes_rustc_lint_opt_deny_field_access =
-    `#[rustc_lint_opt_deny_field_access]` should be applied to a field
-    .label = not a field
-
-passes_link_ordinal =
-    attribute should be applied to a foreign function or static
-    .label = not a foreign function or static
-
-passes_collapse_debuginfo =
-    `collapse_debuginfo` attribute should be applied to macro definitions
-    .label = not a macro definition
-
-passes_deprecated_annotation_has_no_effect =
-    this `#[deprecated]` annotation has no effect
-    .suggestion = remove the unnecessary deprecation attribute
-
-passes_unknown_external_lang_item =
-    unknown external lang item: `{$lang_item}`
-
-passes_missing_panic_handler =
-    `#[panic_handler]` function required, but not found
-
-passes_missing_lang_item =
-    language item required, but not found: `{$name}`
-    .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
-    .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
-
-passes_lang_item_on_incorrect_target =
-    `{$name}` language item must be applied to a {$expected_target}
-    .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
-
-passes_unknown_lang_item =
-    definition of an unknown language item: `{$name}`
-    .label = definition of unknown language item `{$name}`
-
-passes_invalid_attr_at_crate_level =
-    `{$name}` attribute cannot be used at crate level
-    .suggestion = perhaps you meant to use an outer attribute
-
-passes_duplicate_diagnostic_item_in_crate =
-    duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
-    .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
-
-passes_diagnostic_item_first_defined =
-    the diagnostic item is first defined here
-
 passes_abi =
     abi: {$abi}
 
 passes_align =
     align: {$align}
 
-passes_size =
-    size: {$size}
+passes_allow_incoherent_impl =
+    `rustc_allow_incoherent_impl` attribute should be applied to impl items.
+    .label = the only currently supported targets are inherent methods
 
-passes_homogeneous_aggregate =
-    homogeneous_aggregate: {$homogeneous_aggregate}
+passes_allow_internal_unstable =
+    attribute should be applied to a macro
+    .label = not a macro
 
-passes_layout_of =
-    layout_of({$normalized_ty}) = {$ty_layout}
+passes_attr_application_enum =
+    attribute should be applied to an enum
+    .label = not an enum
 
-passes_unrecognized_field =
-    unrecognized field name `{$name}`
+passes_attr_application_struct =
+    attribute should be applied to a struct
+    .label = not a struct
 
-passes_layout =
-    layout error: {$layout_error}
+passes_attr_application_struct_enum_function_method_union =
+    attribute should be applied to a struct, enum, function, associated function, or union
+    .label = not a struct, enum, function, associated function, or union
 
-passes_feature_stable_twice =
-    feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
+passes_attr_application_struct_enum_union =
+    attribute should be applied to a struct, enum, or union
+    .label = not a struct, enum, or union
 
-passes_feature_previously_declared =
-    feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
+passes_attr_application_struct_union =
+    attribute should be applied to a struct or union
+    .label = not a struct or union
 
-passes_expr_not_allowed_in_context =
-    {$expr} is not allowed in a `{$context}`
+passes_attr_crate_level =
+    this attribute can only be applied at the crate level
+    .suggestion = to apply to the crate, use an inner attribute
+    .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
 
-passes_const_impl_const_trait =
-    const `impl`s must be for traits marked with `#[const_trait]`
-    .note = this trait must be annotated with `#[const_trait]`
+passes_attr_only_in_functions =
+    `{$attr}` attribute can only be used on functions
+
+passes_attr_only_on_main =
+    `{$attr}` attribute can only be used on `fn main()`
+
+passes_attr_only_on_root_main =
+    `{$attr}` attribute can only be used on root `fn main()`
+
+passes_both_ffi_const_and_pure =
+    `#[ffi_const]` function cannot be `#[ffi_pure]`
+
+passes_break_inside_async_block =
+    `{$name}` inside of an `async` block
+    .label = cannot `{$name}` inside of an `async` block
+    .async_block_label = enclosing `async` block
+
+passes_break_inside_closure =
+    `{$name}` inside of a closure
+    .label = cannot `{$name}` inside of a closure
+    .closure_label = enclosing closure
 
 passes_break_non_loop =
     `break` with value from a `{$kind}` loop
@@ -446,105 +72,170 @@
     .suggestion = use `break` on its own without a value inside this `{$kind}` loop
     .break_expr_suggestion = alternatively, you might have meant to use the available loop label
 
+passes_cannot_inline_naked_function =
+    naked functions cannot be inlined
+
+passes_cannot_stabilize_deprecated =
+    an API can't be stabilized after it is deprecated
+    .label = invalid version
+    .item = the stability attribute annotates this item
+
+passes_change_fields_to_be_of_unit_type =
+    consider changing the { $num ->
+      [one] field
+     *[other] fields
+    } to be of unit type to suppress this warning while preserving the field numbering, or remove the { $num ->
+      [one] field
+     *[other] fields
+    }
+
+passes_cold =
+    {passes_should_be_applied_to_fn}
+    .warn = {-passes_previously_accepted}
+    .label = {passes_should_be_applied_to_fn.label}
+
+passes_collapse_debuginfo =
+    `collapse_debuginfo` attribute should be applied to macro definitions
+    .label = not a macro definition
+
+passes_const_impl_const_trait =
+    const `impl`s must be for traits marked with `#[const_trait]`
+    .note = this trait must be annotated with `#[const_trait]`
+
+passes_const_trait =
+    attribute should be applied to a trait
+
 passes_continue_labeled_block =
     `continue` pointing to a labeled block
     .label = labeled blocks cannot be `continue`'d
     .block_label = labeled block the `continue` points to
 
-passes_break_inside_closure =
-    `{$name}` inside of a closure
-    .label = cannot `{$name}` inside of a closure
-    .closure_label = enclosing closure
+passes_dead_codes =
+    { $multiple ->
+      *[true] multiple {$descr}s are
+       [false] { $num ->
+         [one] {$descr} {$name_list} is
+        *[other] {$descr}s {$name_list} are
+       }
+    } never {$participle}
 
-passes_break_inside_async_block =
-    `{$name}` inside of an `async` block
-    .label = cannot `{$name}` inside of an `async` block
-    .async_block_label = enclosing `async` block
+passes_debug_visualizer_invalid =
+    invalid argument
+    .note_1 = expected: `natvis_file = "..."`
+    .note_2 = OR
+    .note_3 = expected: `gdb_script_file = "..."`
 
-passes_outside_loop =
-    `{$name}` outside of a loop{$is_break ->
-        [true] {" or labeled block"}
-        *[false] {""}
-    }
-    .label = cannot `{$name}` outside of a loop{$is_break ->
-        [true] {" or labeled block"}
-        *[false] {""}
-    }
+passes_debug_visualizer_placement =
+    attribute should be applied to a module
 
-passes_unlabeled_in_labeled_block =
-    unlabeled `{$cf_type}` inside of a labeled block
-    .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
+passes_debug_visualizer_unreadable =
+    couldn't read {$file}: {$error}
 
-passes_unlabeled_cf_in_while_condition =
-    `break` or `continue` with no label in the condition of a `while` loop
-    .label = unlabeled `{$cf_type}` in the condition of a `while` loop
+passes_deprecated =
+    attribute is ignored here
 
-passes_cannot_inline_naked_function =
-    naked functions cannot be inlined
+passes_deprecated_annotation_has_no_effect =
+    this `#[deprecated]` annotation has no effect
+    .suggestion = remove the unnecessary deprecation attribute
 
-passes_undefined_naked_function_abi =
-    Rust ABI is unsupported in naked functions
+passes_deprecated_attribute =
+    deprecated attribute must be paired with either stable or unstable attribute
 
-passes_no_patterns =
-    patterns not allowed in naked function parameters
+passes_diagnostic_item_first_defined =
+    the diagnostic item is first defined here
 
-passes_params_not_allowed =
-    referencing function parameters is not allowed in naked functions
-    .help = follow the calling convention in asm block to use parameters
+passes_doc_alias_bad_char =
+    {$char_} character isn't allowed in {$attr_str}
 
-passes_naked_functions_asm_block =
-    naked functions must contain a single asm block
-    .label_multiple_asm = multiple asm blocks are unsupported in naked functions
-    .label_non_asm = non-asm is unsupported in naked functions
+passes_doc_alias_bad_location =
+    {$attr_str} isn't allowed on {$location}
 
-passes_naked_functions_operands =
-    only `const` and `sym` operands are supported in naked functions
+passes_doc_alias_duplicated = doc alias is duplicated
+    .label = first defined here
 
-passes_naked_functions_asm_options =
-    asm options unsupported in naked functions: {$unsupported_options}
+passes_doc_alias_empty =
+    {$attr_str} attribute cannot have empty value
 
-passes_naked_functions_must_use_noreturn =
-    asm in naked functions must use `noreturn` option
-    .suggestion = consider specifying that the asm block is responsible for returning from the function
+passes_doc_alias_malformed =
+    doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
 
-passes_attr_only_on_main =
-    `{$attr}` attribute can only be used on `fn main()`
+passes_doc_alias_not_an_alias =
+    {$attr_str} is the same as the item's name
 
-passes_attr_only_on_root_main =
-    `{$attr}` attribute can only be used on root `fn main()`
+passes_doc_alias_not_string_literal =
+    `#[doc(alias("a"))]` expects string literals
 
-passes_attr_only_in_functions =
-    `{$attr}` attribute can only be used on functions
+passes_doc_alias_start_end =
+    {$attr_str} cannot start or end with ' '
 
-passes_multiple_rustc_main =
-    multiple functions with a `#[rustc_main]` attribute
-    .first = first `#[rustc_main]` function
-    .additional = additional `#[rustc_main]` function
+passes_doc_attr_not_crate_level =
+    `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
 
-passes_multiple_start_functions =
-    multiple `start` functions
-    .label = multiple `start` functions
-    .previous = previous `#[start]` function here
+passes_doc_cfg_hide_takes_list =
+    `#[doc(cfg_hide(...)]` takes a list of attributes
 
-passes_extern_main =
-    the `main` function cannot be declared in an `extern` block
+passes_doc_expect_str =
+    doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
 
-passes_unix_sigpipe_values =
-    valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+passes_doc_fake_variadic_not_valid =
+    `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
 
-passes_no_main_function =
-    `main` function not found in crate `{$crate_name}`
-    .here_is_main = here is a function named `main`
-    .one_or_more_possible_main = you have one or more functions named `main` not defined at the crate level
-    .consider_moving_main = consider moving the `main` function definitions
-    .main_must_be_defined_at_crate = the main function must be defined at the crate level{$has_filename ->
-        [true] {" "}(in `{$filename}`)
-        *[false] {""}
-    }
-    .consider_adding_main_to_file = consider adding a `main` function to `{$filename}`
-    .consider_adding_main_at_crate = consider adding a `main` function at the crate level
-    .teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/
-    .non_function_main = non-function item at `crate::main` is found
+passes_doc_inline_conflict =
+    conflicting doc inlining attributes
+    .help = remove one of the conflicting attributes
+
+passes_doc_inline_conflict_first =
+    this attribute...
+
+passes_doc_inline_conflict_second =
+    {"."}..conflicts with this attribute
+
+passes_doc_inline_only_use =
+    this attribute can only be applied to a `use` item
+    .label = only applicable on `use` items
+    .not_a_use_item_label = not a `use` item
+    .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
+
+passes_doc_invalid =
+    invalid `doc` attribute
+
+passes_doc_keyword_empty_mod =
+    `#[doc(keyword = "...")]` should be used on empty modules
+
+passes_doc_keyword_invalid_ident =
+    `{$doc_keyword}` is not a valid identifier
+
+passes_doc_keyword_not_mod =
+    `#[doc(keyword = "...")]` should be used on modules
+
+passes_doc_keyword_only_impl =
+    `#[doc(keyword = "...")]` should be used on impl blocks
+
+passes_doc_test_takes_list =
+    `#[doc(test(...)]` takes a list of attributes
+
+passes_doc_test_unknown =
+    unknown `doc(test)` attribute `{$path}`
+
+passes_doc_test_unknown_any =
+    unknown `doc` attribute `{$path}`
+
+passes_doc_test_unknown_include =
+    unknown `doc` attribute `{$path}`
+    .suggestion = use `doc = include_str!` instead
+
+passes_doc_test_unknown_spotlight =
+    unknown `doc` attribute `{$path}`
+    .note = `doc(spotlight)` was renamed to `doc(notable_trait)`
+    .suggestion = use `notable_trait` instead
+    .no_op_note = `doc(spotlight)` is now a no-op
+
+passes_duplicate_diagnostic_item_in_crate =
+    duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
+    .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
+
+passes_duplicate_feature_err =
+    the feature `{$feature}` has already been declared
 
 passes_duplicate_lang_item =
     found duplicate lang item `{$lang_item_name}`
@@ -576,6 +267,66 @@
     .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
     .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
 
+passes_export_name =
+    attribute should be applied to a free function, impl method or static
+    .label = not a free function, impl method or static
+
+passes_expr_not_allowed_in_context =
+    {$expr} is not allowed in a `{$context}`
+
+passes_extern_main =
+    the `main` function cannot be declared in an `extern` block
+
+passes_feature_only_on_nightly =
+    `#![feature]` may not be used on the {$release_channel} release channel
+
+passes_feature_previously_declared =
+    feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
+
+passes_feature_stable_twice =
+    feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
+
+passes_ffi_const_invalid_target =
+    `#[ffi_const]` may only be used on foreign functions
+
+passes_ffi_pure_invalid_target =
+    `#[ffi_pure]` may only be used on foreign functions
+
+passes_ffi_returns_twice_invalid_target =
+    `#[ffi_returns_twice]` may only be used on foreign functions
+
+passes_has_incoherent_inherent_impl =
+    `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
+    .label = only adts, extern types and traits are supported
+
+passes_homogeneous_aggregate =
+    homogeneous_aggregate: {$homogeneous_aggregate}
+
+passes_ignored_attr =
+    `#[{$sym}]` is ignored on struct fields and match arms
+    .warn = {-passes_previously_accepted}
+    .note = {-passes_see_issue(issue: "80564")}
+
+passes_ignored_attr_with_macro =
+    `#[{$sym}]` is ignored on struct fields, match arms and macro defs
+    .warn = {-passes_previously_accepted}
+    .note = {-passes_see_issue(issue: "80564")}
+
+passes_ignored_derived_impls =
+    `{$name}` has {$trait_list_len ->
+      [one] a derived impl
+     *[other] derived impls
+    } for the {$trait_list_len ->
+      [one] trait {$trait_list}, but this is
+     *[other] traits {$trait_list}, but these are
+    } intentionally ignored during dead code analysis
+
+passes_implied_feature_not_exist =
+    feature `{$implied_by}` implying `{$feature}` does not exist
+
+passes_incorrect_do_not_recommend_location =
+    `#[do_not_recommend]` can only be placed on trait implementations
+
 passes_incorrect_target =
     `{$name}` language item must be applied to a {$kind} with {$at_least ->
         [true] at least {$num}
@@ -589,11 +340,189 @@
         *[other] arguments
     }
 
-passes_useless_assignment =
-    useless assignment of {$is_field_assign ->
-        [true] field
-        *[false] variable
-    } of type `{$ty}` to itself
+passes_ineffective_unstable_impl = an `#[unstable]` annotation here has no effect
+    .note = see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
+
+passes_inline_ignored_constants =
+    `#[inline]` is ignored on constants
+    .warn = {-passes_previously_accepted}
+    .note = {-passes_see_issue(issue: "65833")}
+
+passes_inline_ignored_function_prototype =
+    `#[inline]` is ignored on function prototypes
+
+passes_inline_not_fn_or_closure =
+    attribute should be applied to function or closure
+    .label = not a function or closure
+
+passes_inner_crate_level_attr =
+    crate-level attribute should be in the root module
+
+passes_invalid_attr_at_crate_level =
+    `{$name}` attribute cannot be used at crate level
+    .suggestion = perhaps you meant to use an outer attribute
+
+passes_invalid_deprecation_version =
+    invalid deprecation version found
+    .label = invalid deprecation version
+    .item = the stability attribute annotates this item
+
+passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
+
+passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
+
+passes_invalid_stability =
+    invalid stability version found
+    .label = invalid stability version
+    .item = the stability attribute annotates this item
+
+passes_lang_item_on_incorrect_target =
+    `{$name}` language item must be applied to a {$expected_target}
+    .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
+
+passes_layout =
+    layout error: {$layout_error}
+
+passes_layout_of =
+    layout_of({$normalized_ty}) = {$ty_layout}
+
+passes_link =
+    attribute should be applied to an `extern` block with non-Rust ABI
+    .warn = {-passes_previously_accepted}
+    .label = not an `extern` block
+
+passes_link_name =
+    attribute should be applied to a foreign function or static
+    .warn = {-passes_previously_accepted}
+    .label = not a foreign function or static
+    .help = try `#[link(name = "{$value}")]` instead
+
+passes_link_ordinal =
+    attribute should be applied to a foreign function or static
+    .label = not a foreign function or static
+
+passes_link_section =
+    attribute should be applied to a function or static
+    .warn = {-passes_previously_accepted}
+    .label = not a function or static
+
+passes_macro_export =
+    `#[macro_export]` only has an effect on macro definitions
+
+passes_macro_use =
+    `#[{$name}]` only has an effect on `extern crate` and modules
+
+passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
+passes_missing_const_err =
+    attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+    .help = make the function or method const
+    .label = attribute specified here
+
+passes_missing_const_stab_attr =
+    {$descr} has missing const stability attribute
+
+passes_missing_lang_item =
+    language item required, but not found: `{$name}`
+    .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
+    .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
+
+passes_missing_panic_handler =
+    `#[panic_handler]` function required, but not found
+
+passes_missing_stability_attr =
+    {$descr} has missing stability attribute
+
+passes_multiple_rustc_main =
+    multiple functions with a `#[rustc_main]` attribute
+    .first = first `#[rustc_main]` function
+    .additional = additional `#[rustc_main]` function
+
+passes_multiple_start_functions =
+    multiple `start` functions
+    .label = multiple `start` functions
+    .previous = previous `#[start]` function here
+
+passes_must_not_suspend =
+    `must_not_suspend` attribute should be applied to a struct, enum, or trait
+    .label = is not a struct, enum, or trait
+
+passes_must_use_async =
+    `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
+    .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
+
+passes_must_use_no_effect =
+    `#[must_use]` has no effect when applied to {$article} {$target}
+
+passes_naked_functions_asm_block =
+    naked functions must contain a single asm block
+    .label_multiple_asm = multiple asm blocks are unsupported in naked functions
+    .label_non_asm = non-asm is unsupported in naked functions
+
+passes_naked_functions_asm_options =
+    asm options unsupported in naked functions: {$unsupported_options}
+
+passes_naked_functions_must_use_noreturn =
+    asm in naked functions must use `noreturn` option
+    .suggestion = consider specifying that the asm block is responsible for returning from the function
+
+passes_naked_functions_operands =
+    only `const` and `sym` operands are supported in naked functions
+
+passes_naked_tracked_caller =
+    cannot use `#[track_caller]` with `#[naked]`
+
+passes_no_coverage_fn_defn =
+    `#[no_coverage]` may only be applied to function definitions
+
+passes_no_coverage_ignored_function_prototype =
+    `#[no_coverage]` is ignored on function prototypes
+
+passes_no_coverage_not_coverable =
+    `#[no_coverage]` must be applied to coverable code
+    .label = not coverable code
+
+passes_no_coverage_propagate =
+    `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+
+passes_no_link =
+    attribute should be applied to an `extern crate` item
+    .label = not an `extern crate` item
+
+passes_no_main_function =
+    `main` function not found in crate `{$crate_name}`
+    .here_is_main = here is a function named `main`
+    .one_or_more_possible_main = you have one or more functions named `main` not defined at the crate level
+    .consider_moving_main = consider moving the `main` function definitions
+    .main_must_be_defined_at_crate = the main function must be defined at the crate level{$has_filename ->
+        [true] {" "}(in `{$filename}`)
+        *[false] {""}
+    }
+    .consider_adding_main_to_file = consider adding a `main` function to `{$filename}`
+    .consider_adding_main_at_crate = consider adding a `main` function at the crate level
+    .teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/
+    .non_function_main = non-function item at `crate::main` is found
+
+passes_no_mangle =
+    attribute should be applied to a free function, impl method or static
+    .warn = {-passes_previously_accepted}
+    .label = not a free function, impl method or static
+
+passes_no_mangle_foreign =
+    `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
+    .warn = {-passes_previously_accepted}
+    .label = foreign {$foreign_item_kind}
+    .note = symbol names in extern blocks are not mangled
+    .suggestion = remove this attribute
+
+passes_no_patterns =
+    patterns not allowed in naked function parameters
+
+passes_non_exported_macro_invalid_attrs =
+    attribute should be applied to function or closure
+    .label = not a function or closure
+
+passes_object_lifetime_err =
+    {$repr}
 
 passes_only_has_effect_on =
     `#[{$attr_name}]` only has an effect on {$target_name ->
@@ -603,103 +532,22 @@
         *[unspecified] (unspecified--this is a compiler bug)
     }
 
-passes_object_lifetime_err =
-    {$repr}
+passes_outer_crate_level_attr =
+    crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
 
-passes_unrecognized_repr_hint =
-    unrecognized representation hint
-    .help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
-
-passes_attr_application_enum =
-    attribute should be applied to an enum
-    .label = not an enum
-
-passes_attr_application_struct =
-    attribute should be applied to a struct
-    .label = not a struct
-
-passes_attr_application_struct_union =
-    attribute should be applied to a struct or union
-    .label = not a struct or union
-
-passes_attr_application_struct_enum_union =
-    attribute should be applied to a struct, enum, or union
-    .label = not a struct, enum, or union
-
-passes_attr_application_struct_enum_function_method_union =
-    attribute should be applied to a struct, enum, function, associated function, or union
-    .label = not a struct, enum, function, associated function, or union
-
-passes_transparent_incompatible =
-    transparent {$target} cannot have other repr hints
-
-passes_deprecated_attribute =
-    deprecated attribute must be paired with either stable or unstable attribute
-
-passes_useless_stability =
-    this stability annotation is useless
-    .label = useless stability annotation
-    .item = the stability attribute annotates this item
-
-passes_invalid_stability =
-    invalid stability version found
-    .label = invalid stability version
-    .item = the stability attribute annotates this item
-
-passes_cannot_stabilize_deprecated =
-    an API can't be stabilized after it is deprecated
-    .label = invalid version
-    .item = the stability attribute annotates this item
-
-passes_invalid_deprecation_version =
-    invalid deprecation version found
-    .label = invalid deprecation version
-    .item = the stability attribute annotates this item
-
-passes_missing_stability_attr =
-    {$descr} has missing stability attribute
-
-passes_missing_const_stab_attr =
-    {$descr} has missing const stability attribute
-
-passes_trait_impl_const_stable =
-    trait implementations cannot be const stable yet
-    .note = see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
-
-passes_feature_only_on_nightly =
-    `#![feature]` may not be used on the {$release_channel} release channel
-
-passes_unknown_feature =
-    unknown feature `{$feature}`
-
-passes_implied_feature_not_exist =
-    feature `{$implied_by}` implying `{$feature}` does not exist
-
-passes_duplicate_feature_err =
-    the feature `{$feature}` has already been declared
-
-passes_missing_const_err =
-    attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
-    .help = make the function or method const
-    .label = attribute specified here
-
-passes_dead_codes =
-    { $multiple ->
-      *[true] multiple {$descr}s are
-       [false] { $num ->
-         [one] {$descr} {$name_list} is
-        *[other] {$descr}s {$name_list} are
-       }
-    } never {$participle}
-
-passes_change_fields_to_be_of_unit_type =
-    consider changing the { $num ->
-      [one] field
-     *[other] fields
-    } to be of unit type to suppress this warning while preserving the field numbering, or remove the { $num ->
-      [one] field
-     *[other] fields
+passes_outside_loop =
+    `{$name}` outside of a loop{$is_break ->
+        [true] {" or labeled block"}
+        *[false] {""}
     }
+    .label = cannot `{$name}` outside of a loop{$is_break ->
+        [true] {" or labeled block"}
+        *[false] {""}
+    }
+
+passes_params_not_allowed =
+    referencing function parameters is not allowed in naked functions
+    .help = follow the calling convention in asm block to use parameters
 
 passes_parent_info =
     {$num ->
@@ -707,48 +555,154 @@
      *[other] {$descr}s
     } in this {$parent_descr}
 
-passes_ignored_derived_impls =
-    `{$name}` has {$trait_list_len ->
-      [one] a derived impl
-     *[other] derived impls
-    } for the {$trait_list_len ->
-      [one] trait {$trait_list}, but this is
-     *[other] traits {$trait_list}, but these are
-    } intentionally ignored during dead code analysis
+passes_pass_by_value =
+    `pass_by_value` attribute should be applied to a struct, enum or type alias
+    .label = is not a struct, enum or type alias
+
+passes_plugin_registrar =
+    `#[plugin_registrar]` only has an effect on functions
 
 passes_proc_macro_bad_sig = {$kind} has incorrect signature
 
+passes_repr_conflicting =
+    conflicting representation hints
+
+passes_repr_ident =
+    meta item in `repr` must be an identifier
+
+passes_rustc_allow_const_fn_unstable =
+    attribute should be applied to `const fn`
+    .label = not a `const fn`
+
+passes_rustc_dirty_clean =
+    attribute requires -Z query-dep-graph to be enabled
+
+passes_rustc_layout_scalar_valid_range_arg =
+    expected exactly one integer literal argument
+
+passes_rustc_layout_scalar_valid_range_not_struct =
+    attribute should be applied to a struct
+    .label = not a struct
+
+passes_rustc_legacy_const_generics_index =
+    #[rustc_legacy_const_generics] must have one index for each generic parameter
+    .label = generic parameters
+
+passes_rustc_legacy_const_generics_index_exceed =
+    index exceeds number of arguments
+    .label = there {$arg_count ->
+        [one] is
+        *[other] are
+    } only {$arg_count} {$arg_count ->
+        [one] argument
+        *[other] arguments
+    }
+
+passes_rustc_legacy_const_generics_index_negative =
+    arguments should be non-negative integers
+
+passes_rustc_legacy_const_generics_only =
+    #[rustc_legacy_const_generics] functions must only have const generics
+    .label = non-const generic parameter
+
+passes_rustc_lint_opt_deny_field_access =
+    `#[rustc_lint_opt_deny_field_access]` should be applied to a field
+    .label = not a field
+
+passes_rustc_lint_opt_ty =
+    `#[rustc_lint_opt_ty]` should be applied to a struct
+    .label = not a struct
+
+passes_rustc_std_internal_symbol =
+    attribute should be applied to functions or statics
+    .label = not a function or static
+
+passes_should_be_applied_to_fn =
+    attribute should be applied to a function definition
+    .label = {$on_crate ->
+        [true] cannot be applied to crates
+        *[false] not a function definition
+    }
+
+passes_should_be_applied_to_static =
+    attribute should be applied to a static
+    .label = not a static
+
+passes_should_be_applied_to_struct_enum =
+    attribute should be applied to a struct or enum
+    .label = not a struct or enum
+
+passes_should_be_applied_to_trait =
+    attribute should be applied to a trait
+    .label = not a trait
+
+passes_size =
+    size: {$size}
+
 passes_skipping_const_checks = skipping const checks
 
-passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
+passes_stability_promotable =
+    attribute cannot be applied to an expression
 
-passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
+passes_string_interpolation_only_works = string interpolation only works in `format!` invocations
+
+passes_target_feature_on_statement =
+    {passes_should_be_applied_to_fn}
+    .warn = {-passes_previously_accepted}
+    .label = {passes_should_be_applied_to_fn.label}
+
+passes_trait_impl_const_stable =
+    trait implementations cannot be const stable yet
+    .note = see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+
+passes_transparent_incompatible =
+    transparent {$target} cannot have other repr hints
+
+passes_undefined_naked_function_abi =
+    Rust ABI is unsupported in naked functions
+
+passes_unix_sigpipe_values =
+    valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+
+passes_unknown_external_lang_item =
+    unknown external lang item: `{$lang_item}`
+
+passes_unknown_feature =
+    unknown feature `{$feature}`
+
+passes_unknown_lang_item =
+    definition of an unknown language item: `{$name}`
+    .label = definition of unknown language item `{$name}`
+
+passes_unlabeled_cf_in_while_condition =
+    `break` or `continue` with no label in the condition of a `while` loop
+    .label = unlabeled `{$cf_type}` in the condition of a `while` loop
+
+passes_unlabeled_in_labeled_block =
+    unlabeled `{$cf_type}` inside of a labeled block
+    .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
+
+passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}`
+    .suggestion = if you are using features which are still unstable, change to using `{$implies}`
+    .suggestion_remove = if you are using features which are now stable, remove this line
+
+passes_unnecessary_stable_feature = the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable
 
 passes_unreachable_due_to_uninhabited = unreachable {$descr}
     .label = unreachable {$descr}
     .label_orig = any code following this expression is unreachable
     .note = this expression has type `{$ty}`, which is uninhabited
 
-passes_unused_var_maybe_capture_ref = unused variable: `{$name}`
-    .help = did you mean to capture by reference instead?
+passes_unrecognized_field =
+    unrecognized field name `{$name}`
 
-passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
-    .help = did you mean to capture by reference instead?
+passes_unrecognized_repr_hint =
+    unrecognized representation hint
+    .help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
 
-passes_unused_var_remove_field = unused variable: `{$name}`
-passes_unused_var_remove_field_suggestion = try removing the field
-
-passes_unused_var_assigned_only = variable `{$name}` is assigned to, but never used
-    .note = consider using `_{$name}` instead
-
-passes_unnecessary_stable_feature = the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable
-
-passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}`
-    .suggestion = if you are using features which are still unstable, change to using `{$implies}`
-    .suggestion_remove = if you are using features which are now stable, remove this line
-
-passes_ineffective_unstable_impl = an `#[unstable]` annotation here has no effect
-    .note = see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
+passes_unused =
+    unused attribute
+    .suggestion = remove this attribute
 
 passes_unused_assign = value assigned to `{$name}` is never read
     .help = maybe it is overwritten before being read?
@@ -756,12 +710,58 @@
 passes_unused_assign_passed = value passed to `{$name}` is never read
     .help = maybe it is overwritten before being read?
 
-passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
-passes_string_interpolation_only_works = string interpolation only works in `format!` invocations
+passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
+    .help = did you mean to capture by reference instead?
+
+passes_unused_default_method_body_const_note =
+    `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
+
+passes_unused_duplicate =
+    unused attribute
+    .suggestion = remove this attribute
+    .note = attribute also specified here
+    .warn = {-passes_previously_accepted}
+
+passes_unused_empty_lints_note =
+    attribute `{$name}` with an empty list has no effect
+
+passes_unused_multiple =
+    multiple `{$name}` attributes
+    .suggestion = remove this attribute
+    .note = attribute also specified here
+
+passes_unused_no_lints_note =
+    attribute `{$name}` without any lints has no effect
+
+passes_unused_var_assigned_only = variable `{$name}` is assigned to, but never used
+    .note = consider using `_{$name}` instead
+
+passes_unused_var_maybe_capture_ref = unused variable: `{$name}`
+    .help = did you mean to capture by reference instead?
+
+passes_unused_var_remove_field = unused variable: `{$name}`
+passes_unused_var_remove_field_suggestion = try removing the field
+
+passes_unused_variable_try_ignore = unused variable: `{$name}`
+    .suggestion = try ignoring the field
 
 passes_unused_variable_try_prefix = unused variable: `{$name}`
     .label = unused variable
     .suggestion = if this is intentional, prefix it with an underscore
 
-passes_unused_variable_try_ignore = unused variable: `{$name}`
-    .suggestion = try ignoring the field
+passes_used_compiler_linker =
+    `used(compiler)` and `used(linker)` can't be used together
+
+passes_used_static =
+    attribute must be applied to a `static` variable
+
+passes_useless_assignment =
+    useless assignment of {$is_field_assign ->
+        [true] field
+        *[false] variable
+    } of type `{$ty}` to itself
+
+passes_useless_stability =
+    this stability annotation is useless
+    .label = useless stability annotation
+    .item = the stability attribute annotates this item
diff --git a/compiler/rustc_privacy/messages.ftl b/compiler/rustc_privacy/messages.ftl
index a26d1b2..b68e8a7 100644
--- a/compiler/rustc_privacy/messages.ftl
+++ b/compiler/rustc_privacy/messages.ftl
@@ -2,22 +2,22 @@
 privacy_field_is_private_is_update_syntax_label = field `{$field_name}` is private
 privacy_field_is_private_label = private field
 
-privacy_item_is_private = {$kind} `{$descr}` is private
-    .label = private {$kind}
-privacy_unnamed_item_is_private = {$kind} is private
-    .label = private {$kind}
+privacy_from_private_dep_in_public_interface =
+    {$kind} `{$descr}` from private dependency '{$krate}' in public interface
 
 privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interface
     .label = can't leak {$vis_descr} {$kind}
     .visibility_label = `{$descr}` declared as {$vis_descr}
 
-privacy_report_effective_visibility = {$descr}
-
-privacy_from_private_dep_in_public_interface =
-    {$kind} `{$descr}` from private dependency '{$krate}' in public interface
-
+privacy_item_is_private = {$kind} `{$descr}` is private
+    .label = private {$kind}
 privacy_private_in_public_lint =
     {$vis_descr} {$kind} `{$descr}` in public interface (error {$kind ->
         [trait] E0445
         *[other] E0446
     })
+
+privacy_report_effective_visibility = {$descr}
+
+privacy_unnamed_item_is_private = {$kind} is private
+    .label = private {$kind}
diff --git a/compiler/rustc_query_system/messages.ftl b/compiler/rustc_query_system/messages.ftl
index 0d01123..49b423d 100644
--- a/compiler/rustc_query_system/messages.ftl
+++ b/compiler/rustc_query_system/messages.ftl
@@ -1,4 +1,20 @@
-query_system_reentrant = internal compiler error: reentrant incremental verify failure, suppressing message
+query_system_cycle = cycle detected when {$stack_bottom}
+
+query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive
+
+query_system_cycle_recursive_ty_alias = type aliases cannot be recursive
+query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle
+query_system_cycle_recursive_ty_alias_help2 = see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
+
+query_system_cycle_stack_middle = ...which requires {$desc}...
+
+query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle
+
+query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again
+
+query_system_cycle_usage = cycle used when {$usage}
+
+query_system_cycle_which_requires = ...which requires {$desc}...
 
 query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node}
     .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile
@@ -6,25 +22,9 @@
 query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information
 query_system_increment_compilation_note2 = See <https://github.com/rust-lang/rust/issues/84970> for more information
 
-query_system_cycle = cycle detected when {$stack_bottom}
-
-query_system_cycle_usage = cycle used when {$usage}
-
-query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again
-
-query_system_cycle_stack_middle = ...which requires {$desc}...
-
-query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle
-
-query_system_cycle_recursive_ty_alias = type aliases cannot be recursive
-query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle
-query_system_cycle_recursive_ty_alias_help2 = see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
-
-query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive
-
-query_system_cycle_which_requires = ...which requires {$desc}...
+query_system_layout_of_depth = query depth increased by {$depth} when {$desc}
 
 query_system_query_overflow = queries overflow the depth limit!
     .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
 
-query_system_layout_of_depth = query depth increased by {$depth} when {$desc}
+query_system_reentrant = internal compiler error: reentrant incremental verify failure, suppressing message
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 345255c..539b88a 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -1,134 +1,38 @@
-resolve_parent_module_reset_for_binding =
-    parent module is reset for binding
+resolve_accessible_unsure = not sure whether the path is accessible or not
+    .note = the type may have associated items, but we are currently not checking them
+
+resolve_add_as_non_derive =
+    add as non-Derive macro
+    `#[{$macro_path}]`
 
 resolve_ampersand_used_without_explicit_lifetime_name =
     `&` without an explicit lifetime name cannot be used here
     .note = explicit lifetime name needed here
 
-resolve_underscore_lifetime_name_cannot_be_used_here =
-    `'_` cannot be used here
-    .note = `'_` is a reserved lifetime name
-
-resolve_crate_may_not_be_imported =
-    `$crate` may not be imported
-
-resolve_crate_root_imports_must_be_named_explicitly =
-    crate root imports need to be explicitly named: `use crate as name;`
-
-resolve_generic_params_from_outer_function =
-    can't use generic parameters from outer function
-    .label = use of generic parameter from outer function
-    .suggestion = try using a local generic parameter instead
-
-resolve_self_type_implicitly_declared_by_impl =
-    `Self` type implicitly declared here, by this `impl`
-
-resolve_cannot_use_self_type_here =
-    can't use `Self` here
-
-resolve_use_a_type_here_instead =
-    use a type here instead
-
-resolve_type_param_from_outer_fn =
-    type parameter from outer function
-
-resolve_const_param_from_outer_fn =
-    const parameter from outer function
-
-resolve_try_using_local_generic_parameter =
-    try using a local generic parameter instead
-
-resolve_try_adding_local_generic_param_on_method =
-    try adding a local generic parameter in this method instead
-
-resolve_help_try_using_local_generic_param =
-    try using a local generic parameter instead
-
-resolve_name_is_already_used_as_generic_parameter =
-    the name `{$name}` is already used for a generic parameter in this item's generic parameters
-    .label = already used
-    .first_use_of_name = first use of `{$name}`
-
-resolve_method_not_member_of_trait =
-    method `{$method}` is not a member of trait `{$trait_}`
-    .label = not a member of trait `{$trait_}`
-
-resolve_associated_fn_with_similar_name_exists =
-    there is an associated function with a similar name
-
-resolve_type_not_member_of_trait =
-    type `{$type_}` is not a member of trait `{$trait_}`
-    .label = not a member of trait `{$trait_}`
-
-resolve_associated_type_with_similar_name_exists =
-    there is an associated type with a similar name
-
-resolve_const_not_member_of_trait =
-    const `{$const_}` is not a member of trait `{$trait_}`
-    .label = not a member of trait `{$trait_}`
+resolve_ancestor_only =
+    visibilities can only be restricted to ancestor modules
 
 resolve_associated_const_with_similar_name_exists =
     there is an associated constant with a similar name
 
-resolve_variable_bound_with_different_mode =
-    variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
-    .label = bound in different ways
-    .first_binding_span = first binding
+resolve_associated_fn_with_similar_name_exists =
+    there is an associated function with a similar name
 
-resolve_ident_bound_more_than_once_in_parameter_list =
-    identifier `{$identifier}` is bound more than once in this parameter list
-    .label = used as parameter more than once
-
-resolve_ident_bound_more_than_once_in_same_pattern =
-    identifier `{$identifier}` is bound more than once in the same pattern
-    .label = used in a pattern more than once
-
-resolve_undeclared_label =
-    use of undeclared label `{$name}`
-    .label = undeclared label `{$name}`
-
-resolve_label_with_similar_name_reachable =
-    a label with a similar name is reachable
-
-resolve_try_using_similarly_named_label =
-    try using similarly named label
-
-resolve_unreachable_label_with_similar_name_exists =
-    a label with a similar name exists but is unreachable
-
-resolve_self_import_can_only_appear_once_in_the_list =
-    `self` import can only appear once in an import list
-    .label = can only appear once in an import list
-
-resolve_self_import_only_in_import_list_with_non_empty_prefix =
-    `self` import can only appear in an import list with a non-empty prefix
-    .label = can only appear in an import list with a non-empty prefix
-
-resolve_cannot_capture_dynamic_environment_in_fn_item =
-    can't capture dynamic environment in a fn item
-    .help = use the `|| {"{"} ... {"}"}` closure form instead
+resolve_associated_type_with_similar_name_exists =
+    there is an associated type with a similar name
 
 resolve_attempt_to_use_non_constant_value_in_constant =
     attempt to use a non-constant value in a constant
 
-resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion =
-    consider using `{$suggestion}` instead of `{$current}`
-
 resolve_attempt_to_use_non_constant_value_in_constant_label_with_suggestion =
     non-constant value
 
+resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion =
+    consider using `{$suggestion}` instead of `{$current}`
+
 resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
     this would need to be a `{$suggestion}`
 
-resolve_self_imports_only_allowed_within =
-    `self` imports are only allowed within a {"{"} {"}"} list
-
-resolve_self_imports_only_allowed_within_suggestion =
-    consider importing the module directly
-
-resolve_self_imports_only_allowed_within_multipart_suggestion =
-    alternatively, use the multi-path `use` syntax to import `self`
-
 resolve_binding_shadows_something_unacceptable =
     {$shadowing_binding}s cannot shadow {$shadowed_binding}s
     .label = cannot be named the same as {$article} {$shadowed_binding}
@@ -137,26 +41,105 @@
 resolve_binding_shadows_something_unacceptable_suggestion =
     try specify the pattern arguments
 
-resolve_forward_declared_generic_param =
-    generic parameters with a default cannot use forward declared identifiers
-    .label = defaulted generic parameters cannot be forward declared
+resolve_cannot_capture_dynamic_environment_in_fn_item =
+    can't capture dynamic environment in a fn item
+    .help = use the `|| {"{"} ... {"}"}` closure form instead
 
-resolve_param_in_ty_of_const_param =
-    the type of const parameters must not depend on other generic parameters
-    .label = the type must not depend on the parameter `{$name}`
+resolve_cannot_use_self_type_here =
+    can't use `Self` here
 
-resolve_type_param_in_ty_of_const_param =
-    type parameters may not be used in the type of const parameters
+resolve_const_not_member_of_trait =
+    const `{$const_}` is not a member of trait `{$trait_}`
+    .label = not a member of trait `{$trait_}`
+
+resolve_const_param_from_outer_fn =
+    const parameter from outer function
+
+resolve_const_param_in_enum_discriminant =
+    const parameters may not be used in enum discriminant values
+
+resolve_const_param_in_non_trivial_anon_const =
+    const parameters may only be used as standalone arguments, i.e. `{$name}`
 
 resolve_const_param_in_ty_of_const_param =
     const parameters may not be used in the type of const parameters
 
+resolve_crate_may_not_be_imported =
+    `$crate` may not be imported
+
+resolve_crate_root_imports_must_be_named_explicitly =
+    crate root imports need to be explicitly named: `use crate as name;`
+
+resolve_expected_found =
+    expected module, found {$res} `{$path_str}`
+    .label = not a module
+
+resolve_forward_declared_generic_param =
+    generic parameters with a default cannot use forward declared identifiers
+    .label = defaulted generic parameters cannot be forward declared
+
+resolve_generic_params_from_outer_function =
+    can't use generic parameters from outer function
+    .label = use of generic parameter from outer function
+    .suggestion = try using a local generic parameter instead
+
+resolve_help_try_using_local_generic_param =
+    try using a local generic parameter instead
+
+resolve_ident_bound_more_than_once_in_parameter_list =
+    identifier `{$identifier}` is bound more than once in this parameter list
+    .label = used as parameter more than once
+
+resolve_ident_bound_more_than_once_in_same_pattern =
+    identifier `{$identifier}` is bound more than once in the same pattern
+    .label = used in a pattern more than once
+
+resolve_imported_crate = `$crate` may not be imported
+
+resolve_indeterminate =
+    cannot determine resolution for the visibility
+
+resolve_invalid_asm_sym =
+    invalid `sym` operand
+    .label = is a local variable
+    .help = `sym` operands must refer to either a function or a static
+
+resolve_label_with_similar_name_reachable =
+    a label with a similar name is reachable
+
+resolve_lifetime_param_in_enum_discriminant =
+    lifetime parameters may not be used in enum discriminant values
+
+resolve_lifetime_param_in_non_trivial_anon_const =
+    lifetime parameters may not be used in const expressions
+
 resolve_lifetime_param_in_ty_of_const_param =
     lifetime parameters may not be used in the type of const parameters
 
-resolve_self_in_generic_param_default =
-    generic parameters cannot use `Self` in their defaults
-    .label = `Self` in generic parameter default
+resolve_lowercase_self =
+    attempt to use a non-constant value in a constant
+    .suggestion = try using `Self`
+
+resolve_macro_expected_found =
+    expected {$expected}, found {$found} `{$macro_path}`
+
+resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self`
+
+resolve_method_not_member_of_trait =
+    method `{$method}` is not a member of trait `{$trait_}`
+    .label = not a member of trait `{$trait_}`
+
+resolve_module_only =
+    visibility must resolve to a module
+
+resolve_name_is_already_used_as_generic_parameter =
+    the name `{$name}` is already used for a generic parameter in this item's generic parameters
+    .label = already used
+    .first_use_of_name = first use of `{$name}`
+
+resolve_param_in_enum_discriminant =
+    generic parameters may not be used in enum discriminant values
+    .label = cannot perform const operation using `{$name}`
 
 resolve_param_in_non_trivial_anon_const =
     generic parameters may not be used in const operations
@@ -165,43 +148,50 @@
 resolve_param_in_non_trivial_anon_const_help =
     use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-resolve_type_param_in_non_trivial_anon_const =
-    type parameters may not be used in const expressions
+resolve_param_in_ty_of_const_param =
+    the type of const parameters must not depend on other generic parameters
+    .label = the type must not depend on the parameter `{$name}`
 
-resolve_const_param_in_non_trivial_anon_const =
-    const parameters may only be used as standalone arguments, i.e. `{$name}`
+resolve_parent_module_reset_for_binding =
+    parent module is reset for binding
 
-resolve_lifetime_param_in_non_trivial_anon_const =
-    lifetime parameters may not be used in const expressions
+resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it
+    .help = you can define integration tests in a directory named `tests`
 
-resolve_unreachable_label =
-    use of unreachable label `{$name}`
-    .label = unreachable label `{$name}`
-    .label_definition_span = unreachable label defined here
-    .note = labels are unreachable through functions, closures, async blocks and modules
+resolve_relative_2018 =
+    relative paths are not supported in visibilities in 2018 edition or later
+    .suggestion = try
 
-resolve_unreachable_label_suggestion_use_similarly_named =
-    try using similarly named label
+resolve_remove_surrounding_derive =
+    remove from the surrounding `derive()`
 
-resolve_unreachable_label_similar_name_reachable =
-    a label with a similar name is reachable
+resolve_self_import_can_only_appear_once_in_the_list =
+    `self` import can only appear once in an import list
+    .label = can only appear once in an import list
 
-resolve_unreachable_label_similar_name_unreachable =
-    a label with a similar name exists but is also unreachable
+resolve_self_import_only_in_import_list_with_non_empty_prefix =
+    `self` import can only appear in an import list with a non-empty prefix
+    .label = can only appear in an import list with a non-empty prefix
 
-resolve_trait_impl_mismatch =
-    item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
-    .label = does not match trait
-    .label_trait_item = item in trait
+resolve_self_imports_only_allowed_within =
+    `self` imports are only allowed within a {"{"} {"}"} list
 
-resolve_invalid_asm_sym =
-    invalid `sym` operand
-    .label = is a local variable
-    .help = `sym` operands must refer to either a function or a static
+resolve_self_imports_only_allowed_within_multipart_suggestion =
+    alternatively, use the multi-path `use` syntax to import `self`
 
-resolve_lowercase_self =
-    attempt to use a non-constant value in a constant
-    .suggestion = try using `Self`
+resolve_self_imports_only_allowed_within_suggestion =
+    consider importing the module directly
+
+resolve_self_in_generic_param_default =
+    generic parameters cannot use `Self` in their defaults
+    .label = `Self` in generic parameter default
+
+resolve_self_type_implicitly_declared_by_impl =
+    `Self` type implicitly declared here, by this `impl`
+
+resolve_tool_module_imported =
+    cannot use a tool module through an import
+    .note = the tool module imported here
 
 resolve_trait_impl_duplicate =
     duplicate definitions with name `{$name}`:
@@ -209,56 +199,66 @@
     .old_span_label = previous definition here
     .trait_item_span = item in trait
 
-resolve_relative_2018 =
-    relative paths are not supported in visibilities in 2018 edition or later
-    .suggestion = try
+resolve_trait_impl_mismatch =
+    item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
+    .label = does not match trait
+    .label_trait_item = item in trait
 
-resolve_ancestor_only =
-    visibilities can only be restricted to ancestor modules
+resolve_try_adding_local_generic_param_on_method =
+    try adding a local generic parameter in this method instead
 
-resolve_expected_found =
-    expected module, found {$res} `{$path_str}`
-    .label = not a module
+resolve_try_using_local_generic_parameter =
+    try using a local generic parameter instead
 
-resolve_indeterminate =
-    cannot determine resolution for the visibility
+resolve_try_using_similarly_named_label =
+    try using similarly named label
 
-resolve_tool_module_imported =
-    cannot use a tool module through an import
-    .note = the tool module imported here
+resolve_type_not_member_of_trait =
+    type `{$type_}` is not a member of trait `{$trait_}`
+    .label = not a member of trait `{$trait_}`
 
-resolve_module_only =
-    visibility must resolve to a module
-
-resolve_macro_expected_found =
-    expected {$expected}, found {$found} `{$macro_path}`
-
-resolve_remove_surrounding_derive =
-    remove from the surrounding `derive()`
-
-resolve_add_as_non_derive =
-    add as non-Derive macro
-    `#[{$macro_path}]`
-
-resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it
-    .help = you can define integration tests in a directory named `tests`
-
-resolve_imported_crate = `$crate` may not be imported
-
-resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self`
-
-resolve_accessible_unsure = not sure whether the path is accessible or not
-    .note = the type may have associated items, but we are currently not checking them
-
-resolve_param_in_enum_discriminant =
-    generic parameters may not be used in enum discriminant values
-    .label = cannot perform const operation using `{$name}`
+resolve_type_param_from_outer_fn =
+    type parameter from outer function
 
 resolve_type_param_in_enum_discriminant =
     type parameters may not be used in enum discriminant values
 
-resolve_const_param_in_enum_discriminant =
-    const parameters may not be used in enum discriminant values
+resolve_type_param_in_non_trivial_anon_const =
+    type parameters may not be used in const expressions
 
-resolve_lifetime_param_in_enum_discriminant =
-    lifetime parameters may not be used in enum discriminant values
+resolve_type_param_in_ty_of_const_param =
+    type parameters may not be used in the type of const parameters
+
+resolve_undeclared_label =
+    use of undeclared label `{$name}`
+    .label = undeclared label `{$name}`
+
+resolve_underscore_lifetime_name_cannot_be_used_here =
+    `'_` cannot be used here
+    .note = `'_` is a reserved lifetime name
+
+resolve_unreachable_label =
+    use of unreachable label `{$name}`
+    .label = unreachable label `{$name}`
+    .label_definition_span = unreachable label defined here
+    .note = labels are unreachable through functions, closures, async blocks and modules
+
+resolve_unreachable_label_similar_name_reachable =
+    a label with a similar name is reachable
+
+resolve_unreachable_label_similar_name_unreachable =
+    a label with a similar name exists but is also unreachable
+
+resolve_unreachable_label_suggestion_use_similarly_named =
+    try using similarly named label
+
+resolve_unreachable_label_with_similar_name_exists =
+    a label with a similar name exists but is unreachable
+
+resolve_use_a_type_here_instead =
+    use a type here instead
+
+resolve_variable_bound_with_different_mode =
+    variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
+    .label = bound in different ways
+    .first_binding_span = first binding
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 7c4c05d..c1bb262 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -21,7 +21,8 @@
 use rustc_middle::span_bug;
 use rustc_middle::ty;
 use rustc_session::lint::builtin::{
-    AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS,
+    AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+    UNUSED_IMPORTS,
 };
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -526,31 +527,71 @@ pub(crate) fn finalize_imports(&mut self) {
         }
     }
 
-    pub(crate) fn check_reexport_ambiguities(
+    pub(crate) fn check_hidden_glob_reexports(
         &mut self,
         exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>,
     ) {
         for module in self.arenas.local_modules().iter() {
-            module.for_each_child(self, |this, ident, ns, binding| {
-                if let NameBindingKind::Import { import, .. } = binding.kind
-                && let Some((amb_binding, _)) = binding.ambiguity
-                && binding.res() != Res::Err
-                && exported_ambiguities.contains(&Interned::new_unchecked(binding))
-                {
-                    this.lint_buffer.buffer_lint_with_diagnostic(
-                        AMBIGUOUS_GLOB_REEXPORTS,
-                        import.root_id,
-                        import.root_span,
-                        "ambiguous glob re-exports",
-                        BuiltinLintDiagnostics::AmbiguousGlobReexports {
-                            name: ident.to_string(),
-                            namespace: ns.descr().to_string(),
-                            first_reexport_span: import.root_span,
-                            duplicate_reexport_span: amb_binding.span,
-                        },
-                    );
+            for (key, resolution) in self.resolutions(module).borrow().iter() {
+                let resolution = resolution.borrow();
+
+                if let Some(binding) = resolution.binding {
+                    if let NameBindingKind::Import { import, .. } = binding.kind
+                        && let Some((amb_binding, _)) = binding.ambiguity
+                        && binding.res() != Res::Err
+                        && exported_ambiguities.contains(&Interned::new_unchecked(binding))
+                    {
+                        self.lint_buffer.buffer_lint_with_diagnostic(
+                            AMBIGUOUS_GLOB_REEXPORTS,
+                            import.root_id,
+                            import.root_span,
+                            "ambiguous glob re-exports",
+                            BuiltinLintDiagnostics::AmbiguousGlobReexports {
+                                name: key.ident.to_string(),
+                                namespace: key.ns.descr().to_string(),
+                                first_reexport_span: import.root_span,
+                                duplicate_reexport_span: amb_binding.span,
+                            },
+                        );
+                    }
+
+                    if let Some(glob_binding) = resolution.shadowed_glob {
+                        let binding_id = match binding.kind {
+                            NameBindingKind::Res(res) => {
+                                Some(self.def_id_to_node_id[res.def_id().expect_local()])
+                            }
+                            NameBindingKind::Module(module) => {
+                                Some(self.def_id_to_node_id[module.def_id().expect_local()])
+                            }
+                            NameBindingKind::Import { import, .. } => import.id(),
+                        };
+
+                        if binding.res() != Res::Err
+                            && glob_binding.res() != Res::Err
+                            && let NameBindingKind::Import { import: glob_import, .. } = glob_binding.kind
+                            && let Some(binding_id) = binding_id
+                            && let Some(glob_import_id) = glob_import.id()
+                            && let glob_import_def_id = self.local_def_id(glob_import_id)
+                            && self.effective_visibilities.is_exported(glob_import_def_id)
+                            && glob_binding.vis.is_public()
+                            && !binding.vis.is_public()
+                        {
+                            self.lint_buffer.buffer_lint_with_diagnostic(
+                                HIDDEN_GLOB_REEXPORTS,
+                                binding_id,
+                                binding.span,
+                                "private item shadows public glob re-export",
+                                BuiltinLintDiagnostics::HiddenGlobReexports {
+                                    name: key.ident.name.to_string(),
+                                    namespace: key.ns.descr().to_owned(),
+                                    glob_reexport_span: glob_binding.span,
+                                    private_item_span: binding.span,
+                                },
+                            );
+                        }
+                    }
                 }
-            });
+            }
         }
     }
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 3d2bd84..fd977e8 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1496,8 +1496,8 @@ pub fn resolve_crate(&mut self, krate: &Crate) {
             let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || {
                 EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
             });
-            self.tcx.sess.time("check_reexport_ambiguities", || {
-                self.check_reexport_ambiguities(exported_ambiguities)
+            self.tcx.sess.time("check_hidden_glob_reexports", || {
+                self.check_hidden_glob_reexports(exported_ambiguities)
             });
             self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
             self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate));
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index a8fe560..5a0b8f9 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -1,13 +1,20 @@
-session_incorrect_cgu_reuse_type =
-    CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
-    [one] {"at least "}
-    *[other] {""}
-    }`{$expected_reuse}`
+session_binary_float_literal_not_supported = binary float literal is not supported
+session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only supported on aarch64
+
+session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+
+session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
 
 session_cgu_not_recorded =
     CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded
 
-session_feature_gate_error = {$explain}
+session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}`
+
+session_crate_name_empty = crate name must not be empty
+
+session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen
+
+session_expr_parentheses_needed = parentheses are required to parse this as an expression
 
 session_feature_diagnostic_for_issue =
     see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
@@ -15,66 +22,33 @@
 session_feature_diagnostic_help =
     add `#![feature({$feature})]` to the crate attributes to enable
 
-session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist.
-
-session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets
-
-session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist.
-
-session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`
-
-session_instrumentation_not_supported = {$us} instrumentation is not supported for this target
-
-session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
-
-session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
-
-session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
-
-session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
-
-session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
-
-session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
-
-session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
-
-session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
-
-session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
-
-session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
-
-session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
-
-session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
-
-session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only supported on aarch64
-
-session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
+session_feature_gate_error = {$explain}
 
 session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
 
-session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}`
+session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+session_incorrect_cgu_reuse_type =
+    CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
+    [one] {"at least "}
+    *[other] {""}
+    }`{$expected_reuse}`
 
-session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen
+session_instrumentation_not_supported = {$us} instrumentation is not supported for this target
 
-session_crate_name_empty = crate name must not be empty
+session_int_literal_too_large = integer literal is too large
+    .note = value exceeds limit of `{$limit}`
 
 session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}`
 
-session_expr_parentheses_needed = parentheses are required to parse this as an expression
+session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
+    .label = invalid suffix `{$suffix}`
+    .help = valid suffixes are `f32` and `f64`
 
-session_skipping_const_checks = skipping const checks
-session_unleashed_feature_help_named = skipping check for `{$gate}` feature
-session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
+session_invalid_float_literal_width = invalid width `{$width}` for float literal
+    .help = valid widths are 32 and 64
 
-session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
-session_octal_float_literal_not_supported = octal float literal is not supported
-session_binary_float_literal_not_supported = binary float literal is not supported
-session_not_supported = not supported
+session_invalid_int_literal_width = invalid width `{$width}` for integer literal
+    .help = valid widths are 8, 16, 32, 64 and 128
 
 session_invalid_literal_suffix = suffixes on {$kind} literals are invalid
     .label = invalid suffix `{$suffix}`
@@ -87,19 +61,45 @@
     .label = invalid suffix `{$suffix}`
     .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
 
-session_invalid_float_literal_width = invalid width `{$width}` for float literal
-    .help = valid widths are 32 and 64
+session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets
 
-session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
-    .label = invalid suffix `{$suffix}`
-    .help = valid suffixes are `f32` and `f64`
+session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
 
-session_int_literal_too_large = integer literal is too large
-    .note = value exceeds limit of `{$limit}`
-
-session_invalid_int_literal_width = invalid width `{$width}` for integer literal
-    .help = valid widths are 8, 16, 32, 64 and 128
-
-session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
+session_not_supported = not supported
 
 session_nul_in_c_str = null characters in C string literals are not supported
+
+session_octal_float_literal_not_supported = octal float literal is not supported
+session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
+
+session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist.
+
+session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist.
+
+session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
+
+session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
+
+session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
+
+session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
+
+session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
+
+session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
+
+session_skipping_const_checks = skipping const checks
+session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
+
+session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
+
+session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`
+
+session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
+
+session_unleashed_feature_help_named = skipping check for `{$gate}` feature
+session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
+
+session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
+
+session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 2c4c4a7..007e720 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -372,7 +372,7 @@ mod desc {
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
     pub const parse_oom_strategy: &str = "either `panic` or `abort`";
     pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`";
+    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
     pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
     pub const parse_cfguard: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -694,6 +694,7 @@ pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool
                     "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
                     "thread" => SanitizerSet::THREAD,
                     "hwaddress" => SanitizerSet::HWADDRESS,
+                    "safestack" => SanitizerSet::SAFESTACK,
                     _ => return false,
                 }
             }
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 6af43f5..5572108 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -309,7 +309,7 @@ fn rustc_terminator_to_terminator(
         Terminate => Terminator::Abort,
         Return => Terminator::Return,
         Unreachable => Terminator::Unreachable,
-        Drop { place, target, unwind } => Terminator::Drop {
+        Drop { place, target, unwind, replace: _ } => Terminator::Drop {
             place: rustc_place_to_place(place),
             target: target.as_usize(),
             unwind: rustc_unwind_to_unwind(unwind),
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 6755657..b219fde 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1147,7 +1147,6 @@ pub enum DesugaringKind {
     Await,
     ForLoop,
     WhileLoop,
-    Replace,
 }
 
 impl DesugaringKind {
@@ -1163,7 +1162,6 @@ pub fn descr(self) -> &'static str {
             DesugaringKind::OpaqueTy => "`impl Trait`",
             DesugaringKind::ForLoop => "`for` loop",
             DesugaringKind::WhileLoop => "`while` loop",
-            DesugaringKind::Replace => "drop and replace",
         }
     }
 }
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 4cccc63..55901bf 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -274,7 +274,7 @@ fn print_impl_path(
 
         let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id);
         if !substs.is_empty() {
-            param_env = EarlyBinder(param_env).subst(self.tcx, substs);
+            param_env = EarlyBinder::new(param_env).subst(self.tcx, substs);
         }
 
         match &mut impl_trait_ref {
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
index 2b135b6..e2df7e0 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -2,7 +2,7 @@
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let llvm_target = "arm64-apple-ios-macabi";
+    let llvm_target = "arm64-apple-ios14.0-macabi";
 
     let arch = Arch::Arm64_macabi;
     let mut base = opts("ios", arch);
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index ba4b89c..62f9420 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -815,6 +815,7 @@ pub struct SanitizerSet: u16 {
         const SHADOWCALLSTACK = 1 << 7;
         const KCFI    = 1 << 8;
         const KERNELADDRESS = 1 << 9;
+        const SAFESTACK = 1 << 10;
     }
 }
 
@@ -831,6 +832,7 @@ pub fn as_str(self) -> Option<&'static str> {
             SanitizerSet::LEAK => "leak",
             SanitizerSet::MEMORY => "memory",
             SanitizerSet::MEMTAG => "memtag",
+            SanitizerSet::SAFESTACK => "safestack",
             SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
             SanitizerSet::THREAD => "thread",
             SanitizerSet::HWADDRESS => "hwaddress",
@@ -871,6 +873,7 @@ fn into_iter(self) -> Self::IntoIter {
             SanitizerSet::THREAD,
             SanitizerSet::HWADDRESS,
             SanitizerSet::KERNELADDRESS,
+            SanitizerSet::SAFESTACK,
         ]
         .iter()
         .copied()
@@ -2364,6 +2367,7 @@ macro_rules! key {
                                 Some("leak") => SanitizerSet::LEAK,
                                 Some("memory") => SanitizerSet::MEMORY,
                                 Some("memtag") => SanitizerSet::MEMTAG,
+                                Some("safestack") => SanitizerSet::SAFESTACK,
                                 Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
                                 Some("thread") => SanitizerSet::THREAD,
                                 Some("hwaddress") => SanitizerSet::HWADDRESS,
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index 5a3e2a7..9f3b0fa 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -2,7 +2,7 @@
 use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let llvm_target = "x86_64-apple-ios-macabi";
+    let llvm_target = "x86_64-apple-ios14.0-macabi";
 
     let arch = Arch::X86_64_macabi;
     let mut base = opts("ios", arch);
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
index cb62a81..d2906d6 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
@@ -7,7 +7,7 @@ pub fn target() -> Target {
     base.vendor = "pc".into();
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::X86;
-    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
 
     Target {
         llvm_target: "x86_64-pc-solaris".into(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
index 04a12a7..ca5b62e 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
@@ -5,7 +5,7 @@ pub fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64", "-std=c99"]);
     base.cpu = "x86-64".into();
     base.max_atomic_width = Some(64);
-    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
 
     Target {
         // LLVM does not currently have a separate illumos target,
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
index 9af1049..deb15c0 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -11,6 +11,7 @@ pub fn target() -> Target {
         | SanitizerSet::CFI
         | SanitizerSet::LEAK
         | SanitizerSet::MEMORY
+        | SanitizerSet::SAFESTACK
         | SanitizerSet::THREAD;
     base.supports_xray = true;
 
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 8fea3fc..217ba71 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -1,17 +1,13 @@
 trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
 
-trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
-
 trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
     .label = empty on-clause here
 
+trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
+
 trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]`
     .label = invalid on-clause here
 
-trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value
-    .label = expected value here
-    .note = eg `#[rustc_on_unimplemented(message="foo")]`
-
 trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
         [none] {""}
        *[default] {" "}for type `{$self_desc}`
@@ -21,4 +17,8 @@
     .positive_implementation_here = positive implementation here
     .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`
 
-trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
+trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value
+    .label = expected value here
+    .note = eg `#[rustc_on_unimplemented(message="foo")]`
+
+trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 142c200..312bd38 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -5,7 +5,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
-use rustc_middle::traits::query::Fallible;
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_middle::ty::{GenericArg, ToPredicate};
 use rustc_span::DUMMY_SP;
@@ -82,8 +82,8 @@ pub trait InferCtxtBuilderExt<'tcx> {
     fn enter_canonical_trait_query<K, R>(
         &mut self,
         canonical_key: &Canonical<'tcx, K>,
-        operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, R>>
+        operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
+    ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
     where
         K: TypeFoldable<TyCtxt<'tcx>>,
         R: Debug + TypeFoldable<TyCtxt<'tcx>>,
@@ -110,8 +110,8 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
     fn enter_canonical_trait_query<K, R>(
         &mut self,
         canonical_key: &Canonical<'tcx, K>,
-        operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, R>>
+        operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
+    ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
     where
         K: TypeFoldable<TyCtxt<'tcx>>,
         R: Debug + TypeFoldable<TyCtxt<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 0ede32c..1071b8f 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -148,11 +148,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
 
         ty::Adt(def, substs) => {
             let sized_crit = def.sized_constraint(ecx.tcx());
-            Ok(sized_crit
-                .0
-                .iter()
-                .map(|ty| sized_crit.rebind(*ty).subst(ecx.tcx(), substs))
-                .collect())
+            Ok(sized_crit.subst_iter_copied(ecx.tcx(), substs).collect())
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 26ace28f..56a254d 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -231,13 +231,21 @@ enum Invert {
 
                 let mut candidates = Vec::new();
                 // LHS normalizes-to RHS
-                candidates.extend(
-                    evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No).ok(),
-                );
+                candidates.extend(evaluate_normalizes_to(
+                    self,
+                    alias_lhs,
+                    rhs,
+                    direction,
+                    Invert::No,
+                ));
                 // RHS normalizes-to RHS
-                candidates.extend(
-                    evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(),
-                );
+                candidates.extend(evaluate_normalizes_to(
+                    self,
+                    alias_rhs,
+                    lhs,
+                    direction,
+                    Invert::Yes,
+                ));
                 // Relate via substs
                 let subst_relate_response = self.probe(|ecx| {
                     let span = tracing::span!(
@@ -265,10 +273,18 @@ enum Invert {
 
                 if let Some(merged) = self.try_merge_responses(&candidates) {
                     Ok(merged)
-                } else if let Ok(subst_relate_response) = subst_relate_response {
-                    Ok(subst_relate_response)
                 } else {
-                    self.flounder(&candidates)
+                    // When relating two aliases and we have ambiguity, we prefer
+                    // relating the generic arguments of the aliases over normalizing
+                    // them. This is necessary for inference during typeck.
+                    //
+                    // As this is incomplete, we must not do so during coherence.
+                    match (self.solver_mode(), subst_relate_response) {
+                        (SolverMode::Normal, Ok(response)) => Ok(response),
+                        (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => {
+                            self.flounder(&candidates)
+                        }
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 000427b..2c5ffd6 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -14,11 +14,11 @@
 };
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
-use rustc_infer::traits::query::Fallible;
 use rustc_infer::traits::{
     FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
 };
 use rustc_middle::arena::ArenaAllocatable;
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeFoldable;
@@ -235,7 +235,7 @@ pub fn make_canonicalized_query_response<T>(
         &self,
         inference_vars: CanonicalVarValues<'tcx>,
         answer: T,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
+    ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
     where
         T: Debug + TypeFoldable<TyCtxt<'tcx>>,
         Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 2f85c32..88d2091 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -116,6 +116,7 @@ fn select(&mut self, selcx: SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<
 }
 
 impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
+    #[inline]
     fn register_predicate_obligation(
         &mut self,
         infcx: &InferCtxt<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index f265230..0f84032 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -14,10 +14,12 @@
 pub mod outlives_bounds;
 mod project;
 pub mod query;
+#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
 mod select;
 mod specialize;
 mod structural_match;
 mod structural_normalize;
+#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
 mod util;
 mod vtable;
 pub mod wf;
@@ -485,7 +487,7 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 tcx,
                 ObligationCause::dummy_with_span(*span),
                 param_env,
-                ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
+                ty::EarlyBinder::new(*pred).subst(tcx, impl_trait_ref.substs),
             )
         })
     });
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index c81bf6e..0be2115 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -642,7 +642,7 @@ fn receiver_for_self_ty<'tcx>(
         if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
     });
 
-    let result = EarlyBinder(receiver_ty).subst(tcx, substs);
+    let result = EarlyBinder::new(receiver_ty).subst(tcx, substs);
     debug!(
         "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
         receiver_ty, self_ty, method_def_id, result
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 0db8023..f8d056e 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -1,9 +1,9 @@
 use crate::infer::InferCtxt;
-use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
-use crate::traits::query::NoSolution;
 use crate::traits::{ObligationCause, ObligationCtxt};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_infer::infer::InferOk;
+use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
 use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
 use rustc_span::def_id::LocalDefId;
 
@@ -68,24 +68,29 @@ fn implied_outlives_bounds(
             return vec![];
         }
 
-        let span = self.tcx.def_span(body_id);
-        let result = param_env
-            .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
-            .fully_perform(self);
-        let result = match result {
-            Ok(r) => r,
-            Err(NoSolution) => {
-                self.tcx.sess.delay_span_bug(
-                    span,
-                    "implied_outlives_bounds failed to solve all obligations",
-                );
-                return vec![];
-            }
+        let mut canonical_var_values = OriginalQueryValues::default();
+        let canonical_ty =
+            self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values);
+        let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else {
+            return vec![];
         };
 
-        let TypeOpOutput { output, constraints, .. } = result;
+        let mut constraints = QueryRegionConstraints::default();
+        let Ok(InferOk { value, obligations }) = self
+            .instantiate_nll_query_response_and_region_obligations(
+                &ObligationCause::dummy(),
+                param_env,
+                &canonical_var_values,
+                canonical_result,
+                &mut constraints,
+            ) else {
+            return vec![];
+        };
+        assert_eq!(&obligations, &[]);
 
-        if let Some(constraints) = constraints {
+        if !constraints.is_empty() {
+            let span = self.tcx.def_span(body_id);
+
             debug!(?constraints);
             if !constraints.member_constraints.is_empty() {
                 span_bug!(span, "{:#?}", constraints.member_constraints);
@@ -112,7 +117,7 @@ fn implied_outlives_bounds(
             }
         };
 
-        output
+        value
     }
 
     fn implied_bounds_tys(
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 455b53b..0a1b1b1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -1,6 +1,11 @@
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use crate::traits::query::normalize::QueryNormalizeExt;
+use crate::traits::query::NoSolution;
+use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
 
-pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
+use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
+use rustc_span::source_map::{Span, DUMMY_SP};
 
 /// This returns true if the type `ty` is "trivial" for
 /// dropck-outlives -- that is, if it doesn't require any types to
@@ -71,3 +76,263 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Generator(..) => false,
     }
 }
+
+pub fn compute_dropck_outlives_inner<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
+    goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
+    let tcx = ocx.infcx.tcx;
+    let ParamEnvAnd { param_env, value: for_ty } = goal;
+
+    let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
+
+    // A stack of types left to process. Each round, we pop
+    // something from the stack and invoke
+    // `dtorck_constraint_for_ty_inner`. This may produce new types that
+    // have to be pushed on the stack. This continues until we have explored
+    // all the reachable types from the type `for_ty`.
+    //
+    // Example: Imagine that we have the following code:
+    //
+    // ```rust
+    // struct A {
+    //     value: B,
+    //     children: Vec<A>,
+    // }
+    //
+    // struct B {
+    //     value: u32
+    // }
+    //
+    // fn f() {
+    //   let a: A = ...;
+    //   ..
+    // } // here, `a` is dropped
+    // ```
+    //
+    // at the point where `a` is dropped, we need to figure out
+    // which types inside of `a` contain region data that may be
+    // accessed by any destructors in `a`. We begin by pushing `A`
+    // onto the stack, as that is the type of `a`. We will then
+    // invoke `dtorck_constraint_for_ty_inner` which will expand `A`
+    // into the types of its fields `(B, Vec<A>)`. These will get
+    // pushed onto the stack. Eventually, expanding `Vec<A>` will
+    // lead to us trying to push `A` a second time -- to prevent
+    // infinite recursion, we notice that `A` was already pushed
+    // once and stop.
+    let mut ty_stack = vec![(for_ty, 0)];
+
+    // Set used to detect infinite recursion.
+    let mut ty_set = FxHashSet::default();
+
+    let cause = ObligationCause::dummy();
+    let mut constraints = DropckConstraint::empty();
+    while let Some((ty, depth)) = ty_stack.pop() {
+        debug!(
+            "{} kinds, {} overflows, {} ty_stack",
+            result.kinds.len(),
+            result.overflows.len(),
+            ty_stack.len()
+        );
+        dtorck_constraint_for_ty_inner(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
+
+        // "outlives" represent types/regions that may be touched
+        // by a destructor.
+        result.kinds.append(&mut constraints.outlives);
+        result.overflows.append(&mut constraints.overflows);
+
+        // If we have even one overflow, we should stop trying to evaluate further --
+        // chances are, the subsequent overflows for this evaluation won't provide useful
+        // information and will just decrease the speed at which we can emit these errors
+        // (since we'll be printing for just that much longer for the often enormous types
+        // that result here).
+        if !result.overflows.is_empty() {
+            break;
+        }
+
+        // dtorck types are "types that will get dropped but which
+        // do not themselves define a destructor", more or less. We have
+        // to push them onto the stack to be expanded.
+        for ty in constraints.dtorck_types.drain(..) {
+            let Normalized { value: ty, obligations } =
+                ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
+            ocx.register_obligations(obligations);
+
+            debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+
+            match ty.kind() {
+                // All parameters live for the duration of the
+                // function.
+                ty::Param(..) => {}
+
+                // A projection that we couldn't resolve - it
+                // might have a destructor.
+                ty::Alias(..) => {
+                    result.kinds.push(ty.into());
+                }
+
+                _ => {
+                    if ty_set.insert(ty) {
+                        ty_stack.push((ty, depth + 1));
+                    }
+                }
+            }
+        }
+    }
+
+    debug!("dropck_outlives: result = {:#?}", result);
+    Ok(result)
+}
+
+/// Returns a set of constraints that needs to be satisfied in
+/// order for `ty` to be valid for destruction.
+pub fn dtorck_constraint_for_ty_inner<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    span: Span,
+    for_ty: Ty<'tcx>,
+    depth: usize,
+    ty: Ty<'tcx>,
+    constraints: &mut DropckConstraint<'tcx>,
+) -> Result<(), NoSolution> {
+    debug!("dtorck_constraint_for_ty_inner({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
+
+    if !tcx.recursion_limit().value_within_limit(depth) {
+        constraints.overflows.push(ty);
+        return Ok(());
+    }
+
+    if trivial_dropck_outlives(tcx, ty) {
+        return Ok(());
+    }
+
+    match ty.kind() {
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Str
+        | ty::Never
+        | ty::Foreign(..)
+        | ty::RawPtr(..)
+        | ty::Ref(..)
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::GeneratorWitness(..)
+        | ty::GeneratorWitnessMIR(..) => {
+            // these types never have a destructor
+        }
+
+        ty::Array(ety, _) | ty::Slice(ety) => {
+            // single-element containers, behave like their element
+            rustc_data_structures::stack::ensure_sufficient_stack(|| {
+                dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, *ety, constraints)
+            })?;
+        }
+
+        ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
+            for ty in tys.iter() {
+                dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
+            }
+            Ok::<_, NoSolution>(())
+        })?,
+
+        ty::Closure(_, substs) => {
+            if !substs.as_closure().is_valid() {
+                // By the time this code runs, all type variables ought to
+                // be fully resolved.
+
+                tcx.sess.delay_span_bug(
+                    span,
+                    format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
+                );
+                return Err(NoSolution);
+            }
+
+            rustc_data_structures::stack::ensure_sufficient_stack(|| {
+                for ty in substs.as_closure().upvar_tys() {
+                    dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
+                }
+                Ok::<_, NoSolution>(())
+            })?
+        }
+
+        ty::Generator(_, substs, _movability) => {
+            // rust-lang/rust#49918: types can be constructed, stored
+            // in the interior, and sit idle when generator yields
+            // (and is subsequently dropped).
+            //
+            // It would be nice to descend into interior of a
+            // generator to determine what effects dropping it might
+            // have (by looking at any drop effects associated with
+            // its interior).
+            //
+            // However, the interior's representation uses things like
+            // GeneratorWitness that explicitly assume they are not
+            // traversed in such a manner. So instead, we will
+            // simplify things for now by treating all generators as
+            // if they were like trait objects, where its upvars must
+            // all be alive for the generator's (potential)
+            // destructor.
+            //
+            // In particular, skipping over `_interior` is safe
+            // because any side-effects from dropping `_interior` can
+            // only take place through references with lifetimes
+            // derived from lifetimes attached to the upvars and resume
+            // argument, and we *do* incorporate those here.
+
+            if !substs.as_generator().is_valid() {
+                // By the time this code runs, all type variables ought to
+                // be fully resolved.
+                tcx.sess.delay_span_bug(
+                    span,
+                    format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
+                );
+                return Err(NoSolution);
+            }
+
+            constraints.outlives.extend(
+                substs
+                    .as_generator()
+                    .upvar_tys()
+                    .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }),
+            );
+            constraints.outlives.push(substs.as_generator().resume_ty().into());
+        }
+
+        ty::Adt(def, substs) => {
+            let DropckConstraint { dtorck_types, outlives, overflows } =
+                tcx.at(span).adt_dtorck_constraint(def.did())?;
+            // FIXME: we can try to recursively `dtorck_constraint_on_ty`
+            // there, but that needs some way to handle cycles.
+            constraints
+                .dtorck_types
+                .extend(dtorck_types.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs)));
+            constraints
+                .outlives
+                .extend(outlives.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs)));
+            constraints
+                .overflows
+                .extend(overflows.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs)));
+        }
+
+        // Objects must be alive in order for their destructor
+        // to be called.
+        ty::Dynamic(..) => {
+            constraints.outlives.push(ty.into());
+        }
+
+        // Types that can't be resolved. Pass them forward.
+        ty::Alias(..) | ty::Param(..) => {
+            constraints.dtorck_types.push(ty);
+        }
+
+        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
+            // By the time this code runs, all type variables ought to
+            // be fully resolved.
+            return Err(NoSolution);
+        }
+    }
+
+    Ok(())
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
index e6db96c..01d7a1e7 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
@@ -1,8 +1,13 @@
 use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
-use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+use crate::traits::ObligationCtxt;
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+use rustc_infer::traits::Obligation;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserSelfTy, UserSubsts, UserType};
 
 pub use rustc_middle::traits::query::type_op::AscribeUserType;
+use rustc_span::{Span, DUMMY_SP};
 
 impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
     type QueryResponse = ();
@@ -17,7 +22,119 @@ fn try_fast_path(
     fn perform_query(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
         tcx.type_op_ascribe_user_type(canonicalized)
     }
+
+    fn perform_locally_in_new_solver(
+        ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        type_op_ascribe_user_type_with_span(ocx, key, None)
+    }
+}
+
+/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
+/// this query can be re-run to better track the span of the obligation cause, and improve the error
+/// message. Do not call directly unless you're in that very specific context.
+pub fn type_op_ascribe_user_type_with_span<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
+    key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
+    span: Option<Span>,
+) -> Result<(), NoSolution> {
+    let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
+    debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
+    let span = span.unwrap_or(DUMMY_SP);
+    match user_ty {
+        UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
+        UserType::TypeOf(def_id, user_substs) => {
+            relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
+        }
+    };
+    Ok(())
+}
+
+#[instrument(level = "debug", skip(ocx, param_env, span))]
+fn relate_mir_and_user_ty<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    span: Span,
+    mir_ty: Ty<'tcx>,
+    user_ty: Ty<'tcx>,
+) -> Result<(), NoSolution> {
+    let cause = ObligationCause::dummy_with_span(span);
+    let user_ty = ocx.normalize(&cause, param_env, user_ty);
+    ocx.eq(&cause, param_env, mir_ty, user_ty)?;
+
+    // FIXME(#104764): We should check well-formedness before normalization.
+    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
+    ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
+    Ok(())
+}
+
+#[instrument(level = "debug", skip(ocx, param_env, span))]
+fn relate_mir_and_user_substs<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    span: Span,
+    mir_ty: Ty<'tcx>,
+    def_id: DefId,
+    user_substs: UserSubsts<'tcx>,
+) -> Result<(), NoSolution> {
+    let param_env = param_env.without_const();
+    let UserSubsts { user_self_ty, substs } = user_substs;
+    let tcx = ocx.infcx.tcx;
+    let cause = ObligationCause::dummy_with_span(span);
+
+    let ty = tcx.type_of(def_id).subst(tcx, substs);
+    let ty = ocx.normalize(&cause, param_env, ty);
+    debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
+
+    ocx.eq(&cause, param_env, mir_ty, ty)?;
+
+    // Prove the predicates coming along with `def_id`.
+    //
+    // Also, normalize the `instantiated_predicates`
+    // because otherwise we wind up with duplicate "type
+    // outlives" error messages.
+    let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
+
+    debug!(?instantiated_predicates);
+    for (instantiated_predicate, predicate_span) in instantiated_predicates {
+        let span = if span == DUMMY_SP { predicate_span } else { span };
+        let cause = ObligationCause::new(
+            span,
+            CRATE_DEF_ID,
+            ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
+        );
+        let instantiated_predicate =
+            ocx.normalize(&cause.clone(), param_env, instantiated_predicate);
+
+        ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
+    }
+
+    if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
+        let self_ty = ocx.normalize(&cause, param_env, self_ty);
+        let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs);
+        let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
+
+        ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
+        let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
+        ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
+    }
+
+    // In addition to proving the predicates, we have to
+    // prove that `ty` is well-formed -- this is because
+    // the WF of `ty` is predicated on the substs being
+    // well-formed, and we haven't proven *that*. We don't
+    // want to prove the WF of types from  `substs` directly because they
+    // haven't been normalized.
+    //
+    // FIXME(nmatsakis): Well, perhaps we should normalize
+    // them?  This would only be relevant if some input
+    // type were ill-formed but did not appear in `ty`,
+    // which...could happen with normalization...
+    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
+    ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
+    Ok(())
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 3d6c1d9..6d8d210 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,11 +1,12 @@
 use crate::infer::canonical::query_response;
 use crate::infer::InferCtxt;
 use crate::traits::query::type_op::TypeOpOutput;
-use crate::traits::query::Fallible;
 use crate::traits::ObligationCtxt;
+use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_middle::traits::query::NoSolution;
 use rustc_span::source_map::DUMMY_SP;
+use rustc_span::Span;
 
 use std::fmt;
 
@@ -17,7 +18,7 @@ pub struct CustomTypeOp<F> {
 impl<F> CustomTypeOp<F> {
     pub fn new<'tcx, R>(closure: F, description: &'static str) -> Self
     where
-        F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>,
+        F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
     {
         CustomTypeOp { closure, description }
     }
@@ -25,7 +26,7 @@ pub fn new<'tcx, R>(closure: F, description: &'static str) -> Self
 
 impl<'tcx, F, R: fmt::Debug> super::TypeOp<'tcx> for CustomTypeOp<F>
 where
-    F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>,
+    F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
 {
     type Output = R;
     /// We can't do any custom error reporting for `CustomTypeOp`, so
@@ -35,12 +36,16 @@ impl<'tcx, F, R: fmt::Debug> super::TypeOp<'tcx> for CustomTypeOp<F>
     /// Processes the operation and all resulting obligations,
     /// returning the final result along with any region constraints
     /// (they will be given over to the NLL region solver).
-    fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+    fn fully_perform(
+        self,
+        infcx: &InferCtxt<'tcx>,
+        span: Span,
+    ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
         if cfg!(debug_assertions) {
             info!("fully_perform({:?})", self);
         }
 
-        Ok(scrape_region_constraints(infcx, self.closure)?.0)
+        Ok(scrape_region_constraints(infcx, self.closure, self.description, span)?.0)
     }
 }
 
@@ -54,8 +59,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// constraints that result, creating query-region-constraints.
 pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     infcx: &InferCtxt<'tcx>,
-    op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Fallible<R>,
-) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
+    op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
+    name: &'static str,
+    span: Span,
+) -> Result<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>), ErrorGuaranteed> {
     // During NLL, we expect that nobody will register region
     // obligations **except** as part of a custom type op (and, at the
     // end of each custom type op, we scrape out the region
@@ -70,16 +77,17 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
 
     let value = infcx.commit_if_ok(|_| {
         let ocx = ObligationCtxt::new_in_snapshot(infcx);
-        let value = op(&ocx)?;
+        let value = op(&ocx).map_err(|_| {
+            infcx.tcx.sess.delay_span_bug(span, format!("error performing operation: {name}"))
+        })?;
         let errors = ocx.select_all_or_error();
         if errors.is_empty() {
             Ok(value)
         } else {
-            infcx.tcx.sess.delay_span_bug(
+            Err(infcx.tcx.sess.delay_span_bug(
                 DUMMY_SP,
                 format!("errors selecting obligation during MIR typeck: {:?}", errors),
-            );
-            Err(NoSolution)
+            ))
         }
     })?;
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
index 8c9b961..f658930 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
@@ -1,5 +1,7 @@
 use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 
 pub use rustc_middle::traits::query::type_op::Eq;
@@ -17,7 +19,15 @@ fn try_fast_path(
     fn perform_query(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
         tcx.type_op_eq(canonicalized)
     }
+
+    fn perform_locally_in_new_solver(
+        ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        ocx.eq(&ObligationCause::dummy(), key.param_env, key.value.a, key.value.b)?;
+        Ok(())
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 18d7c9b1..9989fc9 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -1,7 +1,15 @@
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::query::NoSolution;
+use crate::traits::wf;
+use crate::traits::ObligationCtxt;
+
+use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_infer::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::infer::canonical::CanonicalQueryResponse;
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::def_id::CRATE_DEF_ID;
+use rustc_span::source_map::DUMMY_SP;
+use smallvec::{smallvec, SmallVec};
 
 #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct ImpliedOutlivesBounds<'tcx> {
@@ -28,7 +36,7 @@ fn try_fast_path(
     fn perform_query(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
         // FIXME this `unchecked_map` is only necessary because the
         // query is defined as taking a `ParamEnvAnd<Ty>`; it should
         // take an `ImpliedOutlivesBounds` instead
@@ -39,4 +47,169 @@ fn perform_query(
 
         tcx.implied_outlives_bounds(canonicalized)
     }
+
+    fn perform_locally_in_new_solver(
+        ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty)
+    }
+}
+
+pub fn compute_implied_outlives_bounds_inner<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
+    let tcx = ocx.infcx.tcx;
+
+    // Sometimes when we ask what it takes for T: WF, we get back that
+    // U: WF is required; in that case, we push U onto this stack and
+    // process it next. Because the resulting predicates aren't always
+    // guaranteed to be a subset of the original type, so we need to store the
+    // WF args we've computed in a set.
+    let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
+    let mut wf_args = vec![ty.into()];
+
+    let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
+        vec![];
+
+    while let Some(arg) = wf_args.pop() {
+        if !checked_wf_args.insert(arg) {
+            continue;
+        }
+
+        // Compute the obligations for `arg` to be well-formed. If `arg` is
+        // an unresolved inference variable, just substituted an empty set
+        // -- because the return type here is going to be things we *add*
+        // to the environment, it's always ok for this set to be smaller
+        // than the ultimate set. (Note: normally there won't be
+        // unresolved inference variables here anyway, but there might be
+        // during typeck under some circumstances.)
+        //
+        // FIXME(@lcnr): It's not really "always fine", having fewer implied
+        // bounds can be backward incompatible, e.g. #101951 was caused by
+        // us not dealing with inference vars in `TypeOutlives` predicates.
+        let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
+            .unwrap_or_default();
+
+        for obligation in obligations {
+            debug!(?obligation);
+            assert!(!obligation.has_escaping_bound_vars());
+
+            // While these predicates should all be implied by other parts of
+            // the program, they are still relevant as they may constrain
+            // inference variables, which is necessary to add the correct
+            // implied bounds in some cases, mostly when dealing with projections.
+            //
+            // Another important point here: we only register `Projection`
+            // predicates, since otherwise we might register outlives
+            // predicates containing inference variables, and we don't
+            // learn anything new from those.
+            if obligation.predicate.has_non_region_infer() {
+                match obligation.predicate.kind().skip_binder() {
+                    ty::PredicateKind::Clause(ty::Clause::Projection(..))
+                    | ty::PredicateKind::AliasRelate(..) => {
+                        ocx.register_obligation(obligation.clone());
+                    }
+                    _ => {}
+                }
+            }
+
+            let pred = match obligation.predicate.kind().no_bound_vars() {
+                None => continue,
+                Some(pred) => pred,
+            };
+            match pred {
+                ty::PredicateKind::Clause(ty::Clause::Trait(..))
+                // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
+                // if we ever support that
+                | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::Clause(ty::Clause::Projection(..))
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Ambiguous
+                | ty::PredicateKind::AliasRelate(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+
+                // We need to search through *all* WellFormed predicates
+                ty::PredicateKind::WellFormed(arg) => {
+                    wf_args.push(arg);
+                }
+
+                // We need to register region relationships
+                ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
+                    r_a,
+                    r_b,
+                ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
+
+                ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+                    ty_a,
+                    r_b,
+                ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)),
+            }
+        }
+    }
+
+    // This call to `select_all_or_error` is necessary to constrain inference variables, which we
+    // use further down when computing the implied bounds.
+    match ocx.select_all_or_error().as_slice() {
+        [] => (),
+        _ => return Err(NoSolution),
+    }
+
+    // We lazily compute the outlives components as
+    // `select_all_or_error` constrains inference variables.
+    let implied_bounds = outlives_bounds
+        .into_iter()
+        .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
+            ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
+            ty::GenericArgKind::Type(ty_a) => {
+                let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
+                let mut components = smallvec![];
+                push_outlives_components(tcx, ty_a, &mut components);
+                implied_bounds_from_components(r_b, components)
+            }
+            ty::GenericArgKind::Const(_) => unreachable!(),
+        })
+        .collect();
+
+    Ok(implied_bounds)
+}
+
+/// When we have an implied bound that `T: 'a`, we can further break
+/// this down to determine what relationships would have to hold for
+/// `T: 'a` to hold. We get to assume that the caller has validated
+/// those relationships.
+fn implied_bounds_from_components<'tcx>(
+    sub_region: ty::Region<'tcx>,
+    sup_components: SmallVec<[Component<'tcx>; 4]>,
+) -> Vec<OutlivesBound<'tcx>> {
+    sup_components
+        .into_iter()
+        .filter_map(|component| {
+            match component {
+                Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
+                Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
+                Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
+                Component::EscapingAlias(_) =>
+                // If the projection has escaping regions, don't
+                // try to infer any implied bounds even for its
+                // free components. This is conservative, because
+                // the caller will still have to prove that those
+                // free components outlive `sub_region`. But the
+                // idea is that the WAY that the caller proves
+                // that may change in the future and we want to
+                // give ourselves room to get smarter here.
+                {
+                    None
+                }
+                Component::UnresolvedInferenceVariable(..) => None,
+            }
+        })
+        .collect()
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 9e8bc8b..642fdec 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -2,13 +2,14 @@
     Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
 };
 use crate::infer::{InferCtxt, InferOk};
-use crate::traits::query::Fallible;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, ObligationCtxt};
+use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::canonical::Certainty;
-use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::PredicateObligations;
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+use rustc_span::Span;
 use std::fmt;
 
 pub mod ascribe_user_type;
@@ -22,6 +23,8 @@
 
 pub use rustc_middle::traits::query::type_op::*;
 
+use self::custom::scrape_region_constraints;
+
 /// "Type ops" are used in NLL to perform some particular action and
 /// extract out the resulting region constraints (or an error if it
 /// cannot be completed).
@@ -32,7 +35,11 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
     /// Processes the operation and all resulting obligations,
     /// returning the final result along with any region constraints
     /// (they will be given over to the NLL region solver).
-    fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>;
+    fn fully_perform(
+        self,
+        infcx: &InferCtxt<'tcx>,
+        span: Span,
+    ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed>;
 }
 
 /// The output from performing a type op
@@ -74,18 +81,32 @@ fn try_fast_path(
     fn perform_query(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>>;
+    ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution>;
+
+    /// In the new trait solver, we already do caching in the solver itself,
+    /// so there's no need to canonicalize and cache via the query system.
+    /// Additionally, even if we were to canonicalize, we'd still need to
+    /// make sure to feed it predefined opaque types and the defining anchor
+    /// and that would require duplicating all of the tcx queries. Instead,
+    /// just perform these ops locally.
+    fn perform_locally_in_new_solver(
+        ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+    ) -> Result<Self::QueryResponse, NoSolution>;
 
     fn fully_perform_into(
         query_key: ParamEnvAnd<'tcx, Self>,
         infcx: &InferCtxt<'tcx>,
         output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
-    ) -> Fallible<(
-        Self::QueryResponse,
-        Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
-        PredicateObligations<'tcx>,
-        Certainty,
-    )> {
+    ) -> Result<
+        (
+            Self::QueryResponse,
+            Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
+            PredicateObligations<'tcx>,
+            Certainty,
+        ),
+        NoSolution,
+    > {
         if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
             return Ok((result, None, vec![], Certainty::Proven));
         }
@@ -120,10 +141,26 @@ impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q>
     type Output = Q::QueryResponse;
     type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>;
 
-    fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+    fn fully_perform(
+        self,
+        infcx: &InferCtxt<'tcx>,
+        span: Span,
+    ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
+        if infcx.tcx.trait_solver_next() {
+            return Ok(scrape_region_constraints(
+                infcx,
+                |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self),
+                "query type op",
+                span,
+            )?
+            .0);
+        }
+
         let mut region_constraints = QueryRegionConstraints::default();
         let (output, error_info, mut obligations, _) =
-            Q::fully_perform_into(self, infcx, &mut region_constraints)?;
+            Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
+                infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}"))
+            })?;
 
         // Typically, instantiating NLL query results does not
         // create obligations. However, in some cases there
@@ -151,7 +188,10 @@ fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, S
                 }
             }
             if !progress {
-                return Err(NoSolution);
+                return Err(infcx.tcx.sess.delay_span_bug(
+                    span,
+                    format!("ambiguity processing {obligations:?} from {self:?}"),
+                ));
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index 5b216c0..57ca14a 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -1,5 +1,7 @@
 use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use std::fmt;
@@ -19,23 +21,31 @@ fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T>
     fn perform_query(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
         T::type_op_method(tcx, canonicalized)
     }
+
+    fn perform_locally_in_new_solver(
+        ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        // FIXME(-Ztrait-solver=next): shouldn't be using old normalizer
+        Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value))
+    }
 }
 
 pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx> + Copy {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>>;
+    ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution>;
 }
 
 impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
         tcx.type_op_normalize_ty(canonicalized)
     }
 }
@@ -44,7 +54,7 @@ impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
         tcx.type_op_normalize_predicate(canonicalized)
     }
 }
@@ -53,7 +63,7 @@ impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
         tcx.type_op_normalize_poly_fn_sig(canonicalized)
     }
 }
@@ -62,7 +72,7 @@ impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
         tcx.type_op_normalize_fn_sig(canonicalized)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
index 21ef4e2..9889426 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
@@ -1,6 +1,9 @@
 use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult};
-use crate::traits::query::Fallible;
+use crate::traits::query::dropck_outlives::{
+    compute_dropck_outlives_inner, trivial_dropck_outlives,
+};
+use crate::traits::ObligationCtxt;
+use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
 use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
@@ -27,7 +30,7 @@ fn try_fast_path(
     fn perform_query(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
         // Subtle: note that we are not invoking
         // `infcx.at(...).dropck_outlives(...)` here, but rather the
         // underlying `dropck_outlives` query. This same underlying
@@ -48,4 +51,11 @@ fn perform_query(
 
         tcx.dropck_outlives(canonicalized)
     }
+
+    fn perform_locally_in_new_solver(
+        ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        compute_dropck_outlives_inner(ocx, key.param_env.and(key.value.dropped_ty))
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index baa2fbb..47850bc 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -1,5 +1,8 @@
 use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
+use rustc_infer::traits::Obligation;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
 
 pub use rustc_middle::traits::query::type_op::ProvePredicate;
@@ -33,7 +36,20 @@ fn try_fast_path(
     fn perform_query(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
         tcx.type_op_prove_predicate(canonicalized)
     }
+
+    fn perform_locally_in_new_solver(
+        ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        ocx.register_obligation(Obligation::new(
+            ocx.infcx.tcx,
+            ObligationCause::dummy(),
+            key.param_env,
+            key.value.predicate,
+        ));
+        Ok(())
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
index c51292e..10976d5 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
@@ -1,5 +1,7 @@
 use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 
 pub use rustc_middle::traits::query::type_op::Subtype;
@@ -14,7 +16,15 @@ fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()
     fn perform_query(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
+    ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
         tcx.type_op_subtype(canonicalized)
     }
+
+    fn perform_locally_in_new_solver(
+        ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        ocx.sub(&ObligationCause::dummy(), key.param_env, key.value.sub, key.value.sup)?;
+        Ok(())
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 8bc82b9..3c223db 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -360,7 +360,9 @@ fn assemble_candidates_from_impls(
                 // consider a "quick reject". This avoids creating more types
                 // and so forth that we need to.
                 let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
-                if !drcx.substs_refs_may_unify(obligation_substs, impl_trait_ref.0.substs) {
+                if !drcx
+                    .substs_refs_may_unify(obligation_substs, impl_trait_ref.skip_binder().substs)
+                {
                     return;
                 }
                 if self.reject_fn_ptr_impls(
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 0d9f55d..0245dfd 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -527,9 +527,9 @@ fn confirm_object_candidate(
                         substs.extend(trait_predicate.trait_ref.substs.iter());
                         let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
                             smallvec::SmallVec::with_capacity(
-                                bound.0.kind().bound_vars().len() + defs.count(),
+                                bound.skip_binder().kind().bound_vars().len() + defs.count(),
                             );
-                        bound_vars.extend(bound.0.kind().bound_vars().into_iter());
+                        bound_vars.extend(bound.skip_binder().kind().bound_vars().into_iter());
                         InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param
                             .kind
                         {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 3baf1c9..ed380f3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2149,13 +2149,11 @@ fn sized_conditions(
             ty::Adt(def, substs) => {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
-                Where(obligation.predicate.rebind({
-                    sized_crit
-                        .0
-                        .iter()
-                        .map(|ty| sized_crit.rebind(*ty).subst(self.tcx(), substs))
-                        .collect()
-                }))
+                Where(
+                    obligation
+                        .predicate
+                        .rebind(sized_crit.subst_iter_copied(self.tcx(), substs).collect()),
+                )
             }
 
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None,
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index c319b2e..1d3ea96 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -294,7 +294,7 @@ fn fn_def_datum(
         };
         Arc::new(chalk_solve::rust_ir::FnDefDatum {
             id: fn_def_id,
-            sig: sig.0.lower_into(self.interner),
+            sig: sig.skip_binder().lower_into(self.interner),
             binders: chalk_ir::Binders::new(binders, bound),
         })
     }
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 83f6c7d..f35c14e 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -3,17 +3,14 @@
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
+use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
 use rustc_middle::ty::InternalSubsts;
-use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
-use rustc_span::source_map::{Span, DUMMY_SP};
+use rustc_middle::ty::TyCtxt;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives;
 use rustc_trait_selection::traits::query::dropck_outlives::{
-    DropckConstraint, DropckOutlivesResult,
+    compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner,
 };
-use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
-use rustc_trait_selection::traits::{Normalized, ObligationCause};
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p };
@@ -26,263 +23,10 @@ fn dropck_outlives<'tcx>(
     debug!("dropck_outlives(goal={:#?})", canonical_goal);
 
     tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| {
-        let tcx = ocx.infcx.tcx;
-        let ParamEnvAnd { param_env, value: for_ty } = goal;
-
-        let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
-
-        // A stack of types left to process. Each round, we pop
-        // something from the stack and invoke
-        // `dtorck_constraint_for_ty`. This may produce new types that
-        // have to be pushed on the stack. This continues until we have explored
-        // all the reachable types from the type `for_ty`.
-        //
-        // Example: Imagine that we have the following code:
-        //
-        // ```rust
-        // struct A {
-        //     value: B,
-        //     children: Vec<A>,
-        // }
-        //
-        // struct B {
-        //     value: u32
-        // }
-        //
-        // fn f() {
-        //   let a: A = ...;
-        //   ..
-        // } // here, `a` is dropped
-        // ```
-        //
-        // at the point where `a` is dropped, we need to figure out
-        // which types inside of `a` contain region data that may be
-        // accessed by any destructors in `a`. We begin by pushing `A`
-        // onto the stack, as that is the type of `a`. We will then
-        // invoke `dtorck_constraint_for_ty` which will expand `A`
-        // into the types of its fields `(B, Vec<A>)`. These will get
-        // pushed onto the stack. Eventually, expanding `Vec<A>` will
-        // lead to us trying to push `A` a second time -- to prevent
-        // infinite recursion, we notice that `A` was already pushed
-        // once and stop.
-        let mut ty_stack = vec![(for_ty, 0)];
-
-        // Set used to detect infinite recursion.
-        let mut ty_set = FxHashSet::default();
-
-        let cause = ObligationCause::dummy();
-        let mut constraints = DropckConstraint::empty();
-        while let Some((ty, depth)) = ty_stack.pop() {
-            debug!(
-                "{} kinds, {} overflows, {} ty_stack",
-                result.kinds.len(),
-                result.overflows.len(),
-                ty_stack.len()
-            );
-            dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
-
-            // "outlives" represent types/regions that may be touched
-            // by a destructor.
-            result.kinds.append(&mut constraints.outlives);
-            result.overflows.append(&mut constraints.overflows);
-
-            // If we have even one overflow, we should stop trying to evaluate further --
-            // chances are, the subsequent overflows for this evaluation won't provide useful
-            // information and will just decrease the speed at which we can emit these errors
-            // (since we'll be printing for just that much longer for the often enormous types
-            // that result here).
-            if !result.overflows.is_empty() {
-                break;
-            }
-
-            // dtorck types are "types that will get dropped but which
-            // do not themselves define a destructor", more or less. We have
-            // to push them onto the stack to be expanded.
-            for ty in constraints.dtorck_types.drain(..) {
-                let Normalized { value: ty, obligations } =
-                    ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
-                ocx.register_obligations(obligations);
-
-                debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
-
-                match ty.kind() {
-                    // All parameters live for the duration of the
-                    // function.
-                    ty::Param(..) => {}
-
-                    // A projection that we couldn't resolve - it
-                    // might have a destructor.
-                    ty::Alias(..) => {
-                        result.kinds.push(ty.into());
-                    }
-
-                    _ => {
-                        if ty_set.insert(ty) {
-                            ty_stack.push((ty, depth + 1));
-                        }
-                    }
-                }
-            }
-        }
-
-        debug!("dropck_outlives: result = {:#?}", result);
-        Ok(result)
+        compute_dropck_outlives_inner(ocx, goal)
     })
 }
 
-/// Returns a set of constraints that needs to be satisfied in
-/// order for `ty` to be valid for destruction.
-fn dtorck_constraint_for_ty<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    span: Span,
-    for_ty: Ty<'tcx>,
-    depth: usize,
-    ty: Ty<'tcx>,
-    constraints: &mut DropckConstraint<'tcx>,
-) -> Result<(), NoSolution> {
-    debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
-
-    if !tcx.recursion_limit().value_within_limit(depth) {
-        constraints.overflows.push(ty);
-        return Ok(());
-    }
-
-    if trivial_dropck_outlives(tcx, ty) {
-        return Ok(());
-    }
-
-    match ty.kind() {
-        ty::Bool
-        | ty::Char
-        | ty::Int(_)
-        | ty::Uint(_)
-        | ty::Float(_)
-        | ty::Str
-        | ty::Never
-        | ty::Foreign(..)
-        | ty::RawPtr(..)
-        | ty::Ref(..)
-        | ty::FnDef(..)
-        | ty::FnPtr(_)
-        | ty::GeneratorWitness(..)
-        | ty::GeneratorWitnessMIR(..) => {
-            // these types never have a destructor
-        }
-
-        ty::Array(ety, _) | ty::Slice(ety) => {
-            // single-element containers, behave like their element
-            rustc_data_structures::stack::ensure_sufficient_stack(|| {
-                dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, *ety, constraints)
-            })?;
-        }
-
-        ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
-            for ty in tys.iter() {
-                dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
-            }
-            Ok::<_, NoSolution>(())
-        })?,
-
-        ty::Closure(_, substs) => {
-            if !substs.as_closure().is_valid() {
-                // By the time this code runs, all type variables ought to
-                // be fully resolved.
-
-                tcx.sess.delay_span_bug(
-                    span,
-                    format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
-                );
-                return Err(NoSolution);
-            }
-
-            rustc_data_structures::stack::ensure_sufficient_stack(|| {
-                for ty in substs.as_closure().upvar_tys() {
-                    dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
-                }
-                Ok::<_, NoSolution>(())
-            })?
-        }
-
-        ty::Generator(_, substs, _movability) => {
-            // rust-lang/rust#49918: types can be constructed, stored
-            // in the interior, and sit idle when generator yields
-            // (and is subsequently dropped).
-            //
-            // It would be nice to descend into interior of a
-            // generator to determine what effects dropping it might
-            // have (by looking at any drop effects associated with
-            // its interior).
-            //
-            // However, the interior's representation uses things like
-            // GeneratorWitness that explicitly assume they are not
-            // traversed in such a manner. So instead, we will
-            // simplify things for now by treating all generators as
-            // if they were like trait objects, where its upvars must
-            // all be alive for the generator's (potential)
-            // destructor.
-            //
-            // In particular, skipping over `_interior` is safe
-            // because any side-effects from dropping `_interior` can
-            // only take place through references with lifetimes
-            // derived from lifetimes attached to the upvars and resume
-            // argument, and we *do* incorporate those here.
-
-            if !substs.as_generator().is_valid() {
-                // By the time this code runs, all type variables ought to
-                // be fully resolved.
-                tcx.sess.delay_span_bug(
-                    span,
-                    format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
-                );
-                return Err(NoSolution);
-            }
-
-            constraints.outlives.extend(
-                substs
-                    .as_generator()
-                    .upvar_tys()
-                    .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }),
-            );
-            constraints.outlives.push(substs.as_generator().resume_ty().into());
-        }
-
-        ty::Adt(def, substs) => {
-            let DropckConstraint { dtorck_types, outlives, overflows } =
-                tcx.at(span).adt_dtorck_constraint(def.did())?;
-            // FIXME: we can try to recursively `dtorck_constraint_on_ty`
-            // there, but that needs some way to handle cycles.
-            constraints
-                .dtorck_types
-                .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
-            constraints
-                .outlives
-                .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
-            constraints
-                .overflows
-                .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
-        }
-
-        // Objects must be alive in order for their destructor
-        // to be called.
-        ty::Dynamic(..) => {
-            constraints.outlives.push(ty.into());
-        }
-
-        // Types that can't be resolved. Pass them forward.
-        ty::Alias(..) | ty::Param(..) => {
-            constraints.dtorck_types.push(ty);
-        }
-
-        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
-            // By the time this code runs, all type variables ought to
-            // be fully resolved.
-            return Err(NoSolution);
-        }
-    }
-
-    Ok(())
-}
-
 /// Calculates the dtorck constraint for a type.
 pub(crate) fn adt_dtorck_constraint(
     tcx: TyCtxt<'_>,
@@ -311,7 +55,7 @@ pub(crate) fn adt_dtorck_constraint(
     let mut result = DropckConstraint::empty();
     for field in def.all_fields() {
         let fty = tcx.type_of(field.did).subst_identity();
-        dtorck_constraint_for_ty(tcx, span, fty, 0, fty, &mut result)?;
+        dtorck_constraint_for_ty_inner(tcx, span, fty, 0, fty, &mut result)?;
     }
     result.outlives.extend(tcx.destructor_constraints(def));
     dedup_dtorck_constraint(&mut result);
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 0c2bb86..959838a 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -3,18 +3,13 @@
 //! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`].
 
 use rustc_infer::infer::canonical::{self, Canonical};
-use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::source_map::DUMMY_SP;
+use rustc_middle::ty::TyCtxt;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
-use rustc_trait_selection::traits::wf;
-use rustc_trait_selection::traits::ObligationCtxt;
-use smallvec::{smallvec, SmallVec};
+use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner;
+use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers { implied_outlives_bounds, ..*p };
@@ -29,164 +24,6 @@ fn implied_outlives_bounds<'tcx>(
 > {
     tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
         let (param_env, ty) = key.into_parts();
-        compute_implied_outlives_bounds(ocx, param_env, ty)
+        compute_implied_outlives_bounds_inner(ocx, param_env, ty)
     })
 }
-
-fn compute_implied_outlives_bounds<'tcx>(
-    ocx: &ObligationCtxt<'_, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-) -> Fallible<Vec<OutlivesBound<'tcx>>> {
-    let tcx = ocx.infcx.tcx;
-
-    // Sometimes when we ask what it takes for T: WF, we get back that
-    // U: WF is required; in that case, we push U onto this stack and
-    // process it next. Because the resulting predicates aren't always
-    // guaranteed to be a subset of the original type, so we need to store the
-    // WF args we've computed in a set.
-    let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
-    let mut wf_args = vec![ty.into()];
-
-    let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
-        vec![];
-
-    while let Some(arg) = wf_args.pop() {
-        if !checked_wf_args.insert(arg) {
-            continue;
-        }
-
-        // Compute the obligations for `arg` to be well-formed. If `arg` is
-        // an unresolved inference variable, just substituted an empty set
-        // -- because the return type here is going to be things we *add*
-        // to the environment, it's always ok for this set to be smaller
-        // than the ultimate set. (Note: normally there won't be
-        // unresolved inference variables here anyway, but there might be
-        // during typeck under some circumstances.)
-        //
-        // FIXME(@lcnr): It's not really "always fine", having fewer implied
-        // bounds can be backward incompatible, e.g. #101951 was caused by
-        // us not dealing with inference vars in `TypeOutlives` predicates.
-        let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
-            .unwrap_or_default();
-
-        for obligation in obligations {
-            debug!(?obligation);
-            assert!(!obligation.has_escaping_bound_vars());
-
-            // While these predicates should all be implied by other parts of
-            // the program, they are still relevant as they may constrain
-            // inference variables, which is necessary to add the correct
-            // implied bounds in some cases, mostly when dealing with projections.
-            //
-            // Another important point here: we only register `Projection`
-            // predicates, since otherwise we might register outlives
-            // predicates containing inference variables, and we don't
-            // learn anything new from those.
-            if obligation.predicate.has_non_region_infer() {
-                match obligation.predicate.kind().skip_binder() {
-                    ty::PredicateKind::Clause(ty::Clause::Projection(..))
-                    | ty::PredicateKind::AliasRelate(..) => {
-                        ocx.register_obligation(obligation.clone());
-                    }
-                    _ => {}
-                }
-            }
-
-            let pred = match obligation.predicate.kind().no_bound_vars() {
-                None => continue,
-                Some(pred) => pred,
-            };
-            match pred {
-                ty::PredicateKind::Clause(ty::Clause::Trait(..))
-                // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
-                // if we ever support that
-                | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-                | ty::PredicateKind::Subtype(..)
-                | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::Clause(ty::Clause::Projection(..))
-                | ty::PredicateKind::ClosureKind(..)
-                | ty::PredicateKind::ObjectSafe(..)
-                | ty::PredicateKind::ConstEvaluatable(..)
-                | ty::PredicateKind::ConstEquate(..)
-                | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasRelate(..)
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
-
-                // We need to search through *all* WellFormed predicates
-                ty::PredicateKind::WellFormed(arg) => {
-                    wf_args.push(arg);
-                }
-
-                // We need to register region relationships
-                ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
-                    r_a,
-                    r_b,
-                ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
-
-                ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
-                    ty_a,
-                    r_b,
-                ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)),
-            }
-        }
-    }
-
-    // This call to `select_all_or_error` is necessary to constrain inference variables, which we
-    // use further down when computing the implied bounds.
-    match ocx.select_all_or_error().as_slice() {
-        [] => (),
-        _ => return Err(NoSolution),
-    }
-
-    // We lazily compute the outlives components as
-    // `select_all_or_error` constrains inference variables.
-    let implied_bounds = outlives_bounds
-        .into_iter()
-        .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
-            ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
-            ty::GenericArgKind::Type(ty_a) => {
-                let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
-                let mut components = smallvec![];
-                push_outlives_components(tcx, ty_a, &mut components);
-                implied_bounds_from_components(r_b, components)
-            }
-            ty::GenericArgKind::Const(_) => unreachable!(),
-        })
-        .collect();
-
-    Ok(implied_bounds)
-}
-
-/// When we have an implied bound that `T: 'a`, we can further break
-/// this down to determine what relationships would have to hold for
-/// `T: 'a` to hold. We get to assume that the caller has validated
-/// those relationships.
-fn implied_bounds_from_components<'tcx>(
-    sub_region: ty::Region<'tcx>,
-    sup_components: SmallVec<[Component<'tcx>; 4]>,
-) -> Vec<OutlivesBound<'tcx>> {
-    sup_components
-        .into_iter()
-        .filter_map(|component| {
-            match component {
-                Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
-                Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
-                Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
-                Component::EscapingAlias(_) =>
-                // If the projection has escaping regions, don't
-                // try to infer any implied bounds even for its
-                // free components. This is conservative, because
-                // the caller will still have to prove that those
-                // free components outlive `sub_region`. But the
-                // idea is that the WAY that the caller proves
-                // that may change in the future and we want to
-                // give ourselves room to get smarter here.
-                {
-                    None
-                }
-                Component::UnresolvedInferenceVariable(..) => None,
-            }
-        })
-        .collect()
-}
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index b0f9c57..907e2d3 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -21,7 +21,8 @@
 mod normalize_projection_ty;
 mod type_op;
 
-pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
+pub use rustc_trait_selection::traits::query::type_op::ascribe_user_type::type_op_ascribe_user_type_with_span;
+pub use type_op::type_op_prove_predicate_with_cause;
 
 use rustc_middle::query::Providers;
 
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index b1cbd88..9904acb 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -1,21 +1,19 @@
-use rustc_hir as hir;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
-use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
-use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::DefiningAnchor;
+use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{ParamEnvAnd, Predicate};
-use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType};
-use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
-use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType;
+use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
+    type_op_ascribe_user_type_with_span, AscribeUserType,
+};
 use rustc_trait_selection::traits::query::type_op::eq::Eq;
 use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
 use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
 use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
-use rustc_trait_selection::traits::query::{Fallible, NoSolution};
 use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
 use std::fmt;
 
@@ -42,111 +40,6 @@ fn type_op_ascribe_user_type<'tcx>(
     })
 }
 
-/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
-/// this query can be re-run to better track the span of the obligation cause, and improve the error
-/// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_ascribe_user_type_with_span<'tcx>(
-    ocx: &ObligationCtxt<'_, 'tcx>,
-    key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
-    span: Option<Span>,
-) -> Result<(), NoSolution> {
-    let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
-    debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
-    let span = span.unwrap_or(DUMMY_SP);
-    match user_ty {
-        UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
-        UserType::TypeOf(def_id, user_substs) => {
-            relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
-        }
-    };
-    Ok(())
-}
-
-#[instrument(level = "debug", skip(ocx, param_env, span))]
-fn relate_mir_and_user_ty<'tcx>(
-    ocx: &ObligationCtxt<'_, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    span: Span,
-    mir_ty: Ty<'tcx>,
-    user_ty: Ty<'tcx>,
-) -> Result<(), NoSolution> {
-    let cause = ObligationCause::dummy_with_span(span);
-    let user_ty = ocx.normalize(&cause, param_env, user_ty);
-    ocx.eq(&cause, param_env, mir_ty, user_ty)?;
-
-    // FIXME(#104764): We should check well-formedness before normalization.
-    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
-    ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
-    Ok(())
-}
-
-#[instrument(level = "debug", skip(ocx, param_env, span))]
-fn relate_mir_and_user_substs<'tcx>(
-    ocx: &ObligationCtxt<'_, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    span: Span,
-    mir_ty: Ty<'tcx>,
-    def_id: hir::def_id::DefId,
-    user_substs: UserSubsts<'tcx>,
-) -> Result<(), NoSolution> {
-    let param_env = param_env.without_const();
-    let UserSubsts { user_self_ty, substs } = user_substs;
-    let tcx = ocx.infcx.tcx;
-    let cause = ObligationCause::dummy_with_span(span);
-
-    let ty = tcx.type_of(def_id).subst(tcx, substs);
-    let ty = ocx.normalize(&cause, param_env, ty);
-    debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
-
-    ocx.eq(&cause, param_env, mir_ty, ty)?;
-
-    // Prove the predicates coming along with `def_id`.
-    //
-    // Also, normalize the `instantiated_predicates`
-    // because otherwise we wind up with duplicate "type
-    // outlives" error messages.
-    let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
-
-    debug!(?instantiated_predicates);
-    for (instantiated_predicate, predicate_span) in instantiated_predicates {
-        let span = if span == DUMMY_SP { predicate_span } else { span };
-        let cause = ObligationCause::new(
-            span,
-            CRATE_DEF_ID,
-            ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
-        );
-        let instantiated_predicate =
-            ocx.normalize(&cause.clone(), param_env, instantiated_predicate);
-
-        ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
-    }
-
-    if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
-        let self_ty = ocx.normalize(&cause, param_env, self_ty);
-        let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs);
-        let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
-
-        ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
-        let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
-        ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
-    }
-
-    // In addition to proving the predicates, we have to
-    // prove that `ty` is well-formed -- this is because
-    // the WF of `ty` is predicated on the substs being
-    // well-formed, and we haven't proven *that*. We don't
-    // want to prove the WF of types from  `substs` directly because they
-    // haven't been normalized.
-    //
-    // FIXME(nmatsakis): Well, perhaps we should normalize
-    // them?  This would only be relevant if some input
-    // type were ill-formed but did not appear in `ty`,
-    // which...could happen with normalization...
-    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
-    ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
-    Ok(())
-}
-
 fn type_op_eq<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
@@ -160,7 +53,7 @@ fn type_op_eq<'tcx>(
 fn type_op_normalize<'tcx, T>(
     ocx: &ObligationCtxt<'_, 'tcx>,
     key: ParamEnvAnd<'tcx, Normalize<T>>,
-) -> Fallible<T>
+) -> Result<T, NoSolution>
 where
     T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx>,
 {
diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl
index 5bc3e3c..c416aa5 100644
--- a/compiler/rustc_ty_utils/messages.ftl
+++ b/compiler/rustc_ty_utils/messages.ftl
@@ -1,61 +1,31 @@
-ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop
+ty_utils_address_and_deref_not_supported = dereferencing or taking the address is not supported in generic constants
+
+ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants
+
+ty_utils_array_not_supported = array construction is not supported in generic constants
+
+ty_utils_assign_not_supported = assignment is not supported in generic constants
+
+ty_utils_binary_not_supported = unsupported binary operation in generic constants
+
+ty_utils_block_not_supported = blocks are not supported in generic constants
+
+ty_utils_borrow_not_supported = borrowing is not supported in generic constants
+
+ty_utils_box_not_supported = allocations are not allowed in generic constants
+
+ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants
+
+ty_utils_const_block_not_supported = const blocks are not supported in generic constants
+
+ty_utils_control_flow_not_supported = control flow is not supported in generic constants
+
+ty_utils_field_not_supported = field access is not supported in generic constants
 
 ty_utils_generic_constant_too_complex = overly complex generic constant
     .help = consider moving this anonymous constant into a `const` function
     .maybe_supported = this operation may be supported in the future
 
-ty_utils_borrow_not_supported = borrowing is not supported in generic constants
-
-ty_utils_address_and_deref_not_supported = dereferencing or taking the address is not supported in generic constants
-
-ty_utils_array_not_supported = array construction is not supported in generic constants
-
-ty_utils_block_not_supported = blocks are not supported in generic constants
-
-ty_utils_never_to_any_not_supported = coercing the `never` type is not supported in generic constants
-
-ty_utils_tuple_not_supported = tuple construction is not supported in generic constants
-
-ty_utils_index_not_supported = indexing is not supported in generic constants
-
-ty_utils_field_not_supported = field access is not supported in generic constants
-
-ty_utils_const_block_not_supported = const blocks are not supported in generic constants
-
-ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants
-
-ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants
-
-ty_utils_yield_not_supported = generator control flow is not allowed in generic constants
-
-ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants
-
-ty_utils_box_not_supported = allocations are not allowed in generic constants
-
-ty_utils_binary_not_supported = unsupported binary operation in generic constants
-
-ty_utils_logical_op_not_supported = unsupported operation in generic constants, short-circuiting operations would imply control flow
-
-ty_utils_assign_not_supported = assignment is not supported in generic constants
-
-ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants
-
-ty_utils_control_flow_not_supported = control flow is not supported in generic constants
-
-ty_utils_inline_asm_not_supported = assembly is not supported in generic constants
-
-ty_utils_operation_not_supported = unsupported operation in generic constants
-
-ty_utils_unexpected_fnptr_associated_item = `FnPtr` trait with unexpected associated item
-
-ty_utils_zero_length_simd_type = monomorphising SIMD type `{$ty}` of zero length
-
-ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with more than one array field
-
-ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes}
-
-ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}`
-
 ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope
     .label = generic argument `{$arg}` used twice
     .note = for this opaque type
@@ -63,3 +33,33 @@
 ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope
     .label = argument `{$arg}` is not a generic parameter
     .note = for this opaque type
+
+ty_utils_index_not_supported = indexing is not supported in generic constants
+
+ty_utils_inline_asm_not_supported = assembly is not supported in generic constants
+
+ty_utils_logical_op_not_supported = unsupported operation in generic constants, short-circuiting operations would imply control flow
+
+ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants
+
+ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with more than one array field
+
+ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop
+
+ty_utils_never_to_any_not_supported = coercing the `never` type is not supported in generic constants
+
+ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}`
+
+ty_utils_operation_not_supported = unsupported operation in generic constants
+
+ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes}
+
+ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants
+
+ty_utils_tuple_not_supported = tuple construction is not supported in generic constants
+
+ty_utils_unexpected_fnptr_associated_item = `FnPtr` trait with unexpected associated item
+
+ty_utils_yield_not_supported = generator control flow is not allowed in generic constants
+
+ty_utils_zero_length_simd_type = monomorphising SIMD type `{$ty}` of zero length
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index ed574f2..0925b39 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -301,7 +301,7 @@ fn associated_type_for_impl_trait_in_trait(
     trait_assoc_ty.impl_defaultness(tcx.impl_defaultness(fn_def_id));
 
     // Copy type_of of the opaque.
-    trait_assoc_ty.type_of(ty::EarlyBinder(tcx.mk_opaque(
+    trait_assoc_ty.type_of(ty::EarlyBinder::new(tcx.mk_opaque(
         opaque_ty_def_id.to_def_id(),
         InternalSubsts::identity_for_item(tcx, opaque_ty_def_id),
     )));
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 1219bb4..bb723c9 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -419,7 +419,7 @@ pub fn thir_abstract_const(
 
     let root_span = body.exprs[body_id].span;
 
-    Ok(Some(ty::EarlyBinder(recurse_build(tcx, body, body_id, root_span)?)))
+    Ok(Some(ty::EarlyBinder::new(recurse_build(tcx, body, body_id, root_span)?)))
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 16cd8bc..0e5b23c 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -610,7 +610,7 @@ fn generator_layout<'tcx>(
 ) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
     use SavedLocalEligibility::*;
     let tcx = cx.tcx;
-    let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs);
+    let subst_field = |ty: Ty<'tcx>| EarlyBinder::new(ty).subst(tcx, substs);
 
     let Some(info) = tcx.generator_layout(def_id) else {
         return Err(LayoutError::Unknown(ty));
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 1f9701b..075fde6 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -210,7 +210,7 @@ fn with_query_cache<'tcx>(
             match subty.kind() {
                 ty::Adt(adt_id, subst) => {
                     for subty in tcx.adt_drop_tys(adt_id.did())? {
-                        vec.push(EarlyBinder(subty).subst(tcx, subst));
+                        vec.push(EarlyBinder::new(subty).subst(tcx, subst));
                     }
                 }
                 _ => vec.push(subty),
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 65dc3c3..52bc386 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -44,9 +44,7 @@ fn sized_constraint_for_ty<'tcx>(
             let adt_tys = adt.sized_constraint(tcx);
             debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
             adt_tys
-                .0
-                .iter()
-                .map(|ty| adt_tys.rebind(*ty).subst(tcx, substs))
+                .subst_iter_copied(tcx, substs)
                 .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
                 .collect()
         }
@@ -508,7 +506,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<EarlyBinder<Ty<'
 
     if self_ty_matches {
         debug!("issue33140_self_ty - MATCHES!");
-        Some(EarlyBinder(self_ty))
+        Some(EarlyBinder::new(self_ty))
     } else {
         debug!("issue33140_self_ty - non-matching self type");
         None
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 498fbd9..c524d4c 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1851,7 +1851,7 @@ pub fn into_boxed_str(self) -> Box<str> {
     }
 
     /// Consumes and leaks the `String`, returning a mutable reference to the contents,
-    /// `&'static mut str`.
+    /// `&'a mut str`.
     ///
     /// This is mainly useful for data that lives for the remainder of
     /// the program's life. Dropping the returned reference will cause a memory
@@ -1874,7 +1874,7 @@ pub fn into_boxed_str(self) -> Box<str> {
     /// ```
     #[unstable(feature = "string_leak", issue = "102929")]
     #[inline]
-    pub fn leak(self) -> &'static mut str {
+    pub fn leak<'a>(self) -> &'a mut str {
         let slice = self.vec.leak();
         unsafe { from_utf8_unchecked_mut(slice) }
     }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 82f30a2..47661a3 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2662,7 +2662,6 @@ fn clone_from(&mut self, other: &Self) {
 /// as required by the `core::borrow::Borrow` implementation.
 ///
 /// ```
-/// #![feature(build_hasher_simple_hash_one)]
 /// use std::hash::BuildHasher;
 ///
 /// let b = std::collections::hash_map::RandomState::new();
diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs
index 18da704..c582111 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -235,7 +235,8 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
     /// * `new_size` must be greater than zero.
     ///
     /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
-    ///   must not overflow (i.e., the rounded value must be less than `usize::MAX`).
+    ///   must not overflow isize (i.e., the rounded value must be less than or
+    ///   equal to `isize::MAX`).
     ///
     /// (Extension subtraits might provide more specific bounds on
     /// behavior, e.g., guarantee a sentinel address or a null pointer
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index d1c1ae6..7969f40 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -662,12 +662,20 @@ pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
 /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth
 /// noting that the hashes and ordering will vary between Rust releases. Beware
 /// of relying on them inside of your code!
-#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, Copy, Debug, Hash, Eq, PartialOrd, Ord)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct TypeId {
     t: u64,
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for TypeId {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.t == other.t
+    }
+}
+
 impl TypeId {
     /// Returns the `TypeId` of the type this generic function has been
     /// instantiated with.
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index bdb4c97..fec9232 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -204,6 +204,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
 {
     type Error = TryFromSliceError;
 
+    #[inline]
     fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> {
         <&Self>::try_from(slice).map(|r| *r)
     }
@@ -228,6 +229,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
 {
     type Error = TryFromSliceError;
 
+    #[inline]
     fn try_from(slice: &mut [T]) -> Result<[T; N], TryFromSliceError> {
         <Self>::try_from(&*slice)
     }
@@ -249,6 +251,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
 impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
     type Error = TryFromSliceError;
 
+    #[inline]
     fn try_from(slice: &'a [T]) -> Result<&'a [T; N], TryFromSliceError> {
         if slice.len() == N {
             let ptr = slice.as_ptr() as *const [T; N];
@@ -276,6 +279,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
 impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] {
     type Error = TryFromSliceError;
 
+    #[inline]
     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];
@@ -291,7 +295,6 @@ fn borrow_mut(&mut self) -> &mut [T] {
 /// as required by the `Borrow` implementation.
 ///
 /// ```
-/// #![feature(build_hasher_simple_hash_one)]
 /// use std::hash::BuildHasher;
 ///
 /// let b = std::collections::hash_map::RandomState::new();
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index a73b5b6..ca7c077 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -674,8 +674,6 @@ pub trait BuildHasher {
     /// # Example
     ///
     /// ```
-    /// #![feature(build_hasher_simple_hash_one)]
-    ///
     /// use std::cmp::{max, min};
     /// use std::hash::{BuildHasher, Hash, Hasher};
     /// struct OrderAmbivalentPair<T: Ord>(T, T);
@@ -697,7 +695,7 @@ pub trait BuildHasher {
     ///     bh.hash_one(&OrderAmbivalentPair(2, 10))
     /// );
     /// ```
-    #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")]
+    #[stable(feature = "build_hasher_simple_hash_one", since = "CURRENT_RUSTC_VERSION")]
     fn hash_one<T: Hash>(&self, x: T) -> u64
     where
         Self: Sized,
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index b24882d..c4134db 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1427,7 +1427,7 @@ macro_rules! include {
     #[rustc_builtin_macro]
     #[macro_export]
     #[rustc_diagnostic_item = "assert_macro"]
-    #[allow_internal_unstable(core_panic, edition_panic)]
+    #[allow_internal_unstable(core_panic, edition_panic, generic_assert_internals)]
     macro_rules! assert {
         ($cond:expr $(,)?) => {{ /* compiler built-in */ }};
         ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 9e09ce3..8a007d0 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -593,7 +593,8 @@ pub trait Read {
     /// This may happen for example because fewer bytes are actually available right now
     /// (e. g. being close to end-of-file) or because read() was interrupted by a signal.
     ///
-    /// As this trait is safe to implement, callers cannot rely on `n <= buf.len()` for safety.
+    /// As this trait is safe to implement, callers in unsafe code cannot rely on
+    /// `n <= buf.len()` for safety.
     /// Extra care needs to be taken when `unsafe` functions are used to access the read bytes.
     /// Callers have to ensure that no unchecked out-of-bounds accesses are possible even if
     /// `n > buf.len()`.
@@ -603,8 +604,8 @@ pub trait Read {
     /// contents of `buf` being true. It is recommended that *implementations*
     /// only write data to `buf` instead of reading its contents.
     ///
-    /// Correspondingly, however, *callers* of this method must not assume any guarantees
-    /// about how the implementation uses `buf`. The trait is safe to implement,
+    /// Correspondingly, however, *callers* of this method in unsafe code must not assume
+    /// any guarantees about how the implementation uses `buf`. The trait is safe to implement,
     /// so it is possible that the code that's supposed to write to the buffer might also read
     /// from it. It is your responsibility to make sure that `buf` is initialized
     /// before calling `read`. Calling `read` with an uninitialized `buf` (of the kind one
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 6d59266..a6a3704 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -298,8 +298,18 @@ pub mod panic_count {
 
     pub const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1);
 
-    // Panic count for the current thread.
-    thread_local! { static LOCAL_PANIC_COUNT: Cell<usize> = const { Cell::new(0) } }
+    /// A reason for forcing an immediate abort on panic.
+    #[derive(Debug)]
+    pub enum MustAbort {
+        AlwaysAbort,
+        PanicInHook,
+    }
+
+    // Panic count for the current thread and whether a panic hook is currently
+    // being executed..
+    thread_local! {
+        static LOCAL_PANIC_COUNT: Cell<(usize, bool)> = const { Cell::new((0, false)) }
+    }
 
     // Sum of panic counts from all threads. The purpose of this is to have
     // a fast path in `count_is_zero` (which is used by `panicking`). In any particular
@@ -328,34 +338,39 @@ pub mod panic_count {
     // panicking thread consumes at least 2 bytes of address space.
     static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
 
-    // Return the state of the ALWAYS_ABORT_FLAG and number of panics.
+    // Increases the global and local panic count, and returns whether an
+    // immediate abort is required.
     //
-    // If ALWAYS_ABORT_FLAG is not set, the number is determined on a per-thread
-    // base (stored in LOCAL_PANIC_COUNT), i.e. it is the amount of recursive calls
-    // of the calling thread.
-    // If ALWAYS_ABORT_FLAG is set, the number equals the *global* number of panic
-    // calls. See above why LOCAL_PANIC_COUNT is not used.
-    pub fn increase() -> (bool, usize) {
+    // This also updates thread-local state to keep track of whether a panic
+    // hook is currently executing.
+    pub fn increase(run_panic_hook: bool) -> Option<MustAbort> {
         let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
-        let must_abort = global_count & ALWAYS_ABORT_FLAG != 0;
-        let panics = if must_abort {
-            global_count & !ALWAYS_ABORT_FLAG
-        } else {
-            LOCAL_PANIC_COUNT.with(|c| {
-                let next = c.get() + 1;
-                c.set(next);
-                next
-            })
-        };
-        (must_abort, panics)
+        if global_count & ALWAYS_ABORT_FLAG != 0 {
+            return Some(MustAbort::AlwaysAbort);
+        }
+
+        LOCAL_PANIC_COUNT.with(|c| {
+            let (count, in_panic_hook) = c.get();
+            if in_panic_hook {
+                return Some(MustAbort::PanicInHook);
+            }
+            c.set((count + 1, run_panic_hook));
+            None
+        })
+    }
+
+    pub fn finished_panic_hook() {
+        LOCAL_PANIC_COUNT.with(|c| {
+            let (count, _) = c.get();
+            c.set((count, false));
+        });
     }
 
     pub fn decrease() {
         GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed);
         LOCAL_PANIC_COUNT.with(|c| {
-            let next = c.get() - 1;
-            c.set(next);
-            next
+            let (count, _) = c.get();
+            c.set((count - 1, false));
         });
     }
 
@@ -366,7 +381,7 @@ pub fn set_always_abort() {
     // Disregards ALWAYS_ABORT_FLAG
     #[must_use]
     pub fn get_count() -> usize {
-        LOCAL_PANIC_COUNT.with(|c| c.get())
+        LOCAL_PANIC_COUNT.with(|c| c.get().0)
     }
 
     // Disregards ALWAYS_ABORT_FLAG
@@ -394,7 +409,7 @@ pub fn count_is_zero() -> bool {
     #[inline(never)]
     #[cold]
     fn is_zero_slow_path() -> bool {
-        LOCAL_PANIC_COUNT.with(|c| c.get() == 0)
+        LOCAL_PANIC_COUNT.with(|c| c.get().0 == 0)
     }
 }
 
@@ -655,23 +670,22 @@ fn rust_panic_with_hook(
     location: &Location<'_>,
     can_unwind: bool,
 ) -> ! {
-    let (must_abort, panics) = panic_count::increase();
+    let must_abort = panic_count::increase(true);
 
-    // If this is the third nested call (e.g., panics == 2, this is 0-indexed),
-    // the panic hook probably triggered the last panic, otherwise the
-    // double-panic check would have aborted the process. In this case abort the
-    // process real quickly as we don't want to try calling it again as it'll
-    // probably just panic again.
-    if must_abort || panics > 2 {
-        if panics > 2 {
-            // Don't try to print the message in this case
-            // - perhaps that is causing the recursive panics.
-            rtprintpanic!("thread panicked while processing panic. aborting.\n");
-        } else {
-            // Unfortunately, this does not print a backtrace, because creating
-            // a `Backtrace` will allocate, which we must to avoid here.
-            let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
-            rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
+    // Check if we need to abort immediately.
+    if let Some(must_abort) = must_abort {
+        match must_abort {
+            panic_count::MustAbort::PanicInHook => {
+                // Don't try to print the message in this case
+                // - perhaps that is causing the recursive panics.
+                rtprintpanic!("thread panicked while processing panic. aborting.\n");
+            }
+            panic_count::MustAbort::AlwaysAbort => {
+                // Unfortunately, this does not print a backtrace, because creating
+                // a `Backtrace` will allocate, which we must to avoid here.
+                let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
+                rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
+            }
         }
         crate::sys::abort_internal();
     }
@@ -697,16 +711,16 @@ fn rust_panic_with_hook(
     };
     drop(hook);
 
-    if panics > 1 || !can_unwind {
-        // If a thread panics while it's already unwinding then we
-        // have limited options. Currently our preference is to
-        // just abort. In the future we may consider resuming
-        // unwinding or otherwise exiting the thread cleanly.
-        if !can_unwind {
-            rtprintpanic!("thread caused non-unwinding panic. aborting.\n");
-        } else {
-            rtprintpanic!("thread panicked while panicking. aborting.\n");
-        }
+    // Indicate that we have finished executing the panic hook. After this point
+    // it is fine if there is a panic while executing destructors, as long as it
+    // it contained within a `catch_unwind`.
+    panic_count::finished_panic_hook();
+
+    if !can_unwind {
+        // If a thread panics while running destructors or tries to unwind
+        // through a nounwind function (e.g. extern "C") then we cannot continue
+        // unwinding and have to abort immediately.
+        rtprintpanic!("thread caused non-unwinding panic. aborting.\n");
         crate::sys::abort_internal();
     }
 
@@ -716,7 +730,7 @@ fn rust_panic_with_hook(
 /// This is the entry point for `resume_unwind`.
 /// It just forwards the payload to the panic runtime.
 pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
-    panic_count::increase();
+    panic_count::increase(false);
 
     struct RewrapBox(Box<dyn Any + Send>);
 
diff --git a/library/test/src/options.rs b/library/test/src/options.rs
index 75ec0b6..3eaad59 100644
--- a/library/test/src/options.rs
+++ b/library/test/src/options.rs
@@ -16,19 +16,21 @@ pub enum ShouldPanic {
 }
 
 /// Whether should console output be colored or not
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Default, Debug)]
 pub enum ColorConfig {
+    #[default]
     AutoColor,
     AlwaysColor,
     NeverColor,
 }
 
 /// Format of the test results output
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
 pub enum OutputFormat {
     /// Verbose output
     Pretty,
     /// Quiet output
+    #[default]
     Terse,
     /// JSON output
     Json,
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 8f8778e..311ac17 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -58,7 +58,6 @@
  "once_cell",
  "opener",
  "pretty_assertions",
- "semver",
  "serde",
  "serde_derive",
  "serde_json",
@@ -647,12 +646,6 @@
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
-name = "semver"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
-
-[[package]]
 name = "serde"
 version = "1.0.160"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 367c619..70ade77 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -57,7 +57,6 @@
 sysinfo = { version = "0.26.0", optional = true }
 clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
 clap_complete = "4.2.2"
-semver = "1.0.17"
 
 # Solaris doesn't support flock() and thus fd-lock is not option now
 [target.'cfg(not(target_os = "solaris"))'.dependencies]
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 50ace98..58d1926 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -226,16 +226,13 @@
 
 def default_build_triple(verbose):
     """Build triple as in LLVM"""
-    # If the user already has a host build triple with an existing `rustc`
-    # install, use their preference. This fixes most issues with Windows builds
-    # being detected as GNU instead of MSVC.
+    # If we're on Windows and have an existing `rustc` toolchain, use `rustc --version --verbose`
+    # to find our host target triple. This fixes an issue with Windows builds being detected
+    # as GNU instead of MSVC.
+    # Otherwise, detect it via `uname`
     default_encoding = sys.getdefaultencoding()
 
-    if sys.platform == 'darwin':
-        if verbose:
-            print("not using rustc detection as it is unreliable on macOS", file=sys.stderr)
-            print("falling back to auto-detect", file=sys.stderr)
-    else:
+    if platform_is_win32():
         try:
             version = subprocess.check_output(["rustc", "--version", "--verbose"],
                     stderr=subprocess.DEVNULL)
@@ -253,19 +250,17 @@
                 print("falling back to auto-detect", file=sys.stderr)
 
     required = not platform_is_win32()
-    ostype = require(["uname", "-s"], exit=required)
-    cputype = require(['uname', '-m'], exit=required)
+    uname = require(["uname", "-smp"], exit=required)
 
     # If we do not have `uname`, assume Windows.
-    if ostype is None or cputype is None:
+    if uname is None:
         return 'x86_64-pc-windows-msvc'
 
-    ostype = ostype.decode(default_encoding)
-    cputype = cputype.decode(default_encoding)
+    kernel, cputype, processor = uname.decode(default_encoding).split()
 
     # The goal here is to come up with the same triple as LLVM would,
     # at least for the subset of platforms we're willing to target.
-    ostype_mapper = {
+    kerneltype_mapper = {
         'Darwin': 'apple-darwin',
         'DragonFly': 'unknown-dragonfly',
         'FreeBSD': 'unknown-freebsd',
@@ -275,17 +270,18 @@
     }
 
     # Consider the direct transformation first and then the special cases
-    if ostype in ostype_mapper:
-        ostype = ostype_mapper[ostype]
-    elif ostype == 'Linux':
-        os_from_sp = subprocess.check_output(
-            ['uname', '-o']).strip().decode(default_encoding)
-        if os_from_sp == 'Android':
-            ostype = 'linux-android'
+    if kernel in kerneltype_mapper:
+        kernel = kerneltype_mapper[kernel]
+    elif kernel == 'Linux':
+        # Apple doesn't support `-o` so this can't be used in the combined
+        # uname invocation above
+        ostype = require(["uname", "-o"], exit=required).decode(default_encoding)
+        if ostype == 'Android':
+            kernel = 'linux-android'
         else:
-            ostype = 'unknown-linux-gnu'
-    elif ostype == 'SunOS':
-        ostype = 'pc-solaris'
+            kernel = 'unknown-linux-gnu'
+    elif kernel == 'SunOS':
+        kernel = 'pc-solaris'
         # On Solaris, uname -m will return a machine classification instead
         # of a cpu type, so uname -p is recommended instead.  However, the
         # output from that option is too generic for our purposes (it will
@@ -294,34 +290,34 @@
         cputype = require(['isainfo', '-k']).decode(default_encoding)
         # sparc cpus have sun as a target vendor
         if 'sparc' in cputype:
-            ostype = 'sun-solaris'
-    elif ostype.startswith('MINGW'):
+            kernel = 'sun-solaris'
+    elif kernel.startswith('MINGW'):
         # msys' `uname` does not print gcc configuration, but prints msys
         # configuration. so we cannot believe `uname -m`:
         # msys1 is always i686 and msys2 is always x86_64.
         # instead, msys defines $MSYSTEM which is MINGW32 on i686 and
         # MINGW64 on x86_64.
-        ostype = 'pc-windows-gnu'
+        kernel = 'pc-windows-gnu'
         cputype = 'i686'
         if os.environ.get('MSYSTEM') == 'MINGW64':
             cputype = 'x86_64'
-    elif ostype.startswith('MSYS'):
-        ostype = 'pc-windows-gnu'
-    elif ostype.startswith('CYGWIN_NT'):
+    elif kernel.startswith('MSYS'):
+        kernel = 'pc-windows-gnu'
+    elif kernel.startswith('CYGWIN_NT'):
         cputype = 'i686'
-        if ostype.endswith('WOW64'):
+        if kernel.endswith('WOW64'):
             cputype = 'x86_64'
-        ostype = 'pc-windows-gnu'
-    elif sys.platform == 'win32':
+        kernel = 'pc-windows-gnu'
+    elif platform_is_win32():
         # Some Windows platforms might have a `uname` command that returns a
         # non-standard string (e.g. gnuwin32 tools returns `windows32`). In
         # these cases, fall back to using sys.platform.
         return 'x86_64-pc-windows-msvc'
     else:
-        err = "unknown OS type: {}".format(ostype)
+        err = "unknown OS type: {}".format(kernel)
         sys.exit(err)
 
-    if cputype in ['powerpc', 'riscv'] and ostype == 'unknown-freebsd':
+    if cputype in ['powerpc', 'riscv'] and kernel == 'unknown-freebsd':
         cputype = subprocess.check_output(
               ['uname', '-p']).strip().decode(default_encoding)
     cputype_mapper = {
@@ -354,24 +350,23 @@
         cputype = cputype_mapper[cputype]
     elif cputype in {'xscale', 'arm'}:
         cputype = 'arm'
-        if ostype == 'linux-android':
-            ostype = 'linux-androideabi'
-        elif ostype == 'unknown-freebsd':
-            cputype = subprocess.check_output(
-                ['uname', '-p']).strip().decode(default_encoding)
-            ostype = 'unknown-freebsd'
+        if kernel == 'linux-android':
+            kernel = 'linux-androideabi'
+        elif kernel == 'unknown-freebsd':
+            cputype = processor
+            kernel = 'unknown-freebsd'
     elif cputype == 'armv6l':
         cputype = 'arm'
-        if ostype == 'linux-android':
-            ostype = 'linux-androideabi'
+        if kernel == 'linux-android':
+            kernel = 'linux-androideabi'
         else:
-            ostype += 'eabihf'
+            kernel += 'eabihf'
     elif cputype in {'armv7l', 'armv8l'}:
         cputype = 'armv7'
-        if ostype == 'linux-android':
-            ostype = 'linux-androideabi'
+        if kernel == 'linux-android':
+            kernel = 'linux-androideabi'
         else:
-            ostype += 'eabihf'
+            kernel += 'eabihf'
     elif cputype == 'mips':
         if sys.byteorder == 'big':
             cputype = 'mips'
@@ -387,14 +382,14 @@
         else:
             raise ValueError('unknown byteorder: {}'.format(sys.byteorder))
         # only the n64 ABI is supported, indicate it
-        ostype += 'abi64'
+        kernel += 'abi64'
     elif cputype == 'sparc' or cputype == 'sparcv9' or cputype == 'sparc64':
         pass
     else:
         err = "unknown cpu type: {}".format(cputype)
         sys.exit(err)
 
-    return "{}-{}".format(cputype, ostype)
+    return "{}-{}".format(cputype, kernel)
 
 
 @contextlib.contextmanager
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index cf7c659..2fa4455 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -264,7 +264,7 @@ fn intersection_removing_matches(
 
     /// A convenience wrapper for Steps which know they have no aliases and all their sets contain only a single path.
     ///
-    /// This can be used with [`ShouldRun::krate`], [`ShouldRun::path`], or [`ShouldRun::alias`].
+    /// This can be used with [`ShouldRun::crate_or_deps`], [`ShouldRun::path`], or [`ShouldRun::alias`].
     #[track_caller]
     pub fn assert_single_path(&self) -> &TaskPath {
         match self {
@@ -689,7 +689,8 @@ macro_rules! describe {
                 tool::Miri,
                 tool::CargoMiri,
                 llvm::Lld,
-                llvm::CrtBeginEnd
+                llvm::CrtBeginEnd,
+                tool::RustdocGUITest,
             ),
             Kind::Check | Kind::Clippy | Kind::Fix => describe!(
                 check::Std,
@@ -787,6 +788,7 @@ macro_rules! describe {
                 doc::EditionGuide,
                 doc::StyleGuide,
                 doc::Tidy,
+                doc::Bootstrap,
             ),
             Kind::Dist => describe!(
                 dist::Docs,
@@ -1915,10 +1917,10 @@ pub fn cargo(
         }
 
         // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
-        // This replaces spaces with newlines because RUSTDOCFLAGS does not
+        // This replaces spaces with tabs because RUSTDOCFLAGS does not
         // support arguments with regular spaces. Hopefully someday Cargo will
         // have space support.
-        let rust_version = self.rust_version().replace(' ', "\n");
+        let rust_version = self.rust_version().replace(' ', "\t");
         rustdocflags.arg("--crate-version").arg(&rust_version);
 
         // Environment variables *required* throughout the build
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index e192cda..41aca02 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -24,7 +24,6 @@
 use crate::flags::{Color, Flags, Warnings};
 use crate::util::{exe, output, t};
 use once_cell::sync::OnceCell;
-use semver::Version;
 use serde::{Deserialize, Deserializer};
 use serde_derive::Deserialize;
 
@@ -1118,7 +1117,6 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
             config.download_beta_toolchain();
             config.out.join(config.build.triple).join("stage0/bin/rustc")
         });
-
         config.initial_cargo = build
             .cargo
             .map(|cargo| {
@@ -1780,42 +1778,6 @@ pub fn default_codegen_backend(&self) -> Option<Interned<String>> {
         self.rust_codegen_backends.get(0).cloned()
     }
 
-    pub fn check_build_rustc_version(&self) {
-        if self.dry_run() {
-            return;
-        }
-
-        // check rustc version is same or lower with 1 apart from the building one
-        let mut cmd = Command::new(&self.initial_rustc);
-        cmd.arg("--version");
-        let rustc_output = output(&mut cmd)
-            .lines()
-            .next()
-            .unwrap()
-            .split(' ')
-            .nth(1)
-            .unwrap()
-            .split('-')
-            .next()
-            .unwrap()
-            .to_owned();
-        let rustc_version = Version::parse(&rustc_output.trim()).unwrap();
-        let source_version =
-            Version::parse(&fs::read_to_string(self.src.join("src/version")).unwrap().trim())
-                .unwrap();
-        if !(source_version == rustc_version
-            || (source_version.major == rustc_version.major
-                && source_version.minor == rustc_version.minor + 1))
-        {
-            let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1);
-            eprintln!(
-                "Unexpected rustc version: {}, we should use {}/{} to build source with {}",
-                rustc_version, prev_version, source_version, source_version
-            );
-            crate::detail_exit(1);
-        }
-    }
-
     /// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
     fn download_ci_rustc_commit(&self, download_rustc: Option<StringOrBool>) -> Option<String> {
         // If `download-rustc` is not set, default to rebuilding.
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 8f5d9bb..b52c3b6 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -839,6 +839,8 @@ fn run(self, builder: &Builder<'_>) {
                 )+
 
                 cargo.rustdocflag("--document-private-items");
+                // Since we always pass --document-private-items, there's no need to warn about linking to private items.
+                cargo.rustdocflag("-Arustdoc::private-intra-doc-links");
                 cargo.rustdocflag("--enable-index-page");
                 cargo.rustdocflag("--show-type-layout");
                 cargo.rustdocflag("--generate-link-to-definition");
@@ -882,7 +884,8 @@ fn run(self, builder: &Builder<'_>) {
         // "cargo-credential-wincred",
     ]
 );
-tool_doc!(Tidy, "tidy", "src/tools/tidy", ["tidy"]);
+tool_doc!(Tidy, "tidy", "src/tools/tidy", rustc_tool = false, ["tidy"]);
+tool_doc!(Bootstrap, "bootstrap", "src/bootstrap", rustc_tool = false, ["bootstrap"]);
 
 #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct ErrorIndex {
diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs
index 25df5b2..c7969d2 100644
--- a/src/bootstrap/download.rs
+++ b/src/bootstrap/download.rs
@@ -123,7 +123,7 @@ fn should_fix_bins_and_dylibs(&self) -> bool {
     /// This is only required on NixOS and uses the PatchELF utility to
     /// change the interpreter/RPATH of ELF executables.
     ///
-    /// Please see https://nixos.org/patchelf.html for more information
+    /// Please see <https://nixos.org/patchelf.html> for more information
     fn fix_bin_or_dylib(&self, fname: &Path) {
         assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true));
         println!("attempting to patch {}", fname.display());
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 6ee50ee..fb76dff 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -414,7 +414,6 @@ pub fn new(mut config: Config) -> Build {
                 bootstrap_out.display()
             )
         }
-        config.check_build_rustc_version();
 
         if rust_info.is_from_tarball() && config.description.is_none() {
             config.description = Some("built from a source tarball".to_owned());
@@ -1011,6 +1010,8 @@ fn msg_build(
     }
 
     /// Return a `Group` guard for a [`Step`] that is built for each `--stage`.
+    ///
+    /// [`Step`]: crate::builder::Step
     fn msg(
         &self,
         action: impl Into<Kind>,
@@ -1035,6 +1036,8 @@ fn msg(
     }
 
     /// Return a `Group` guard for a [`Step`] that is only built once and isn't affected by `--stage`.
+    ///
+    /// [`Step`]: crate::builder::Step
     fn msg_unstaged(
         &self,
         action: impl Into<Kind>,
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index 040a12f..3fd0cca 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -1017,7 +1017,7 @@ fn supported_sanitizers(
         "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
         "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
         "x86_64-unknown-linux-gnu" => {
-            common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
+            common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"])
         }
         "x86_64-unknown-linux-musl" => {
             common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs
index e19d56c..5990f33 100644
--- a/src/bootstrap/metrics.rs
+++ b/src/bootstrap/metrics.rs
@@ -14,6 +14,25 @@
 use std::time::{Duration, Instant, SystemTime};
 use sysinfo::{CpuExt, System, SystemExt};
 
+// Update this number whenever a breaking change is made to the build metrics.
+//
+// The output format is versioned for two reasons:
+//
+// - The metadata is intended to be consumed by external tooling, and exposing a format version
+//   helps the tools determine whether they're compatible with a metrics file.
+//
+// - If a developer enables build metrics in their local checkout, making a breaking change to the
+//   metrics format would result in a hard-to-diagnose error message when an existing metrics file
+//   is not compatible with the new changes. With a format version number, bootstrap can discard
+//   incompatible metrics files instead of appending metrics to them.
+//
+// Version changelog:
+//
+// - v0: initial version
+// - v1: replaced JsonNode::Test with JsonNode::TestSuite
+//
+const CURRENT_FORMAT_VERSION: usize = 1;
+
 pub(crate) struct BuildMetrics {
     state: RefCell<MetricsState>,
 }
@@ -57,7 +76,7 @@ pub(crate) fn enter_step<S: Step>(&self, step: &S, builder: &Builder<'_>) {
             duration_excluding_children_sec: Duration::ZERO,
 
             children: Vec::new(),
-            tests: Vec::new(),
+            test_suites: Vec::new(),
         });
     }
 
@@ -84,6 +103,17 @@ pub(crate) fn exit_step(&self, builder: &Builder<'_>) {
         }
     }
 
+    pub(crate) fn begin_test_suite(&self, metadata: TestSuiteMetadata, builder: &Builder<'_>) {
+        // Do not record dry runs, as they'd be duplicates of the actual steps.
+        if builder.config.dry_run() {
+            return;
+        }
+
+        let mut state = self.state.borrow_mut();
+        let step = state.running_steps.last_mut().unwrap();
+        step.test_suites.push(TestSuite { metadata, tests: Vec::new() });
+    }
+
     pub(crate) fn record_test(&self, name: &str, outcome: TestOutcome, builder: &Builder<'_>) {
         // Do not record dry runs, as they'd be duplicates of the actual steps.
         if builder.config.dry_run() {
@@ -91,12 +121,13 @@ pub(crate) fn record_test(&self, name: &str, outcome: TestOutcome, builder: &Bui
         }
 
         let mut state = self.state.borrow_mut();
-        state
-            .running_steps
-            .last_mut()
-            .unwrap()
-            .tests
-            .push(Test { name: name.to_string(), outcome });
+        let step = state.running_steps.last_mut().unwrap();
+
+        if let Some(test_suite) = step.test_suites.last_mut() {
+            test_suite.tests.push(Test { name: name.to_string(), outcome });
+        } else {
+            panic!("metrics.record_test() called without calling metrics.begin_test_suite() first");
+        }
     }
 
     fn collect_stats(&self, state: &mut MetricsState) {
@@ -131,7 +162,20 @@ pub(crate) fn persist(&self, build: &Build) {
         // Some of our CI builds consist of multiple independent CI invocations. Ensure all the
         // previous invocations are still present in the resulting file.
         let mut invocations = match std::fs::read(&dest) {
-            Ok(contents) => t!(serde_json::from_slice::<JsonRoot>(&contents)).invocations,
+            Ok(contents) => {
+                // We first parse just the format_version field to have the check succeed even if
+                // the rest of the contents are not valid anymore.
+                let version: OnlyFormatVersion = t!(serde_json::from_slice(&contents));
+                if version.format_version == CURRENT_FORMAT_VERSION {
+                    t!(serde_json::from_slice::<JsonRoot>(&contents)).invocations
+                } else {
+                    println!(
+                        "warning: overriding existing build/metrics.json, as it's not \
+                         compatible with build metrics format version {CURRENT_FORMAT_VERSION}."
+                    );
+                    Vec::new()
+                }
+            }
             Err(err) => {
                 if err.kind() != std::io::ErrorKind::NotFound {
                     panic!("failed to open existing metrics file at {}: {err}", dest.display());
@@ -149,7 +193,7 @@ pub(crate) fn persist(&self, build: &Build) {
             children: steps.into_iter().map(|step| self.prepare_json_step(step)).collect(),
         });
 
-        let json = JsonRoot { system_stats, invocations };
+        let json = JsonRoot { format_version: CURRENT_FORMAT_VERSION, system_stats, invocations };
 
         t!(std::fs::create_dir_all(dest.parent().unwrap()));
         let mut file = BufWriter::new(t!(File::create(&dest)));
@@ -159,11 +203,7 @@ pub(crate) fn persist(&self, build: &Build) {
     fn prepare_json_step(&self, step: StepMetrics) -> JsonNode {
         let mut children = Vec::new();
         children.extend(step.children.into_iter().map(|child| self.prepare_json_step(child)));
-        children.extend(
-            step.tests
-                .into_iter()
-                .map(|test| JsonNode::Test { name: test.name, outcome: test.outcome }),
-        );
+        children.extend(step.test_suites.into_iter().map(JsonNode::TestSuite));
 
         JsonNode::RustbuildStep {
             type_: step.type_,
@@ -198,17 +238,14 @@ struct StepMetrics {
     duration_excluding_children_sec: Duration,
 
     children: Vec<StepMetrics>,
-    tests: Vec<Test>,
-}
-
-struct Test {
-    name: String,
-    outcome: TestOutcome,
+    test_suites: Vec<TestSuite>,
 }
 
 #[derive(Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 struct JsonRoot {
+    #[serde(default)] // For version 0 the field was not present.
+    format_version: usize,
     system_stats: JsonInvocationSystemStats,
     invocations: Vec<JsonInvocation>,
 }
@@ -237,11 +274,39 @@ enum JsonNode {
 
         children: Vec<JsonNode>,
     },
-    Test {
-        name: String,
-        #[serde(flatten)]
-        outcome: TestOutcome,
+    TestSuite(TestSuite),
+}
+
+#[derive(Serialize, Deserialize)]
+struct TestSuite {
+    metadata: TestSuiteMetadata,
+    tests: Vec<Test>,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(tag = "kind", rename_all = "snake_case")]
+pub(crate) enum TestSuiteMetadata {
+    CargoPackage {
+        crates: Vec<String>,
+        target: String,
+        host: String,
+        stage: u32,
     },
+    Compiletest {
+        suite: String,
+        mode: String,
+        compare_mode: Option<String>,
+        target: String,
+        host: String,
+        stage: u32,
+    },
+}
+
+#[derive(Serialize, Deserialize)]
+pub(crate) struct Test {
+    name: String,
+    #[serde(flatten)]
+    outcome: TestOutcome,
 }
 
 #[derive(Serialize, Deserialize)]
@@ -266,3 +331,9 @@ struct JsonInvocationSystemStats {
 struct JsonStepSystemStats {
     cpu_utilization_percent: f64,
 }
+
+#[derive(Deserialize)]
+struct OnlyFormatVersion {
+    #[serde(default)] // For version 0 the field was not present.
+    format_version: usize,
+}
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 2b72d6c..44cd84b 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -317,6 +317,17 @@ fn run(self, builder: &Builder<'_>) {
         cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
         cargo.env("PATH", &path_for_cargo(builder, compiler));
 
+        #[cfg(feature = "build-metrics")]
+        builder.metrics.begin_test_suite(
+            crate::metrics::TestSuiteMetadata::CargoPackage {
+                crates: vec!["cargo".into()],
+                target: self.host.triple.to_string(),
+                host: self.host.triple.to_string(),
+                stage: self.stage,
+            },
+            builder,
+        );
+
         let _time = util::timeit(&builder);
         add_flags_and_try_run_tests(builder, &mut cargo);
     }
@@ -944,28 +955,6 @@ fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
         .or_else(|| get_browser_ui_test_version_inner(npm, true))
 }
 
-fn compare_browser_ui_test_version(installed_version: &str, src: &Path) {
-    match fs::read_to_string(
-        src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"),
-    ) {
-        Ok(v) => {
-            if v.trim() != installed_version {
-                eprintln!(
-                    "⚠️ Installed version of browser-ui-test (`{}`) is different than the \
-                     one used in the CI (`{}`)",
-                    installed_version, v
-                );
-                eprintln!(
-                    "You can install this version using `npm update browser-ui-test` or by using \
-                     `npm install browser-ui-test@{}`",
-                    v,
-                );
-            }
-        }
-        Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e),
-    }
-}
-
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocGUI {
     pub target: TargetSelection,
@@ -997,79 +986,30 @@ fn make_run(run: RunConfig<'_>) {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available");
-        let npm = builder.config.npm.as_ref().expect("npm isn't available");
-
         builder.ensure(compile::Std::new(self.compiler, self.target));
 
-        // The goal here is to check if the necessary packages are installed, and if not, we
-        // panic.
-        match get_browser_ui_test_version(&npm) {
-            Some(version) => {
-                // We also check the version currently used in CI and emit a warning if it's not the
-                // same one.
-                compare_browser_ui_test_version(&version, &builder.build.src);
-            }
-            None => {
-                eprintln!(
-                    "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
-                     dependency is missing",
-                );
-                eprintln!(
-                    "If you want to install the `{0}` dependency, run `npm install {0}`",
-                    "browser-ui-test",
-                );
-                panic!("Cannot run rustdoc-gui tests");
-            }
-        }
+        let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);
 
         let out_dir = builder.test_out(self.target).join("rustdoc-gui");
-
-        // We remove existing folder to be sure there won't be artifacts remaining.
         builder.clear_if_dirty(&out_dir, &builder.rustdoc(self.compiler));
 
-        let src_path = builder.build.src.join("tests/rustdoc-gui/src");
-        // We generate docs for the libraries present in the rustdoc-gui's src folder.
-        for entry in src_path.read_dir().expect("read_dir call failed") {
-            if let Ok(entry) = entry {
-                let path = entry.path();
-
-                if !path.is_dir() {
-                    continue;
-                }
-
-                let mut cargo = Command::new(&builder.initial_cargo);
-                cargo
-                    .arg("doc")
-                    .arg("--target-dir")
-                    .arg(&out_dir)
-                    .env("RUSTC_BOOTSTRAP", "1")
-                    .env("RUSTDOC", builder.rustdoc(self.compiler))
-                    .env("RUSTC", builder.rustc(self.compiler))
-                    .current_dir(path);
-                // FIXME: implement a `// compile-flags` command or similar
-                //        instead of hard-coding this test
-                if entry.file_name() == "link_to_definition" {
-                    cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition");
-                } else if entry.file_name() == "scrape_examples" {
-                    cargo.arg("-Zrustdoc-scrape-examples");
-                } else if entry.file_name() == "extend_css" {
-                    cargo.env("RUSTDOCFLAGS", &format!("--extend-css extra.css"));
-                }
-                builder.run(&mut cargo);
-            }
+        if let Some(src) = builder.config.src.to_str() {
+            cmd.arg("--rust-src").arg(src);
         }
 
-        // We now run GUI tests.
-        let mut command = Command::new(&nodejs);
-        command
-            .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
-            .arg("--jobs")
-            .arg(&builder.jobs().to_string())
-            .arg("--doc-folder")
-            .arg(out_dir.join("doc"))
-            .arg("--tests-folder")
-            .arg(builder.build.src.join("tests/rustdoc-gui"));
+        if let Some(out_dir) = out_dir.to_str() {
+            cmd.arg("--out-dir").arg(out_dir);
+        }
+
+        if let Some(initial_cargo) = builder.config.initial_cargo.to_str() {
+            cmd.arg("--initial-cargo").arg(initial_cargo);
+        }
+
+        cmd.arg("--jobs").arg(builder.jobs().to_string());
+
+        cmd.env("RUSTDOC", builder.rustdoc(self.compiler))
+            .env("RUSTC", builder.rustc(self.compiler));
+
         for path in &builder.paths {
             if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
                 if !p.ends_with(".goml") {
@@ -1077,14 +1017,25 @@ fn run(self, builder: &Builder<'_>) {
                     panic!("Cannot run rustdoc-gui tests");
                 }
                 if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
-                    command.arg("--file").arg(name);
+                    cmd.arg("--goml-file").arg(name);
                 }
             }
         }
+
         for test_arg in builder.config.test_args() {
-            command.arg(test_arg);
+            cmd.arg("--test-arg").arg(test_arg);
         }
-        builder.run(&mut command);
+
+        if let Some(ref nodejs) = builder.config.nodejs {
+            cmd.arg("--nodejs").arg(nodejs);
+        }
+
+        if let Some(ref npm) = builder.config.npm {
+            cmd.arg("--npm").arg(npm);
+        }
+
+        let _time = util::timeit(&builder);
+        crate::render_tests::try_run_tests(builder, &mut cmd);
     }
 }
 
@@ -1759,6 +1710,19 @@ fn run(self, builder: &Builder<'_>) {
 
         builder.ci_env.force_coloring_in_ci(&mut cmd);
 
+        #[cfg(feature = "build-metrics")]
+        builder.metrics.begin_test_suite(
+            crate::metrics::TestSuiteMetadata::Compiletest {
+                suite: suite.into(),
+                mode: mode.into(),
+                compare_mode: None,
+                target: self.target.triple.to_string(),
+                host: self.compiler.host.triple.to_string(),
+                stage: self.compiler.stage,
+            },
+            builder,
+        );
+
         builder.info(&format!(
             "Check compiletest suite={} mode={} ({} -> {})",
             suite, mode, &compiler.host, target
@@ -1768,6 +1732,20 @@ fn run(self, builder: &Builder<'_>) {
 
         if let Some(compare_mode) = compare_mode {
             cmd.arg("--compare-mode").arg(compare_mode);
+
+            #[cfg(feature = "build-metrics")]
+            builder.metrics.begin_test_suite(
+                crate::metrics::TestSuiteMetadata::Compiletest {
+                    suite: suite.into(),
+                    mode: mode.into(),
+                    compare_mode: Some(compare_mode.into()),
+                    target: self.target.triple.to_string(),
+                    host: self.compiler.host.triple.to_string(),
+                    stage: self.compiler.stage,
+                },
+                builder,
+            );
+
             builder.info(&format!(
                 "Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
                 suite, mode, compare_mode, &compiler.host, target
@@ -2094,6 +2072,17 @@ fn run_cargo_test(
     let mut cargo =
         prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder);
     let _time = util::timeit(&builder);
+
+    #[cfg(feature = "build-metrics")]
+    builder.metrics.begin_test_suite(
+        crate::metrics::TestSuiteMetadata::CargoPackage {
+            crates: crates.iter().map(|c| c.to_string()).collect(),
+            target: target.triple.to_string(),
+            host: compiler.host.triple.to_string(),
+            stage: compiler.stage,
+        },
+        builder,
+    );
     add_flags_and_try_run_tests(builder, &mut cargo)
 }
 
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index f13d365..b3791ef 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -302,6 +302,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
     GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
     SuggestTests, "src/tools/suggest-tests", "suggest-tests";
     GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
+    RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
 );
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 2e1adbf..9bfdc77 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -488,7 +488,7 @@ fn GetFullPathNameW(
     }
 }
 
-/// Adapted from https://github.com/llvm/llvm-project/blob/782e91224601e461c019e0a4573bbccc6094fbcd/llvm/cmake/modules/HandleLLVMOptions.cmake#L1058-L1079
+/// Adapted from <https://github.com/llvm/llvm-project/blob/782e91224601e461c019e0a4573bbccc6094fbcd/llvm/cmake/modules/HandleLLVMOptions.cmake#L1058-L1079>
 ///
 /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource
 /// directory to the linker flags, otherwise there will be linker errors about the profiler runtime
diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md
index a82a532..1720487 100644
--- a/src/doc/rustc/src/exploit-mitigations.md
+++ b/src/doc/rustc/src/exploit-mitigations.md
@@ -55,88 +55,18 @@
 Summary of exploit mitigations supported by the Rust compiler when building
 programs for the Linux operating system on the AMD64 architecture and
 equivalent.
-<table class="table">
-  <tr>
-   <td><strong>Exploit mitigation</strong>
-   </td>
-   <td><strong>Supported and enabled by default</strong>
-   </td>
-   <td><strong>Since</strong>
-   </td>
-  </tr>
-  <tr>
-   <td>Position-independent executable
-   </td>
-   <td>Yes
-   </td>
-   <td>0.12.0 (2014-10-09)
-   </td>
-  </tr>
-  <tr>
-   <td>Integer overflow checks
-   </td>
-   <td>Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled)
-   </td>
-   <td>1.1.0 (2015-06-25)
-   </td>
-  </tr>
-  <tr>
-   <td>Non-executable memory regions
-   </td>
-   <td>Yes
-   </td>
-   <td>1.8.0 (2016-04-14)
-   </td>
-  </tr>
-  <tr>
-   <td>Stack clashing protection
-   </td>
-   <td>Yes
-   </td>
-   <td>1.20.0 (2017-08-31)
-   </td>
-  </tr>
-  <tr>
-   <td>Read-only relocations and immediate binding
-   </td>
-   <td>Yes
-   </td>
-   <td>1.21.0 (2017-10-12)
-   </td>
-  </tr>
-  <tr>
-   <td>Heap corruption protection
-   </td>
-   <td>Yes
-   </td>
-   <td>1.32.0 (2019-01-17) (via operating system default or specified allocator)
-   </td>
-  </tr>
-  <tr>
-   <td>Stack smashing protection
-   </td>
-   <td>Yes
-   </td>
-   <td>Nightly
-   </td>
-  </tr>
-  <tr>
-   <td>Forward-edge control flow protection
-   </td>
-   <td>Yes
-   </td>
-   <td>Nightly
-   </td>
-  </tr>
-  <tr>
-   <td>Backward-edge control flow protection (e.g., shadow and safe stack)
-   </td>
-   <td>No
-   </td>
-   <td>
-   </td>
-  </tr>
-</table>
+
+| Exploit mitigation | Supported and enabled by default | Since |
+| - | - | - |
+| Position-independent executable | Yes | 0.12.0 (2014-10-09) |
+| Integer overflow checks | Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) | 1.1.0 (2015-06-25) |
+| Non-executable memory regions | Yes | 1.8.0 (2016-04-14) |
+| Stack clashing protection | Yes | 1.20.0 (2017-08-31) |
+| Read-only relocations and immediate binding | Yes | 1.21.0 (2017-10-12) |
+| Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) |
+| Stack smashing protection | Yes | Nightly |
+| Forward-edge control flow protection | Yes | Nightly |
+| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly |
 
 <small id="fn:1">1\. See
 <https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec>
@@ -513,20 +443,21 @@
 protection, such as ARM Pointer Authentication, and Intel Shadow Stack as
 part of Intel CET.
 
-The Rust compiler does not support shadow or safe stack. There is work
-currently ongoing to add support for the sanitizers[40], which may or may
-not include support for safe stack<sup id="fnref:7" role="doc-noteref"><a
-href="#fn:7" class="footnote">7</a></sup>.
+The Rust compiler supports shadow stack for aarch64 only
+<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote">7</a></sup>
+on nightly Rust compilers [43]-[44]. Safe stack is available on nightly
+Rust compilers [45]-[46].
 
 ```text
 $ readelf -s target/release/hello-rust | grep __safestack_init
+  1177: 00000000000057b0   444 FUNC    GLOBAL DEFAULT    9 __safestack_init
 ```
 Fig. 16. Checking if LLVM SafeStack is enabled for a given binary.
 
 The presence of the `__safestack_init` symbol indicates that LLVM SafeStack
-is enabled for a given binary. Conversely, the absence of the
+is enabled for a given binary (see Fig. 16). Conversely, the absence of the
 `__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a
-given binary (see Fig. 16).
+given binary.
 
 <small id="fn:7">7\. The shadow stack implementation for the AMD64
 architecture and equivalent in LLVM was removed due to performance and
@@ -698,3 +629,15 @@
 
 42. bbjornse. “add codegen option for using LLVM stack smash protection #84197.”
     GitHub. <https://github.com/rust-lang/rust/pull/84197>
+
+43. ivanloz. “Add support for LLVM ShadowCallStack. #98208.” GitHub.
+    <https://github.com/rust-lang/rust/pull/98208>.
+
+44. “ShadowCallStack.” The Rust Unstable Book.
+    [https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#shadowcallstack](../unstable-book/compiler-flags/sanitizer.html#shadowcallstack).
+
+45. W. Wiser. “Add support for LLVM SafeStack #112000” GitHub.
+    <https://github.com/rust-lang/rust/pull/112000>
+
+46. “SafeStack.” The Rust Unstable Book.
+    [https://doc.rust-lang/org/unstable-book/compiler-flags/sanitizer.html#safestack](../unstable-book/compiler-flags/sanitizer.html#safestack).
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index aa776da..49389b2 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -21,7 +21,8 @@
 * [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads.
 * [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on
   Armv8.5-A Memory Tagging Extension.
-* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection.
+* [SafeStack](#safestack) provides backward-edge control flow protection by separating the stack into safe and unsafe regions.
+* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection (aarch64 only).
 * [ThreadSanitizer](#threadsanitizer) a fast data race detector.
 
 To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
@@ -712,6 +713,16 @@
 
 See the [LLVM MemTagSanitizer documentation][llvm-memtag] for more details.
 
+# SafeStack
+
+SafeStack provides backward edge control flow protection by separating the stack into data which is only accessed safely (the safe stack) and all other data (the unsafe stack).
+
+SafeStack can be enabled with the `-Zsanitizer=safestack` option and is supported on the following targets:
+
+* `x86_64-unknown-linux-gnu`
+
+See the [Clang SafeStack documentation][clang-safestack] for more details.
+
 # ShadowCallStack
 
 ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack.
@@ -828,6 +839,7 @@
 [clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
+[clang-safestack]: https://clang.llvm.org/docs/SafeStack.html
 [clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
 [linux-kasan]: https://www.kernel.org/doc/html/latest/dev-tools/kasan.html
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index e4c05b5..7d3ccb9 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -21,7 +21,7 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
         let mut impls = Vec::new();
         for trait_def_id in cx.tcx.all_traits() {
             if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id)
-                || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some()
+                || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some()
             {
                 continue;
             }
@@ -34,13 +34,13 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                     impl_def_id
                 );
                 let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
-                if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) {
+                if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
                     continue;
                 }
                 let infcx = cx.tcx.infer_ctxt().build();
                 let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
                 let impl_ty = ty.subst(infcx.tcx, substs);
-                let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs);
+                let param_env = EarlyBinder::new(param_env).subst(infcx.tcx, substs);
 
                 let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
                 let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
@@ -87,7 +87,7 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                     trait_ref, ty
                 );
 
-                cx.generated_synthetics.insert((ty.0, trait_def_id));
+                cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id));
 
                 impls.push(Item {
                     name: None,
@@ -104,10 +104,10 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                         // the post-inference `trait_ref`, as it's more accurate.
                         trait_: Some(clean_trait_ref_with_bindings(
                             cx,
-                            ty::Binder::dummy(trait_ref.0),
+                            ty::Binder::dummy(trait_ref.skip_binder()),
                             ThinVec::new(),
                         )),
-                        for_: clean_middle_ty(ty::Binder::dummy(ty.0), cx, None),
+                        for_: clean_middle_ty(ty::Binder::dummy(ty.skip_binder()), cx, None),
                         items: cx
                             .tcx
                             .associated_items(impl_def_id)
@@ -116,7 +116,7 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                             .collect::<Vec<_>>(),
                         polarity: ty::ImplPolarity::Positive,
                         kind: ImplKind::Blanket(Box::new(clean_middle_ty(
-                            ty::Binder::dummy(trait_ref.0.self_ty()),
+                            ty::Binder::dummy(trait_ref.skip_binder().self_ty()),
                             cx,
                             None,
                         ))),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index c852f9c..7dc08b3 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -355,9 +355,9 @@ pub(crate) fn build_impl(
         return;
     }
 
-    let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");
-
     let tcx = cx.tcx;
+    let _prof_timer = tcx.sess.prof.generic_activity("build_impl");
+
     let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);
 
     // Only inline impl if the implemented trait is
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 59a3e63..03adc19 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2592,7 +2592,8 @@ fn clean_use_statement_inner<'tcx>(
     } else {
         if inline_attr.is_none()
             && let Res::Def(DefKind::Mod, did) = path.res
-            && !did.is_local() && did.is_crate_root()
+            && !did.is_local()
+            && did.is_crate_root()
         {
             // if we're `pub use`ing an extern crate root, don't inline it unless we
             // were specifically asked for it
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 17aa6b3..366f939 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -193,7 +193,7 @@ pub(crate) fn build_deref_target_impls(
         };
 
         if let Some(prim) = target.primitive_type() {
-            let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls");
+            let _prof_timer = tcx.sess.prof.generic_activity("build_primitive_inherent_impls");
             for did in prim.impls(tcx).filter(|did| !did.is_local()) {
                 inline::build_impl(cx, did, None, ret);
             }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index dfa4b09..9f08609 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -314,7 +314,6 @@ pub(crate) fn from_matches(
         matches: &getopts::Matches,
         args: Vec<String>,
     ) -> Result<(Options, RenderOptions), i32> {
-        let args = &args[1..];
         // Check for unstable options.
         nightly_options::check_nightly_options(matches, &opts());
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index c4758fd..8aaad8b 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -147,7 +147,7 @@ pub(crate) fn populate(cx: &mut DocContext<'_>, mut krate: clean::Crate) -> clea
 
         // Cache where all our extern crates are located
         // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
-        for &crate_num in cx.tcx.crates(()) {
+        for &crate_num in tcx.crates(()) {
             let e = ExternalCrate { crate_num };
 
             let name = e.name(tcx);
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 09e7ed2..9bb2002 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1237,7 +1237,27 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
 pub(crate) struct MarkdownLink {
     pub kind: LinkType,
     pub link: String,
-    pub range: Range<usize>,
+    pub range: MarkdownLinkRange,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum MarkdownLinkRange {
+    /// Normally, markdown link warnings point only at the destination.
+    Destination(Range<usize>),
+    /// In some cases, it's not possible to point at the destination.
+    /// Usually, this happens because backslashes `\\` are used.
+    /// When that happens, point at the whole link, and don't provide structured suggestions.
+    WholeLink(Range<usize>),
+}
+
+impl MarkdownLinkRange {
+    /// Extracts the inner range.
+    pub fn inner_range(&self) -> &Range<usize> {
+        match self {
+            MarkdownLinkRange::Destination(range) => range,
+            MarkdownLinkRange::WholeLink(range) => range,
+        }
+    }
 }
 
 pub(crate) fn markdown_links<R>(
@@ -1257,9 +1277,9 @@ pub(crate) fn markdown_links<R>(
         if md_start <= s_start && s_end <= md_end {
             let start = s_start.offset_from(md_start) as usize;
             let end = s_end.offset_from(md_start) as usize;
-            start..end
+            MarkdownLinkRange::Destination(start..end)
         } else {
-            fallback
+            MarkdownLinkRange::WholeLink(fallback)
         }
     };
 
@@ -1267,6 +1287,7 @@ pub(crate) fn markdown_links<R>(
         // For diagnostics, we want to underline the link's definition but `span` will point at
         // where the link is used. This is a problem for reference-style links, where the definition
         // is separate from the usage.
+
         match link {
             // `Borrowed` variant means the string (the link's destination) may come directly from
             // the markdown text and we can locate the original link destination.
@@ -1275,10 +1296,82 @@ pub(crate) fn markdown_links<R>(
             CowStr::Borrowed(s) => locate(s, span),
 
             // For anything else, we can only use the provided range.
-            CowStr::Boxed(_) | CowStr::Inlined(_) => span,
+            CowStr::Boxed(_) | CowStr::Inlined(_) => MarkdownLinkRange::WholeLink(span),
         }
     };
 
+    let span_for_offset_backward = |span: Range<usize>, open: u8, close: u8| {
+        let mut open_brace = !0;
+        let mut close_brace = !0;
+        for (i, b) in md.as_bytes()[span.clone()].iter().copied().enumerate().rev() {
+            let i = i + span.start;
+            if b == close {
+                close_brace = i;
+                break;
+            }
+        }
+        if close_brace < span.start || close_brace >= span.end {
+            return MarkdownLinkRange::WholeLink(span);
+        }
+        let mut nesting = 1;
+        for (i, b) in md.as_bytes()[span.start..close_brace].iter().copied().enumerate().rev() {
+            let i = i + span.start;
+            if b == close {
+                nesting += 1;
+            }
+            if b == open {
+                nesting -= 1;
+            }
+            if nesting == 0 {
+                open_brace = i;
+                break;
+            }
+        }
+        assert!(open_brace != close_brace);
+        if open_brace < span.start || open_brace >= span.end {
+            return MarkdownLinkRange::WholeLink(span);
+        }
+        // do not actually include braces in the span
+        let range = (open_brace + 1)..close_brace;
+        MarkdownLinkRange::Destination(range.clone())
+    };
+
+    let span_for_offset_forward = |span: Range<usize>, open: u8, close: u8| {
+        let mut open_brace = !0;
+        let mut close_brace = !0;
+        for (i, b) in md.as_bytes()[span.clone()].iter().copied().enumerate() {
+            let i = i + span.start;
+            if b == open {
+                open_brace = i;
+                break;
+            }
+        }
+        if open_brace < span.start || open_brace >= span.end {
+            return MarkdownLinkRange::WholeLink(span);
+        }
+        let mut nesting = 0;
+        for (i, b) in md.as_bytes()[open_brace..span.end].iter().copied().enumerate() {
+            let i = i + open_brace;
+            if b == close {
+                nesting -= 1;
+            }
+            if b == open {
+                nesting += 1;
+            }
+            if nesting == 0 {
+                close_brace = i;
+                break;
+            }
+        }
+        assert!(open_brace != close_brace);
+        if open_brace < span.start || open_brace >= span.end {
+            return MarkdownLinkRange::WholeLink(span);
+        }
+        // do not actually include braces in the span
+        let range = (open_brace + 1)..close_brace;
+        MarkdownLinkRange::Destination(range.clone())
+    };
+
     Parser::new_with_broken_link_callback(
         md,
         main_body_opts(),
@@ -1287,11 +1380,20 @@ pub(crate) fn markdown_links<R>(
     .into_offset_iter()
     .filter_map(|(event, span)| match event {
         Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
-            preprocess_link(MarkdownLink {
-                kind: link_type,
-                range: span_for_link(&dest, span),
-                link: dest.into_string(),
-            })
+            let range = match link_type {
+                // Link is pulled from the link itself.
+                LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => {
+                    span_for_offset_backward(span, b'[', b']')
+                }
+                LinkType::CollapsedUnknown => span_for_offset_forward(span, b'[', b']'),
+                LinkType::Inline => span_for_offset_backward(span, b'(', b')'),
+                // Link is pulled from elsewhere in the document.
+                LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => {
+                    span_for_link(&dest, span)
+                }
+                LinkType::Autolink | LinkType::Email => unreachable!(),
+            };
+            preprocess_link(MarkdownLink { kind: link_type, range, link: dest.into_string() })
         }
         _ => None,
     })
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 76c8e08..d2dc47a 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -9,6 +9,8 @@
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
+use std::borrow::Borrow;
+use std::cell::{RefCell, RefMut};
 use std::cmp::Ordering;
 use std::fmt;
 use std::rc::Rc;
@@ -216,6 +218,53 @@ fn toggle_close(mut w: impl fmt::Write) {
     w.write_str("</details>").unwrap();
 }
 
+trait ItemTemplate<'a, 'cx: 'a>: askama::Template + fmt::Display {
+    fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>);
+}
+
+fn item_template_document<'a: 'b, 'b, 'cx: 'a>(
+    templ: &'b impl ItemTemplate<'a, 'cx>,
+) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+    display_fn(move |f| {
+        let (item, mut cx) = templ.item_and_mut_cx();
+        let v = document(*cx, item, None, HeadingOffset::H2);
+        write!(f, "{v}")
+    })
+}
+
+fn item_template_document_type_layout<'a: 'b, 'b, 'cx: 'a>(
+    templ: &'b impl ItemTemplate<'a, 'cx>,
+) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+    display_fn(move |f| {
+        let (item, cx) = templ.item_and_mut_cx();
+        let def_id = item.item_id.expect_def_id();
+        let v = document_type_layout(*cx, def_id);
+        write!(f, "{v}")
+    })
+}
+
+fn item_template_render_attributes_in_pre<'a: 'b, 'b, 'cx: 'a>(
+    templ: &'b impl ItemTemplate<'a, 'cx>,
+) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+    display_fn(move |f| {
+        let (item, cx) = templ.item_and_mut_cx();
+        let tcx = cx.tcx();
+        let v = render_attributes_in_pre(item, "", tcx);
+        write!(f, "{v}")
+    })
+}
+
+fn item_template_render_assoc_items<'a: 'b, 'b, 'cx: 'a>(
+    templ: &'b impl ItemTemplate<'a, 'cx>,
+) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+    display_fn(move |f| {
+        let (item, mut cx) = templ.item_and_mut_cx();
+        let def_id = item.item_id.expect_def_id();
+        let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All);
+        write!(f, "{v}")
+    })
+}
+
 fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) {
     write!(w, "{}", document(cx, item, None, HeadingOffset::H2));
 
@@ -356,18 +405,18 @@ fn cmp(
 
             clean::ImportItem(ref import) => {
                 let stab_tags = if let Some(import_def_id) = import.source.did {
-                    let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id);
+                    let ast_attrs = tcx.get_attrs_unchecked(import_def_id);
                     let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs));
 
                     // Just need an item with the correct def_id and attrs
                     let import_item = clean::Item {
                         item_id: import_def_id.into(),
                         attrs: import_attrs,
-                        cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg),
+                        cfg: ast_attrs.cfg(tcx, &cx.cache().hidden_cfg),
                         ..myitem.clone()
                     };
 
-                    let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()).to_string());
+                    let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string());
                     stab_tags
                 } else {
                     None
@@ -405,8 +454,7 @@ fn cmp(
 
                 let unsafety_flag = match *myitem.kind {
                     clean::FunctionItem(_) | clean::ForeignFunctionItem(_)
-                        if myitem.fn_header(cx.tcx()).unwrap().unsafety
-                            == hir::Unsafety::Unsafe =>
+                        if myitem.fn_header(tcx).unwrap().unsafety == hir::Unsafety::Unsafe =>
                     {
                         "<sup title=\"unsafe function\">⚠</sup>"
                     }
@@ -439,7 +487,7 @@ fn cmp(
                      {docs_before}{docs}{docs_after}",
                     name = myitem.name.unwrap(),
                     visibility_emoji = visibility_emoji,
-                    stab_tags = extra_info_tags(myitem, item, cx.tcx()),
+                    stab_tags = extra_info_tags(myitem, item, tcx),
                     class = myitem.type_(),
                     unsafety_flag = unsafety_flag,
                     href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
@@ -886,7 +934,7 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
             write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
 
             for implementor in foreign {
-                let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx());
+                let provided_methods = implementor.inner_impl().provided_trait_methods(tcx);
                 let assoc_link =
                     AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods);
                 render_impl(
@@ -919,7 +967,7 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
         }
         w.write_str("</div>");
 
-        if t.is_auto(cx.tcx()) {
+        if t.is_auto(tcx) {
             write_small_section_header(
                 w,
                 "synthetic-implementors",
@@ -948,7 +996,7 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
             "<div id=\"implementors-list\"></div>",
         );
 
-        if t.is_auto(cx.tcx()) {
+        if t.is_auto(tcx) {
             write_small_section_header(
                 w,
                 "synthetic-implementors",
@@ -1131,32 +1179,18 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
     #[derive(Template)]
     #[template(path = "item_union.html")]
     struct ItemUnion<'a, 'cx> {
-        cx: std::cell::RefCell<&'a mut Context<'cx>>,
+        cx: RefCell<&'a mut Context<'cx>>,
         it: &'a clean::Item,
         s: &'a clean::Union,
     }
 
+    impl<'a, 'cx: 'a> ItemTemplate<'a, 'cx> for ItemUnion<'a, 'cx> {
+        fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>) {
+            (self.it, self.cx.borrow_mut())
+        }
+    }
+
     impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
-        fn render_assoc_items<'b>(
-            &'b self,
-        ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
-                let def_id = self.it.item_id.expect_def_id();
-                let mut cx = self.cx.borrow_mut();
-                let v = render_assoc_items(*cx, self.it, def_id, AssocItemRender::All);
-                write!(f, "{v}")
-            })
-        }
-        fn document_type_layout<'b>(
-            &'b self,
-        ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
-                let def_id = self.it.item_id.expect_def_id();
-                let cx = self.cx.borrow_mut();
-                let v = document_type_layout(*cx, def_id);
-                write!(f, "{v}")
-            })
-        }
         fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
             display_fn(move |f| {
                 let cx = self.cx.borrow_mut();
@@ -1164,22 +1198,6 @@ fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Capture
                 write!(f, "{v}")
             })
         }
-        fn render_attributes_in_pre<'b>(
-            &'b self,
-        ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
-                let tcx = self.cx.borrow().tcx();
-                let v = render_attributes_in_pre(self.it, "", tcx);
-                write!(f, "{v}")
-            })
-        }
-        fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            display_fn(move |f| {
-                let mut cx = self.cx.borrow_mut();
-                let v = document(*cx, self.it, None, HeadingOffset::H2);
-                write!(f, "{v}")
-            })
-        }
         fn document_field<'b>(
             &'b self,
             field: &'a clean::Item,
@@ -1219,7 +1237,7 @@ fn fields_iter(
         }
     }
 
-    ItemUnion { cx: std::cell::RefCell::new(cx), it, s }.render_into(w).unwrap();
+    ItemUnion { cx: RefCell::new(cx), it, s }.render_into(w).unwrap();
 }
 
 fn print_tuple_struct_fields<'a, 'cx: 'a>(
@@ -1541,11 +1559,12 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
     write!(w, "{}", document_type_layout(cx, def_id));
 }
 
-fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
-    wrap_item(w, |w| {
-        render_attributes_in_code(w, it, cx.tcx());
+fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
+    let mut buffer = Buffer::new();
+    wrap_item(&mut buffer, |buffer| {
+        render_attributes_in_code(buffer, it, cx.tcx());
         write!(
-            w,
+            buffer,
             "{vis}static {mutability}{name}: {typ}",
             vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
             mutability = s.mutability.print_with_space(),
@@ -1553,24 +1572,29 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
             typ = s.type_.print(cx)
         );
     });
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+
+    write!(w, "{}", buffer.into_inner()).unwrap();
+
+    write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
 }
 
-fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
-    wrap_item(w, |w| {
-        w.write_str("extern {\n");
-        render_attributes_in_code(w, it, cx.tcx());
+fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) {
+    let mut buffer = Buffer::new();
+    wrap_item(&mut buffer, |buffer| {
+        buffer.write_str("extern {\n");
+        render_attributes_in_code(buffer, it, cx.tcx());
         write!(
-            w,
+            buffer,
             "    {}type {};\n}}",
             visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
             it.name.unwrap(),
         );
     });
 
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
+    write!(w, "{}{}", buffer.into_inner(), document(cx, it, None, HeadingOffset::H2)).unwrap();
 
     write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
+        .unwrap();
 }
 
 fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index 22aec62..c9b95b1 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -54,13 +54,13 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
                     } else if let Primitive::Int(i, _) = tag.primitive() {
                         i.size().bytes()
                     } else {
-                        span_bug!(cx.tcx().def_span(ty_def_id), "tag is neither niche nor int")
+                        span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int")
                     };
                 variants
                     .iter_enumerated()
                     .map(|(variant_idx, variant_layout)| {
                         let Adt(adt, _) = type_layout.ty.kind() else {
-                            span_bug!(cx.tcx().def_span(ty_def_id), "not an adt")
+                            span_bug!(tcx.def_span(ty_def_id), "not an adt")
                         };
                         let name = adt.variant(variant_idx).name;
                         let is_unsized = variant_layout.abi.is_unsized();
diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html
index a014579..c219670 100644
--- a/src/librustdoc/html/templates/item_union.html
+++ b/src/librustdoc/html/templates/item_union.html
@@ -1,8 +1,8 @@
 <pre class="rust item-decl"><code>
-    {{ self.render_attributes_in_pre() | safe }}
+    {{ self::item_template_render_attributes_in_pre(self.borrow()) | safe }}
     {{ self.render_union() | safe }}
 </code></pre>
-{{ self.document() | safe }}
+{{ self::item_template_document(self.borrow()) | safe }}
 {% if self.fields_iter().peek().is_some() %}
     <h2 id="fields" class="fields small-section-header">
         Fields<a href="#fields" class="anchor">§</a>
@@ -19,5 +19,5 @@
         {{ self.document_field(field) | safe }}
     {% endfor %}
 {% endif %}
-{{ self.render_assoc_items() | safe }}
-{{ self.document_type_layout() | safe }}
+{{ self::item_template_render_assoc_items(self.borrow()) | safe }}
+{{ self::item_template_document_type_layout(self.borrow()) | safe }}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 0a56916..12c622e 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -712,13 +712,23 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
 }
 
 fn main_args(at_args: &[String]) -> MainResult {
+    // Throw away the first argument, the name of the binary.
+    // In case of at_args being empty, as might be the case by
+    // passing empty argument array to execve under some platforms,
+    // just use an empty slice.
+    //
+    // This situation was possible before due to arg_expand_all being
+    // called before removing the argument, enabling a crash by calling
+    // the compiler with @empty_file as argv[0] and no more arguments.
+    let at_args = at_args.get(1..).unwrap_or_default();
+
     let args = rustc_driver::args::arg_expand_all(at_args);
 
     let mut options = getopts::Options::new();
     for option in opts() {
         (option.apply)(&mut options);
     }
-    let matches = match options.parse(&args[1..]) {
+    let matches = match options.parse(&args) {
         Ok(m) => m,
         Err(err) => {
             early_error(ErrorOutputType::default(), err.to_string());
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 9e6894a..061a572 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -31,7 +31,7 @@
 use crate::clean::{self, utils::find_nearest_parent_module};
 use crate::clean::{Crate, Item, ItemLink, PrimitiveType};
 use crate::core::DocContext;
-use crate::html::markdown::{markdown_links, MarkdownLink};
+use crate::html::markdown::{markdown_links, MarkdownLink, MarkdownLinkRange};
 use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
 use crate::passes::Pass;
 use crate::visit::DocVisitor;
@@ -248,7 +248,7 @@ struct DiagnosticInfo<'a> {
     item: &'a Item,
     dox: &'a str,
     ori_link: &'a str,
-    link_range: Range<usize>,
+    link_range: MarkdownLinkRange,
 }
 
 struct LinkCollector<'a, 'tcx> {
@@ -723,7 +723,7 @@ fn resolve_associated_trait_item<'a>(
         .iter()
         .flat_map(|&(impl_, trait_)| {
             filter_assoc_items_by_name_and_namespace(
-                cx.tcx,
+                tcx,
                 trait_,
                 Ident::with_dummy_span(item_name),
                 ns,
@@ -833,7 +833,7 @@ fn visit_item(&mut self, item: &Item) {
 enum PreprocessingError {
     /// User error: `[std#x#y]` is not valid
     MultipleAnchors,
-    Disambiguator(Range<usize>, String),
+    Disambiguator(MarkdownLinkRange, String),
     MalformedGenerics(MalformedGenerics, String),
 }
 
@@ -873,6 +873,7 @@ pub(crate) struct PreprocessedMarkdownLink(
 /// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
 fn preprocess_link(
     ori_link: &MarkdownLink,
+    dox: &str,
 ) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
     // [] is mostly likely not supposed to be a link
     if ori_link.link.is_empty() {
@@ -906,9 +907,15 @@ fn preprocess_link(
         Err((err_msg, relative_range)) => {
             // Only report error if we would not have ignored this link. See issue #83859.
             if !should_ignore_link_with_disambiguators(link) {
-                let no_backticks_range = range_between_backticks(ori_link);
-                let disambiguator_range = (no_backticks_range.start + relative_range.start)
-                    ..(no_backticks_range.start + relative_range.end);
+                let disambiguator_range = match range_between_backticks(&ori_link.range, dox) {
+                    MarkdownLinkRange::Destination(no_backticks_range) => {
+                        MarkdownLinkRange::Destination(
+                            (no_backticks_range.start + relative_range.start)
+                                ..(no_backticks_range.start + relative_range.end),
+                        )
+                    }
+                    mdlr @ MarkdownLinkRange::WholeLink(_) => mdlr,
+                };
                 return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
             } else {
                 return None;
@@ -947,7 +954,7 @@ fn preprocess_link(
 
 fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
     markdown_links(s, |link| {
-        preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link))
+        preprocess_link(&link, s).map(|pp_link| PreprocessedMarkdownLink(pp_link, link))
     })
 }
 
@@ -1060,22 +1067,12 @@ fn resolve_link(
                     // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
                     // for discussion on the matter.
                     let kind = self.cx.tcx.def_kind(id);
-                    self.verify_disambiguator(
-                        path_str,
-                        ori_link,
-                        kind,
-                        id,
-                        disambiguator,
-                        item,
-                        &diag_info,
-                    )?;
+                    self.verify_disambiguator(path_str, kind, id, disambiguator, item, &diag_info)?;
                 } else {
                     match disambiguator {
                         Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {}
                         Some(other) => {
-                            self.report_disambiguator_mismatch(
-                                path_str, ori_link, other, res, &diag_info,
-                            );
+                            self.report_disambiguator_mismatch(path_str, other, res, &diag_info);
                             return None;
                         }
                     }
@@ -1096,7 +1093,6 @@ fn resolve_link(
                 };
                 self.verify_disambiguator(
                     path_str,
-                    ori_link,
                     kind_for_dis,
                     id_for_dis,
                     disambiguator,
@@ -1118,7 +1114,6 @@ fn resolve_link(
     fn verify_disambiguator(
         &self,
         path_str: &str,
-        ori_link: &MarkdownLink,
         kind: DefKind,
         id: DefId,
         disambiguator: Option<Disambiguator>,
@@ -1142,7 +1137,7 @@ fn verify_disambiguator(
                 => {}
                 (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
                 (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
-                    self.report_disambiguator_mismatch(path_str,ori_link,specified, Res::Def(kind, id),diag_info);
+                    self.report_disambiguator_mismatch(path_str, specified, Res::Def(kind, id), diag_info);
                     return None;
                 }
             }
@@ -1164,14 +1159,13 @@ fn verify_disambiguator(
     fn report_disambiguator_mismatch(
         &self,
         path_str: &str,
-        ori_link: &MarkdownLink,
         specified: Disambiguator,
         resolved: Res,
         diag_info: &DiagnosticInfo<'_>,
     ) {
         // The resolved item did not match the disambiguator; give a better error than 'not found'
         let msg = format!("incompatible link kind for `{}`", path_str);
-        let callback = |diag: &mut Diagnostic, sp: Option<rustc_span::Span>| {
+        let callback = |diag: &mut Diagnostic, sp: Option<rustc_span::Span>, link_range| {
             let note = format!(
                 "this link resolved to {} {}, which is not {} {}",
                 resolved.article(),
@@ -1184,14 +1178,24 @@ fn report_disambiguator_mismatch(
             } else {
                 diag.note(note);
             }
-            suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp);
+            suggest_disambiguator(resolved, diag, path_str, link_range, sp, diag_info);
         };
         report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, callback);
     }
 
-    fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &Range<usize>, item: &Item) {
-        let span = super::source_span_for_markdown_range(self.cx.tcx, dox, ori_link, &item.attrs)
-            .unwrap_or_else(|| item.attr_span(self.cx.tcx));
+    fn report_rawptr_assoc_feature_gate(
+        &self,
+        dox: &str,
+        ori_link: &MarkdownLinkRange,
+        item: &Item,
+    ) {
+        let span = super::source_span_for_markdown_range(
+            self.cx.tcx,
+            dox,
+            ori_link.inner_range(),
+            &item.attrs,
+        )
+        .unwrap_or_else(|| item.attr_span(self.cx.tcx));
         rustc_session::parse::feature_err(
             &self.cx.tcx.sess.parse_sess,
             sym::intra_doc_pointers,
@@ -1371,16 +1375,23 @@ fn resolve_with_disambiguator(
 /// [`Foo`]
 ///   ^^^
 /// ```
-fn range_between_backticks(ori_link: &MarkdownLink) -> Range<usize> {
-    let after_first_backtick_group = ori_link.link.bytes().position(|b| b != b'`').unwrap_or(0);
-    let before_second_backtick_group = ori_link
-        .link
+///
+/// This function does nothing if `ori_link.range` is a `MarkdownLinkRange::WholeLink`.
+fn range_between_backticks(ori_link_range: &MarkdownLinkRange, dox: &str) -> MarkdownLinkRange {
+    let range = match ori_link_range {
+        mdlr @ MarkdownLinkRange::WholeLink(_) => return mdlr.clone(),
+        MarkdownLinkRange::Destination(inner) => inner.clone(),
+    };
+    let ori_link_text = &dox[range.clone()];
+    let after_first_backtick_group = ori_link_text.bytes().position(|b| b != b'`').unwrap_or(0);
+    let before_second_backtick_group = ori_link_text
         .bytes()
         .skip(after_first_backtick_group)
         .position(|b| b == b'`')
-        .unwrap_or(ori_link.link.len());
-    (ori_link.range.start + after_first_backtick_group)
-        ..(ori_link.range.start + before_second_backtick_group)
+        .unwrap_or(ori_link_text.len());
+    MarkdownLinkRange::Destination(
+        (range.start + after_first_backtick_group)..(range.start + before_second_backtick_group),
+    )
 }
 
 /// Returns true if we should ignore `link` due to it being unlikely
@@ -1530,14 +1541,23 @@ fn as_help_span(
         sp: rustc_span::Span,
     ) -> Vec<(rustc_span::Span, String)> {
         let inner_sp = match ori_link.find('(') {
+            Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => {
+                sp.with_hi(sp.lo() + BytePos((index - 1) as _))
+            }
             Some(index) => sp.with_hi(sp.lo() + BytePos(index as _)),
             None => sp,
         };
         let inner_sp = match ori_link.find('!') {
+            Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => {
+                sp.with_hi(sp.lo() + BytePos((index - 1) as _))
+            }
             Some(index) => inner_sp.with_hi(inner_sp.lo() + BytePos(index as _)),
             None => inner_sp,
         };
         let inner_sp = match ori_link.find('@') {
+            Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => {
+                sp.with_hi(sp.lo() + BytePos((index - 1) as _))
+            }
             Some(index) => inner_sp.with_lo(inner_sp.lo() + BytePos(index as u32 + 1)),
             None => inner_sp,
         };
@@ -1584,7 +1604,7 @@ fn report_diagnostic(
     lint: &'static Lint,
     msg: impl Into<DiagnosticMessage> + Display,
     DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>,
-    decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>),
+    decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>, MarkdownLinkRange),
 ) {
     let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
     else {
@@ -1596,16 +1616,32 @@ fn report_diagnostic(
     let sp = item.attr_span(tcx);
 
     tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |lint| {
-        let span =
-            super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| {
-                if dox.as_bytes().get(link_range.start) == Some(&b'`')
-                    && dox.as_bytes().get(link_range.end - 1) == Some(&b'`')
-                {
-                    sp.with_lo(sp.lo() + BytePos(1)).with_hi(sp.hi() - BytePos(1))
-                } else {
-                    sp
-                }
-            });
+        let (span, link_range) = match link_range {
+            MarkdownLinkRange::Destination(md_range) => {
+                let mut md_range = md_range.clone();
+                let sp = super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs)
+                    .map(|mut sp| {
+                        while dox.as_bytes().get(md_range.start) == Some(&b' ')
+                            || dox.as_bytes().get(md_range.start) == Some(&b'`')
+                        {
+                            md_range.start += 1;
+                            sp = sp.with_lo(sp.lo() + BytePos(1));
+                        }
+                        while dox.as_bytes().get(md_range.end - 1) == Some(&b' ')
+                            || dox.as_bytes().get(md_range.end - 1) == Some(&b'`')
+                        {
+                            md_range.end -= 1;
+                            sp = sp.with_hi(sp.hi() - BytePos(1));
+                        }
+                        sp
+                    });
+                (sp, MarkdownLinkRange::Destination(md_range))
+            }
+            MarkdownLinkRange::WholeLink(md_range) => (
+                super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs),
+                link_range.clone(),
+            ),
+        };
 
         if let Some(sp) = span {
             lint.set_span(sp);
@@ -1614,21 +1650,22 @@ fn report_diagnostic(
             //                       ^     ~~~~
             //                       |     link_range
             //                       last_new_line_offset
-            let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
+            let md_range = link_range.inner_range().clone();
+            let last_new_line_offset = dox[..md_range.start].rfind('\n').map_or(0, |n| n + 1);
             let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
 
-            // Print the line containing the `link_range` and manually mark it with '^'s.
+            // Print the line containing the `md_range` and manually mark it with '^'s.
             lint.note(format!(
                 "the link appears in this line:\n\n{line}\n\
                      {indicator: <before$}{indicator:^<found$}",
                 line = line,
                 indicator = "",
-                before = link_range.start - last_new_line_offset,
-                found = link_range.len(),
+                before = md_range.start - last_new_line_offset,
+                found = md_range.len(),
             ));
         }
 
-        decorate(lint, span);
+        decorate(lint, span, link_range);
 
         lint
     });
@@ -1652,7 +1689,7 @@ fn resolution_failure(
         BROKEN_INTRA_DOC_LINKS,
         format!("unresolved link to `{}`", path_str),
         &diag_info,
-        |diag, sp| {
+        |diag, sp, link_range| {
             let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),);
             let assoc_item_not_allowed = |res: Res| {
                 let name = res.name(tcx);
@@ -1706,7 +1743,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                             if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) {
                                 debug!("found partial_res={:?}", v_res);
                                 if !v_res.is_empty() {
-                                    *partial_res = Some(full_res(collector.cx.tcx, v_res[0]));
+                                    *partial_res = Some(full_res(tcx, v_res[0]));
                                     *unresolved = end.into();
                                     break 'outer;
                                 }
@@ -1845,7 +1882,14 @@ fn split(path: &str) -> Option<(&str, &str)> {
                 let note = match failure {
                     ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
                     ResolutionFailure::WrongNamespace { res, expected_ns } => {
-                        suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
+                        suggest_disambiguator(
+                            res,
+                            diag,
+                            path_str,
+                            link_range.clone(),
+                            sp,
+                            &diag_info,
+                        );
 
                         format!(
                             "this link resolves to {}, which is not in the {} namespace",
@@ -1882,7 +1926,7 @@ fn anchor_failure(
     msg: String,
     anchor_idx: usize,
 ) {
-    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp| {
+    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp, _link_range| {
         if let Some(mut sp) = sp {
             if let Some((fragment_offset, _)) =
                 diag_info.ori_link.char_indices().filter(|(_, x)| *x == '#').nth(anchor_idx)
@@ -1898,11 +1942,11 @@ fn anchor_failure(
 fn disambiguator_error(
     cx: &DocContext<'_>,
     mut diag_info: DiagnosticInfo<'_>,
-    disambiguator_range: Range<usize>,
+    disambiguator_range: MarkdownLinkRange,
     msg: impl Into<DiagnosticMessage> + Display,
 ) {
     diag_info.link_range = disambiguator_range;
-    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
+    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp, _link_range| {
         let msg = format!(
             "see {}/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
             crate::DOC_RUST_LANG_ORG_CHANNEL
@@ -1922,7 +1966,7 @@ fn report_malformed_generics(
         BROKEN_INTRA_DOC_LINKS,
         format!("unresolved link to `{}`", path_str),
         &diag_info,
-        |diag, sp| {
+        |diag, sp, _link_range| {
             let note = match err {
                 MalformedGenerics::UnbalancedAngleBrackets => "unbalanced angle brackets",
                 MalformedGenerics::MissingType => "missing type for generic parameters",
@@ -1995,7 +2039,7 @@ fn ambiguity_error(
         }
     }
 
-    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| {
+    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, link_range| {
         if let Some(sp) = sp {
             diag.span_label(sp, "ambiguous link");
         } else {
@@ -2003,7 +2047,7 @@ fn ambiguity_error(
         }
 
         for res in kinds {
-            suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
+            suggest_disambiguator(res, diag, path_str, link_range.clone(), sp, diag_info);
         }
     });
     true
@@ -2015,13 +2059,19 @@ fn suggest_disambiguator(
     res: Res,
     diag: &mut Diagnostic,
     path_str: &str,
-    ori_link: &str,
+    link_range: MarkdownLinkRange,
     sp: Option<rustc_span::Span>,
+    diag_info: &DiagnosticInfo<'_>,
 ) {
     let suggestion = res.disambiguator_suggestion();
     let help = format!("to link to the {}, {}", res.descr(), suggestion.descr());
 
-    if let Some(sp) = sp {
+    let ori_link = match link_range {
+        MarkdownLinkRange::Destination(range) => Some(&diag_info.dox[range]),
+        MarkdownLinkRange::WholeLink(_) => None,
+    };
+
+    if let (Some(sp), Some(ori_link)) = (sp, ori_link) {
         let mut spans = suggestion.as_help_span(path_str, ori_link, sp);
         if spans.len() > 1 {
             diag.multipart_suggestion(help, spans, Applicability::MaybeIncorrect);
@@ -2047,7 +2097,7 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str:
     let msg =
         format!("public documentation for `{}` links to private item `{}`", item_name, path_str);
 
-    report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| {
+    report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, _link_range| {
         if let Some(sp) = sp {
             diag.span_label(sp, "this item is private");
         }
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 8d204dd..fbf827c 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -19,9 +19,10 @@
 };
 
 pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    let tcx = cx.tcx;
     // We need to check if there are errors before running this pass because it would crash when
     // we try to get auto and blanket implementations.
-    if cx.tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
+    if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
         return krate;
     }
 
@@ -32,8 +33,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
     });
 
     let local_crate = ExternalCrate { crate_num: LOCAL_CRATE };
-    let prims: FxHashSet<PrimitiveType> =
-        local_crate.primitives(cx.tcx).iter().map(|p| p.1).collect();
+    let prims: FxHashSet<PrimitiveType> = local_crate.primitives(tcx).iter().map(|p| p.1).collect();
 
     let crate_items = {
         let mut coll = ItemCollector::new();
@@ -46,9 +46,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
 
     // External trait impls.
     {
-        let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls");
-        for &cnum in cx.tcx.crates(()) {
-            for &impl_def_id in cx.tcx.trait_impls_in_crate(cnum) {
+        let _prof_timer = tcx.sess.prof.generic_activity("build_extern_trait_impls");
+        for &cnum in tcx.crates(()) {
+            for &impl_def_id in tcx.trait_impls_in_crate(cnum) {
                 inline::build_impl(cx, impl_def_id, None, &mut new_items_external);
             }
         }
@@ -56,14 +56,13 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
 
     // Local trait impls.
     {
-        let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
+        let _prof_timer = tcx.sess.prof.generic_activity("build_local_trait_impls");
         let mut attr_buf = Vec::new();
-        for &impl_def_id in cx.tcx.trait_impls_in_crate(LOCAL_CRATE) {
-            let mut parent = Some(cx.tcx.parent(impl_def_id));
+        for &impl_def_id in tcx.trait_impls_in_crate(LOCAL_CRATE) {
+            let mut parent = Some(tcx.parent(impl_def_id));
             while let Some(did) = parent {
                 attr_buf.extend(
-                    cx.tcx
-                        .get_attrs(did, sym::doc)
+                    tcx.get_attrs(did, sym::doc)
                         .filter(|attr| {
                             if let Some([attr]) = attr.meta_item_list().as_deref() {
                                 attr.has_name(sym::cfg)
@@ -73,25 +72,24 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
                         })
                         .cloned(),
                 );
-                parent = cx.tcx.opt_parent(did);
+                parent = tcx.opt_parent(did);
             }
             inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local);
             attr_buf.clear();
         }
     }
 
-    cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
-        for def_id in PrimitiveType::all_impls(cx.tcx) {
+    tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
+        for def_id in PrimitiveType::all_impls(tcx) {
             // Try to inline primitive impls from other crates.
             if !def_id.is_local() {
                 inline::build_impl(cx, def_id, None, &mut new_items_external);
             }
         }
-        for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) {
+        for (prim, did) in PrimitiveType::primitive_locations(tcx) {
             // Do not calculate blanket impl list for docs that are not going to be rendered.
             // While the `impl` blocks themselves are only in `libcore`, the module with `doc`
             // attached is directly included in `libstd` as well.
-            let tcx = cx.tcx;
             if did.is_local() {
                 for def_id in prim.impls(tcx).filter(|def_id| {
                     // Avoid including impl blocks with filled-in generics.
@@ -157,7 +155,7 @@ fn add_deref_target(
     // scan through included items ahead of time to splice in Deref targets to the "valid" sets
     for it in new_items_external.iter().chain(new_items_local.iter()) {
         if let ImplItem(box Impl { ref for_, ref trait_, ref items, .. }) = *it.kind &&
-            trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait() &&
+            trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() &&
             cleaner.keep_impl(for_, true)
         {
             let target = items
@@ -199,7 +197,7 @@ fn add_deref_target(
         if let ImplItem(box Impl { ref for_, ref trait_, ref kind, .. }) = *it.kind {
             cleaner.keep_impl(
                 for_,
-                trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait(),
+                trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait(),
             ) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
                 || kind.is_blanket()
         } else {
diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs
index 683c224..8652122 100644
--- a/src/librustdoc/passes/lint/unescaped_backticks.rs
+++ b/src/librustdoc/passes/lint/unescaped_backticks.rs
@@ -56,7 +56,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
                 )
                 .unwrap_or_else(|| item.attr_span(tcx));
 
-                cx.tcx.struct_span_lint_hir(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| {
+                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 {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 8f8dc6b..6b7ad4c 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -280,9 +280,8 @@ fn maybe_inline_local(
             return false;
         };
 
-        let is_private =
-            !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, ori_res_did);
-        let is_hidden = inherits_doc_hidden(self.cx.tcx, res_did, None);
+        let is_private = !self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did);
+        let is_hidden = inherits_doc_hidden(tcx, res_did, None);
 
         // Only inline if requested or if the item would otherwise be stripped.
         if (!please_inline && !is_private && !is_hidden) || is_no_inline {
@@ -290,7 +289,7 @@ fn maybe_inline_local(
         }
 
         if !please_inline &&
-            let Some(item_def_id) = reexport_chain(self.cx.tcx, def_id, res_did).iter()
+            let Some(item_def_id) = reexport_chain(tcx, def_id, res_did).iter()
                 .flat_map(|reexport| reexport.id()).map(|id| id.expect_local())
                 .chain(iter::once(res_did)).nth(1) &&
             item_def_id != def_id &&
@@ -298,22 +297,38 @@ fn maybe_inline_local(
                 .cx
                 .cache
                 .effective_visibilities
-                .is_directly_public(self.cx.tcx, item_def_id.to_def_id()) &&
-            !inherits_doc_hidden(self.cx.tcx, item_def_id, None)
+                .is_directly_public(tcx, item_def_id.to_def_id()) &&
+            !inherits_doc_hidden(tcx, item_def_id, None)
         {
             // The imported item is public and not `doc(hidden)` so no need to inline it.
             return false;
         }
 
-        if !self.view_item_stack.insert(res_did) {
+        let is_bang_macro = matches!(
+            tcx.hir().get_by_def_id(res_did),
+            Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, MacroKind::Bang), .. })
+        );
+
+        if !self.view_item_stack.insert(res_did) && !is_bang_macro {
             return false;
         }
 
         let ret = match tcx.hir().get_by_def_id(res_did) {
+            // Bang macros are handled a bit on their because of how they are handled by the
+            // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have
+            // `#[doc(inline)]`, then we don't inline it.
+            Node::Item(_)
+                if is_bang_macro
+                    && !please_inline
+                    && renamed.is_some()
+                    && self.cx.tcx.is_doc_hidden(ori_res_did) =>
+            {
+                return false;
+            }
             Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => {
                 let prev = mem::replace(&mut self.inlining, true);
                 for &i in m.item_ids {
-                    let i = self.cx.tcx.hir().item(i);
+                    let i = tcx.hir().item(i);
                     self.visit_item_inner(i, None, Some(def_id));
                 }
                 self.inlining = prev;
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index b27ffe7..a418a91 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1219,7 +1219,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
                 return false;
             }
 
-            let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty);
+            let predicate = EarlyBinder::new(predicate).subst(cx.tcx, &substs_with_referent_ty);
             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
             let infcx = cx.tcx.infer_ctxt().build();
             infcx.predicate_must_hold_modulo_regions(&obligation)
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index b2071f4..af2aac6 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -243,7 +243,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs
                 | ty::Ref(..)
                 | ty::Slice(_)
                 | ty::Tuple(_) => {
-                    format!("<{}>", EarlyBinder(ty).subst(cx.tcx, substs))
+                    format!("<{}>", EarlyBinder::new(ty).subst(cx.tcx, substs))
                 },
                 _ => ty.to_string(),
             }
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 6841aaf..d4cc14b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -241,7 +241,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
         && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs)
         && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
     {
-        item_ty == EarlyBinder(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id))
+        item_ty == EarlyBinder::new(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id))
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 67b7d36..fdacfa4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -428,7 +428,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                                      }));
 
                         if trait_predicates.any(|predicate| {
-                            let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst);
+                            let predicate = EarlyBinder::new(predicate).subst(cx.tcx, new_subst);
                             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
                             !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
                         }) {
@@ -438,7 +438,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                         let output_ty = fn_sig.output();
                         if output_ty.contains(*param_ty) {
                             if let Ok(new_ty)  = cx.tcx.try_subst_and_normalize_erasing_regions(
-                                new_subst, cx.param_env, EarlyBinder(output_ty)) {
+                                new_subst, cx.param_env, EarlyBinder::new(output_ty)) {
                                 expr = parent_expr;
                                 ty = new_ty;
                                 continue;
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 2abdfac..e6fd65f 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -138,7 +138,7 @@ fn collect_unsafe_exprs<'tcx>(
                     .type_dependent_def_id(expr.hir_id)
                     .map(|def_id| cx.tcx.fn_sig(def_id))
                 {
-                    if sig.0.unsafety() == Unsafety::Unsafe {
+                    if sig.skip_binder().unsafety() == Unsafety::Unsafe {
                         unsafe_ops.push(("unsafe method call occurs here", expr.span));
                     }
                 }
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index fb77264..843538e 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -462,7 +462,7 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<C
                 let substs = if self.substs.is_empty() {
                     substs
                 } else {
-                    EarlyBinder(substs).subst(self.lcx.tcx, self.substs)
+                    EarlyBinder::new(substs).subst(self.lcx.tcx, self.substs)
                 };
 
                 let result = self
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index e5297d4..d2f2583 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -3,6 +3,9 @@
 version = "0.0.0"
 edition = "2021"
 
+[lib]
+doctest = false
+
 [dependencies]
 colored = "2"
 diff = "0.1.10"
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index ba68b5e..f796c89 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -69,6 +69,12 @@ pub enum Mode {
     }
 }
 
+impl Default for Mode {
+    fn default() -> Self {
+        Mode::Ui
+    }
+}
+
 impl Mode {
     pub fn disambiguator(self) -> &'static str {
         // Pretty-printing tests could run concurrently, and if they do,
@@ -125,7 +131,7 @@ pub enum PanicStrategy {
 }
 
 /// Configuration for compiletest
-#[derive(Debug, Clone)]
+#[derive(Debug, Default, Clone)]
 pub struct Config {
     /// `true` to overwrite stderr/stdout files instead of complaining about changes in output.
     pub bless: bool,
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 4a57c61..18b3b91 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -71,6 +71,11 @@ pub(super) fn handle_needs(
             ignore_reason: "ignored on targets without shadow call stacks",
         },
         Need {
+            name: "needs-sanitizer-safestack",
+            condition: cache.sanitizer_safestack,
+            ignore_reason: "ignored on targets without SafeStack support",
+        },
+        Need {
             name: "needs-run-enabled",
             condition: config.run_enabled(),
             ignore_reason: "ignored when running the resulting test binaries is disabled",
@@ -184,6 +189,7 @@ pub(super) struct CachedNeedsConditions {
     sanitizer_hwaddress: bool,
     sanitizer_memtag: bool,
     sanitizer_shadow_call_stack: bool,
+    sanitizer_safestack: bool,
     xray: bool,
     rust_lld: bool,
     i686_dlltool: bool,
@@ -220,6 +226,7 @@ pub(super) fn load(config: &Config) -> Self {
             sanitizer_hwaddress: util::HWASAN_SUPPORTED_TARGETS.contains(target),
             sanitizer_memtag: util::MEMTAG_SUPPORTED_TARGETS.contains(target),
             sanitizer_shadow_call_stack: util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(target),
+            sanitizer_safestack: util::SAFESTACK_SUPPORTED_TARGETS.contains(target),
             xray: util::XRAY_SUPPORTED_TARGETS.contains(target),
 
             // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
new file mode 100644
index 0000000..fc48d01
--- /dev/null
+++ b/src/tools/compiletest/src/lib.rs
@@ -0,0 +1,1136 @@
+#![crate_name = "compiletest"]
+// The `test` crate is the only unstable feature
+// allowed here, just to share similar code.
+#![feature(test)]
+
+extern crate test;
+
+#[cfg(test)]
+mod tests;
+
+pub mod common;
+pub mod compute_diff;
+pub mod errors;
+pub mod header;
+mod json;
+mod raise_fd_limit;
+mod read2;
+pub mod runtest;
+pub mod util;
+
+use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
+use crate::common::{Config, Debugger, Mode, PassMode, TestPaths};
+use crate::util::logv;
+use build_helper::git::{get_git_modified_files, get_git_untracked_files};
+use core::panic;
+use getopts::Options;
+use lazycell::AtomicLazyCell;
+use std::collections::BTreeSet;
+use std::ffi::OsString;
+use std::fs;
+use std::io::{self, ErrorKind};
+use std::path::{Path, PathBuf};
+use std::process::{Command, Stdio};
+use std::time::SystemTime;
+use std::{env, vec};
+use test::ColorConfig;
+use tracing::*;
+use walkdir::WalkDir;
+
+use self::header::{make_test_description, EarlyProps};
+use crate::header::HeadersCache;
+use std::sync::Arc;
+
+pub fn parse_config(args: Vec<String>) -> Config {
+    let mut opts = Options::new();
+    opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH")
+        .reqopt("", "run-lib-path", "path to target shared libraries", "PATH")
+        .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH")
+        .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
+        .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH")
+        .reqopt("", "python", "path to python to use for doc tests", "PATH")
+        .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH")
+        .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH")
+        .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
+        .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind")
+        .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH")
+        .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR")
+        .reqopt("", "src-base", "directory to scan for test files", "PATH")
+        .reqopt("", "build-base", "directory to deposit test outputs", "PATH")
+        .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH")
+        .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET")
+        .reqopt(
+            "",
+            "mode",
+            "which sort of compile tests to run",
+            "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
+            | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly",
+        )
+        .reqopt(
+            "",
+            "suite",
+            "which suite of compile tests to run. used for nicer error reporting.",
+            "SUITE",
+        )
+        .optopt(
+            "",
+            "pass",
+            "force {check,build,run}-pass tests to this mode.",
+            "check | build | run",
+        )
+        .optopt("", "run", "whether to execute run-* tests", "auto | always | never")
+        .optflag("", "ignored", "run tests marked as ignored")
+        .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING")
+        .optflag("", "exact", "filters match exactly")
+        .optopt(
+            "",
+            "runtool",
+            "supervisor program to run tests under \
+             (eg. emulator, valgrind)",
+            "PROGRAM",
+        )
+        .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
+        .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
+        .optflag("", "optimize-tests", "run tests with optimizations enabled")
+        .optflag("", "verbose", "run tests verbosely, showing all output")
+        .optflag(
+            "",
+            "bless",
+            "overwrite stderr/stdout files instead of complaining about a mismatch",
+        )
+        .optflag("", "quiet", "print one character per test instead of one line")
+        .optopt("", "color", "coloring: auto, always, never", "WHEN")
+        .optflag("", "json", "emit json output instead of plaintext output")
+        .optopt("", "logfile", "file to log test execution to", "FILE")
+        .optopt("", "target", "the target to build for", "TARGET")
+        .optopt("", "host", "the host to build for", "HOST")
+        .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH")
+        .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH")
+        .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING")
+        .optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING")
+        .optflag("", "system-llvm", "is LLVM the system LLVM")
+        .optopt("", "android-cross-path", "Android NDK standalone path", "PATH")
+        .optopt("", "adb-path", "path to the android debugger", "PATH")
+        .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH")
+        .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH")
+        .reqopt("", "cc", "path to a C compiler", "PATH")
+        .reqopt("", "cxx", "path to a C++ compiler", "PATH")
+        .reqopt("", "cflags", "flags for the C compiler", "FLAGS")
+        .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS")
+        .optopt("", "ar", "path to an archiver", "PATH")
+        .optopt("", "target-linker", "path to a linker for the target", "PATH")
+        .optopt("", "host-linker", "path to a linker for the host", "PATH")
+        .reqopt("", "llvm-components", "list of LLVM components built in", "LIST")
+        .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH")
+        .optopt("", "nodejs", "the name of nodejs", "PATH")
+        .optopt("", "npm", "the name of npm", "PATH")
+        .optopt("", "remote-test-client", "path to the remote test client", "PATH")
+        .optopt(
+            "",
+            "compare-mode",
+            "mode describing what file the actual ui output will be compared to",
+            "COMPARE MODE",
+        )
+        .optflag(
+            "",
+            "rustfix-coverage",
+            "enable this to generate a Rustfix coverage file, which is saved in \
+            `./<build_base>/rustfix_missing_coverage.txt`",
+        )
+        .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
+        .optflag("", "only-modified", "only run tests that result been modified")
+        .optflag("", "nocapture", "")
+        .optflag("h", "help", "show this message")
+        .reqopt("", "channel", "current Rust channel", "CHANNEL")
+        .optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries")
+        .optopt("", "edition", "default Rust edition", "EDITION");
+
+    let (argv0, args_) = args.split_first().unwrap();
+    if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
+        let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
+        println!("{}", opts.usage(&message));
+        println!();
+        panic!()
+    }
+
+    let matches = &match opts.parse(args_) {
+        Ok(m) => m,
+        Err(f) => panic!("{:?}", f),
+    };
+
+    if matches.opt_present("h") || matches.opt_present("help") {
+        let message = format!("Usage: {} [OPTIONS]  [TESTNAME...]", argv0);
+        println!("{}", opts.usage(&message));
+        println!();
+        panic!()
+    }
+
+    fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
+        match m.opt_str(nm) {
+            Some(s) => PathBuf::from(&s),
+            None => panic!("no option (=path) found for {}", nm),
+        }
+    }
+
+    fn make_absolute(path: PathBuf) -> PathBuf {
+        if path.is_relative() { env::current_dir().unwrap().join(path) } else { path }
+    }
+
+    let target = opt_str2(matches.opt_str("target"));
+    let android_cross_path = opt_path(matches, "android-cross-path");
+    let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target);
+    let (gdb, gdb_version, gdb_native_rust) =
+        analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path);
+    let (lldb_version, lldb_native_rust) = matches
+        .opt_str("lldb-version")
+        .as_deref()
+        .and_then(extract_lldb_version)
+        .map(|(v, b)| (Some(v), b))
+        .unwrap_or((None, false));
+    let color = match matches.opt_str("color").as_deref() {
+        Some("auto") | None => ColorConfig::AutoColor,
+        Some("always") => ColorConfig::AlwaysColor,
+        Some("never") => ColorConfig::NeverColor,
+        Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
+    };
+    let llvm_version =
+        matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else(
+            || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
+        );
+
+    let src_base = opt_path(matches, "src-base");
+    let run_ignored = matches.opt_present("ignored");
+    let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode");
+    let has_tidy = if mode == Mode::Rustdoc {
+        Command::new("tidy")
+            .arg("--version")
+            .stdout(Stdio::null())
+            .status()
+            .map_or(false, |status| status.success())
+    } else {
+        // Avoid spawning an external command when we know tidy won't be used.
+        false
+    };
+    Config {
+        bless: matches.opt_present("bless"),
+        compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
+        run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
+        rustc_path: opt_path(matches, "rustc-path"),
+        rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
+        rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from),
+        python: matches.opt_str("python").unwrap(),
+        jsondocck_path: matches.opt_str("jsondocck-path"),
+        jsondoclint_path: matches.opt_str("jsondoclint-path"),
+        valgrind_path: matches.opt_str("valgrind-path"),
+        force_valgrind: matches.opt_present("force-valgrind"),
+        run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
+        llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from),
+        llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from),
+        src_base,
+        build_base: opt_path(matches, "build-base"),
+        sysroot_base: opt_path(matches, "sysroot-base"),
+        stage_id: matches.opt_str("stage-id").unwrap(),
+        mode,
+        suite: matches.opt_str("suite").unwrap(),
+        debugger: None,
+        run_ignored,
+        filters: matches.free.clone(),
+        skip: matches.opt_strs("skip"),
+        filter_exact: matches.opt_present("exact"),
+        force_pass_mode: matches.opt_str("pass").map(|mode| {
+            mode.parse::<PassMode>()
+                .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode))
+        }),
+        run: matches.opt_str("run").and_then(|mode| match mode.as_str() {
+            "auto" => None,
+            "always" => Some(true),
+            "never" => Some(false),
+            _ => panic!("unknown `--run` option `{}` given", mode),
+        }),
+        logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
+        runtool: matches.opt_str("runtool"),
+        host_rustcflags: matches.opt_strs("host-rustcflags"),
+        target_rustcflags: matches.opt_strs("target-rustcflags"),
+        optimize_tests: matches.opt_present("optimize-tests"),
+        target,
+        host: opt_str2(matches.opt_str("host")),
+        cdb,
+        cdb_version,
+        gdb,
+        gdb_version,
+        gdb_native_rust,
+        lldb_version,
+        lldb_native_rust,
+        llvm_version,
+        system_llvm: matches.opt_present("system-llvm"),
+        android_cross_path,
+        adb_path: opt_str2(matches.opt_str("adb-path")),
+        adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")),
+        adb_device_status: opt_str2(matches.opt_str("target")).contains("android")
+            && "(none)" != opt_str2(matches.opt_str("adb-test-dir"))
+            && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
+        lldb_python_dir: matches.opt_str("lldb-python-dir"),
+        verbose: matches.opt_present("verbose"),
+        format: match (matches.opt_present("quiet"), matches.opt_present("json")) {
+            (true, true) => panic!("--quiet and --json are incompatible"),
+            (true, false) => test::OutputFormat::Terse,
+            (false, true) => test::OutputFormat::Json,
+            (false, false) => test::OutputFormat::Pretty,
+        },
+        only_modified: matches.opt_present("only-modified"),
+        color,
+        remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
+        compare_mode: matches
+            .opt_str("compare-mode")
+            .map(|s| s.parse().expect("invalid --compare-mode provided")),
+        rustfix_coverage: matches.opt_present("rustfix-coverage"),
+        has_tidy,
+        channel: matches.opt_str("channel").unwrap(),
+        git_hash: matches.opt_present("git-hash"),
+        edition: matches.opt_str("edition"),
+
+        cc: matches.opt_str("cc").unwrap(),
+        cxx: matches.opt_str("cxx").unwrap(),
+        cflags: matches.opt_str("cflags").unwrap(),
+        cxxflags: matches.opt_str("cxxflags").unwrap(),
+        ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")),
+        target_linker: matches.opt_str("target-linker"),
+        host_linker: matches.opt_str("host-linker"),
+        llvm_components: matches.opt_str("llvm-components").unwrap(),
+        nodejs: matches.opt_str("nodejs"),
+        npm: matches.opt_str("npm"),
+
+        force_rerun: matches.opt_present("force-rerun"),
+
+        target_cfgs: AtomicLazyCell::new(),
+
+        nocapture: matches.opt_present("nocapture"),
+    }
+}
+
+pub fn log_config(config: &Config) {
+    let c = config;
+    logv(c, "configuration:".to_string());
+    logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path));
+    logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
+    logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
+    logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
+    logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path));
+    logv(c, format!("src_base: {:?}", config.src_base.display()));
+    logv(c, format!("build_base: {:?}", config.build_base.display()));
+    logv(c, format!("stage_id: {}", config.stage_id));
+    logv(c, format!("mode: {}", config.mode));
+    logv(c, format!("run_ignored: {}", config.run_ignored));
+    logv(c, format!("filters: {:?}", config.filters));
+    logv(c, format!("skip: {:?}", config.skip));
+    logv(c, format!("filter_exact: {}", config.filter_exact));
+    logv(
+        c,
+        format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),),
+    );
+    logv(c, format!("runtool: {}", opt_str(&config.runtool)));
+    logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags));
+    logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags));
+    logv(c, format!("target: {}", config.target));
+    logv(c, format!("host: {}", config.host));
+    logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display()));
+    logv(c, format!("adb_path: {:?}", config.adb_path));
+    logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir));
+    logv(c, format!("adb_device_status: {}", config.adb_device_status));
+    logv(c, format!("ar: {}", config.ar));
+    logv(c, format!("target-linker: {:?}", config.target_linker));
+    logv(c, format!("host-linker: {:?}", config.host_linker));
+    logv(c, format!("verbose: {}", config.verbose));
+    logv(c, format!("format: {:?}", config.format));
+    logv(c, "\n".to_string());
+}
+
+pub fn opt_str(maybestr: &Option<String>) -> &str {
+    match *maybestr {
+        None => "(none)",
+        Some(ref s) => s,
+    }
+}
+
+pub fn opt_str2(maybestr: Option<String>) -> String {
+    match maybestr {
+        None => "(none)".to_owned(),
+        Some(s) => s,
+    }
+}
+
+pub fn run_tests(config: Arc<Config>) {
+    // If we want to collect rustfix coverage information,
+    // we first make sure that the coverage file does not exist.
+    // It will be created later on.
+    if config.rustfix_coverage {
+        let mut coverage_file_path = config.build_base.clone();
+        coverage_file_path.push("rustfix_missing_coverage.txt");
+        if coverage_file_path.exists() {
+            if let Err(e) = fs::remove_file(&coverage_file_path) {
+                panic!("Could not delete {} due to {}", coverage_file_path.display(), e)
+            }
+        }
+    }
+
+    // sadly osx needs some file descriptor limits raised for running tests in
+    // parallel (especially when we have lots and lots of child processes).
+    // For context, see #8904
+    unsafe {
+        raise_fd_limit::raise_fd_limit();
+    }
+    // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
+    // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
+    env::set_var("__COMPAT_LAYER", "RunAsInvoker");
+
+    // Let tests know which target they're running as
+    env::set_var("TARGET", &config.target);
+
+    let opts = test_opts(&config);
+
+    let mut configs = Vec::new();
+    if let Mode::DebugInfo = config.mode {
+        // Debugging emscripten code doesn't make sense today
+        if !config.target.contains("emscripten") {
+            configs.extend(configure_cdb(&config));
+            configs.extend(configure_gdb(&config));
+            configs.extend(configure_lldb(&config));
+        }
+    } else {
+        configs.push(config.clone());
+    };
+
+    let mut tests = Vec::new();
+    for c in configs {
+        let mut found_paths = BTreeSet::new();
+        make_tests(c, &mut tests, &mut found_paths);
+        check_overlapping_tests(&found_paths);
+    }
+
+    tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice()));
+
+    let res = test::run_tests_console(&opts, tests);
+    match res {
+        Ok(true) => {}
+        Ok(false) => {
+            // We want to report that the tests failed, but we also want to give
+            // some indication of just what tests we were running. Especially on
+            // CI, where there can be cross-compiled tests for a lot of
+            // architectures, without this critical information it can be quite
+            // easy to miss which tests failed, and as such fail to reproduce
+            // the failure locally.
+
+            println!(
+                "Some tests failed in compiletest suite={}{} mode={} host={} target={}",
+                config.suite,
+                config
+                    .compare_mode
+                    .as_ref()
+                    .map(|c| format!(" compare_mode={:?}", c))
+                    .unwrap_or_default(),
+                config.mode,
+                config.host,
+                config.target
+            );
+
+            std::process::exit(1);
+        }
+        Err(e) => {
+            // We don't know if tests passed or not, but if there was an error
+            // during testing we don't want to just succeed (we may not have
+            // tested something), so fail.
+            //
+            // This should realistically "never" happen, so don't try to make
+            // this a pretty error message.
+            panic!("I/O failure during tests: {:?}", e);
+        }
+    }
+}
+
+fn configure_cdb(config: &Config) -> Option<Arc<Config>> {
+    config.cdb.as_ref()?;
+
+    Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() }))
+}
+
+fn configure_gdb(config: &Config) -> Option<Arc<Config>> {
+    config.gdb_version?;
+
+    if config.matches_env("msvc") {
+        return None;
+    }
+
+    if config.remote_test_client.is_some() && !config.target.contains("android") {
+        println!(
+            "WARNING: debuginfo tests are not available when \
+             testing with remote"
+        );
+        return None;
+    }
+
+    if config.target.contains("android") {
+        println!(
+            "{} debug-info test uses tcp 5039 port.\
+             please reserve it",
+            config.target
+        );
+
+        // android debug-info test uses remote debugger so, we test 1 thread
+        // at once as they're all sharing the same TCP port to communicate
+        // over.
+        //
+        // we should figure out how to lift this restriction! (run them all
+        // on different ports allocated dynamically).
+        env::set_var("RUST_TEST_THREADS", "1");
+    }
+
+    Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() }))
+}
+
+fn configure_lldb(config: &Config) -> Option<Arc<Config>> {
+    config.lldb_python_dir.as_ref()?;
+
+    if let Some(350) = config.lldb_version {
+        println!(
+            "WARNING: The used version of LLDB (350) has a \
+             known issue that breaks debuginfo tests. See \
+             issue #32520 for more information. Skipping all \
+             LLDB-based tests!",
+        );
+        return None;
+    }
+
+    Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() }))
+}
+
+pub fn test_opts(config: &Config) -> test::TestOpts {
+    if env::var("RUST_TEST_NOCAPTURE").is_ok() {
+        eprintln!(
+            "WARNING: RUST_TEST_NOCAPTURE is no longer used. \
+                   Use the `--nocapture` flag instead."
+        );
+    }
+
+    test::TestOpts {
+        exclude_should_panic: false,
+        filters: config.filters.clone(),
+        filter_exact: config.filter_exact,
+        run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
+        format: config.format,
+        logfile: config.logfile.clone(),
+        run_tests: true,
+        bench_benchmarks: true,
+        nocapture: config.nocapture,
+        color: config.color,
+        shuffle: false,
+        shuffle_seed: None,
+        test_threads: None,
+        skip: config.skip.clone(),
+        list: false,
+        options: test::Options::new(),
+        time_options: None,
+        force_run_in_process: false,
+        fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
+    }
+}
+
+pub fn make_tests(
+    config: Arc<Config>,
+    tests: &mut Vec<test::TestDescAndFn>,
+    found_paths: &mut BTreeSet<PathBuf>,
+) {
+    debug!("making tests from {:?}", config.src_base.display());
+    let inputs = common_inputs_stamp(&config);
+    let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| {
+        panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err)
+    });
+
+    let cache = HeadersCache::load(&config);
+    let mut poisoned = false;
+    collect_tests_from_dir(
+        config.clone(),
+        &cache,
+        &config.src_base,
+        &PathBuf::new(),
+        &inputs,
+        tests,
+        found_paths,
+        &modified_tests,
+        &mut poisoned,
+    )
+    .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display()));
+
+    if poisoned {
+        eprintln!();
+        panic!("there are errors in tests");
+    }
+}
+
+/// Returns a stamp constructed from input files common to all test cases.
+fn common_inputs_stamp(config: &Config) -> Stamp {
+    let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root");
+
+    let mut stamp = Stamp::from_path(&config.rustc_path);
+
+    // Relevant pretty printer files
+    let pretty_printer_files = [
+        "src/etc/rust_types.py",
+        "src/etc/gdb_load_rust_pretty_printers.py",
+        "src/etc/gdb_lookup.py",
+        "src/etc/gdb_providers.py",
+        "src/etc/lldb_batchmode.py",
+        "src/etc/lldb_lookup.py",
+        "src/etc/lldb_providers.py",
+    ];
+    for file in &pretty_printer_files {
+        let path = rust_src_dir.join(file);
+        stamp.add_path(&path);
+    }
+
+    stamp.add_dir(&rust_src_dir.join("src/etc/natvis"));
+
+    stamp.add_dir(&config.run_lib_path);
+
+    if let Some(ref rustdoc_path) = config.rustdoc_path {
+        stamp.add_path(&rustdoc_path);
+        stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py"));
+    }
+
+    // Compiletest itself.
+    stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/"));
+
+    stamp
+}
+
+fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
+    if !config.only_modified {
+        return Ok(vec![]);
+    }
+    let files =
+        get_git_modified_files(Some(dir), &vec!["rs", "stderr", "fixed"])?.unwrap_or(vec![]);
+    // Add new test cases to the list, it will be convenient in daily development.
+    let untracked_files = get_git_untracked_files(None)?.unwrap_or(vec![]);
+
+    let all_paths = [&files[..], &untracked_files[..]].concat();
+    let full_paths = {
+        let mut full_paths: Vec<PathBuf> = all_paths
+            .into_iter()
+            .map(|f| PathBuf::from(f).with_extension("").with_extension("rs"))
+            .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None })
+            .collect();
+        full_paths.dedup();
+        full_paths.sort_unstable();
+        full_paths
+    };
+    Ok(full_paths)
+}
+
+fn collect_tests_from_dir(
+    config: Arc<Config>,
+    cache: &HeadersCache,
+    dir: &Path,
+    relative_dir_path: &Path,
+    inputs: &Stamp,
+    tests: &mut Vec<test::TestDescAndFn>,
+    found_paths: &mut BTreeSet<PathBuf>,
+    modified_tests: &Vec<PathBuf>,
+    poisoned: &mut bool,
+) -> io::Result<()> {
+    // Ignore directories that contain a file named `compiletest-ignore-dir`.
+    if dir.join("compiletest-ignore-dir").exists() {
+        return Ok(());
+    }
+
+    if config.mode == Mode::RunMake && dir.join("Makefile").exists() {
+        let paths = TestPaths {
+            file: dir.to_path_buf(),
+            relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
+        };
+        tests.extend(make_test(config, cache, &paths, inputs, poisoned));
+        return Ok(());
+    }
+
+    // If we find a test foo/bar.rs, we have to build the
+    // output directory `$build/foo` so we can write
+    // `$build/foo/bar` into it. We do this *now* in this
+    // sequential loop because otherwise, if we do it in the
+    // tests themselves, they race for the privilege of
+    // creating the directories and sometimes fail randomly.
+    let build_dir = output_relative_path(&config, relative_dir_path);
+    fs::create_dir_all(&build_dir).unwrap();
+
+    // Add each `.rs` file as a test, and recurse further on any
+    // subdirectories we find, except for `aux` directories.
+    for file in fs::read_dir(dir)? {
+        let file = file?;
+        let file_path = file.path();
+        let file_name = file.file_name();
+        if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) {
+            debug!("found test file: {:?}", file_path.display());
+            let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap());
+            found_paths.insert(rel_test_path);
+            let paths =
+                TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() };
+
+            tests.extend(make_test(config.clone(), cache, &paths, inputs, poisoned))
+        } else if file_path.is_dir() {
+            let relative_file_path = relative_dir_path.join(file.file_name());
+            if &file_name != "auxiliary" {
+                debug!("found directory: {:?}", file_path.display());
+                collect_tests_from_dir(
+                    config.clone(),
+                    cache,
+                    &file_path,
+                    &relative_file_path,
+                    inputs,
+                    tests,
+                    found_paths,
+                    modified_tests,
+                    poisoned,
+                )?;
+            }
+        } else {
+            debug!("found other file/directory: {:?}", file_path.display());
+        }
+    }
+    Ok(())
+}
+
+/// Returns true if `file_name` looks like a proper test file name.
+pub fn is_test(file_name: &OsString) -> bool {
+    let file_name = file_name.to_str().unwrap();
+
+    if !file_name.ends_with(".rs") {
+        return false;
+    }
+
+    // `.`, `#`, and `~` are common temp-file prefixes.
+    let invalid_prefixes = &[".", "#", "~"];
+    !invalid_prefixes.iter().any(|p| file_name.starts_with(p))
+}
+
+fn make_test(
+    config: Arc<Config>,
+    cache: &HeadersCache,
+    testpaths: &TestPaths,
+    inputs: &Stamp,
+    poisoned: &mut bool,
+) -> Vec<test::TestDescAndFn> {
+    let test_path = if config.mode == Mode::RunMake {
+        // Parse directives in the Makefile
+        testpaths.file.join("Makefile")
+    } else {
+        PathBuf::from(&testpaths.file)
+    };
+    let early_props = EarlyProps::from_file(&config, &test_path);
+
+    // Incremental tests are special, they inherently cannot be run in parallel.
+    // `runtest::run` will be responsible for iterating over revisions.
+    let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental {
+        vec![None]
+    } else {
+        early_props.revisions.iter().map(Some).collect()
+    };
+
+    revisions
+        .into_iter()
+        .map(|revision| {
+            let src_file =
+                std::fs::File::open(&test_path).expect("open test file to parse ignores");
+            let cfg = revision.map(|v| &**v);
+            let test_name = crate::make_test_name(&config, testpaths, revision);
+            let mut desc = make_test_description(
+                &config, cache, test_name, &test_path, src_file, cfg, poisoned,
+            );
+            // Ignore tests that already run and are up to date with respect to inputs.
+            if !config.force_rerun {
+                desc.ignore |= is_up_to_date(
+                    &config,
+                    testpaths,
+                    &early_props,
+                    revision.map(|s| s.as_str()),
+                    inputs,
+                );
+            }
+            test::TestDescAndFn {
+                desc,
+                testfn: make_test_closure(config.clone(), testpaths, revision),
+            }
+        })
+        .collect()
+}
+
+fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+    output_base_dir(config, testpaths, revision).join("stamp")
+}
+
+fn files_related_to_test(
+    config: &Config,
+    testpaths: &TestPaths,
+    props: &EarlyProps,
+    revision: Option<&str>,
+) -> Vec<PathBuf> {
+    let mut related = vec![];
+
+    if testpaths.file.is_dir() {
+        // run-make tests use their individual directory
+        for entry in WalkDir::new(&testpaths.file) {
+            let path = entry.unwrap().into_path();
+            if path.is_file() {
+                related.push(path);
+            }
+        }
+    } else {
+        related.push(testpaths.file.clone());
+    }
+
+    for aux in &props.aux {
+        let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux);
+        related.push(path);
+    }
+
+    // UI test files.
+    for extension in UI_EXTENSIONS {
+        let path = expected_output_path(testpaths, revision, &config.compare_mode, extension);
+        related.push(path);
+    }
+
+    related
+}
+
+fn is_up_to_date(
+    config: &Config,
+    testpaths: &TestPaths,
+    props: &EarlyProps,
+    revision: Option<&str>,
+    inputs: &Stamp,
+) -> bool {
+    let stamp_name = stamp(config, testpaths, revision);
+    // Check hash.
+    let contents = match fs::read_to_string(&stamp_name) {
+        Ok(f) => f,
+        Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"),
+        Err(_) => return false,
+    };
+    let expected_hash = runtest::compute_stamp_hash(config);
+    if contents != expected_hash {
+        return false;
+    }
+
+    // Check timestamps.
+    let mut inputs = inputs.clone();
+    for path in files_related_to_test(config, testpaths, props, revision) {
+        inputs.add_path(&path);
+    }
+
+    inputs < Stamp::from_path(&stamp_name)
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+struct Stamp {
+    time: SystemTime,
+}
+
+impl Stamp {
+    fn from_path(path: &Path) -> Self {
+        let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH };
+        stamp.add_path(path);
+        stamp
+    }
+
+    fn add_path(&mut self, path: &Path) {
+        let modified = fs::metadata(path)
+            .and_then(|metadata| metadata.modified())
+            .unwrap_or(SystemTime::UNIX_EPOCH);
+        self.time = self.time.max(modified);
+    }
+
+    fn add_dir(&mut self, path: &Path) {
+        for entry in WalkDir::new(path) {
+            let entry = entry.unwrap();
+            if entry.file_type().is_file() {
+                let modified = entry
+                    .metadata()
+                    .ok()
+                    .and_then(|metadata| metadata.modified().ok())
+                    .unwrap_or(SystemTime::UNIX_EPOCH);
+                self.time = self.time.max(modified);
+            }
+        }
+    }
+}
+
+fn make_test_name(
+    config: &Config,
+    testpaths: &TestPaths,
+    revision: Option<&String>,
+) -> test::TestName {
+    // Print the name of the file, relative to the repository root.
+    // `src_base` looks like `/path/to/rust/tests/ui`
+    let root_directory = config.src_base.parent().unwrap().parent().unwrap();
+    let path = testpaths.file.strip_prefix(root_directory).unwrap();
+    let debugger = match config.debugger {
+        Some(d) => format!("-{}", d),
+        None => String::new(),
+    };
+    let mode_suffix = match config.compare_mode {
+        Some(ref mode) => format!(" ({})", mode.to_str()),
+        None => String::new(),
+    };
+
+    test::DynTestName(format!(
+        "[{}{}{}] {}{}",
+        config.mode,
+        debugger,
+        mode_suffix,
+        path.display(),
+        revision.map_or("".to_string(), |rev| format!("#{}", rev))
+    ))
+}
+
+fn make_test_closure(
+    config: Arc<Config>,
+    testpaths: &TestPaths,
+    revision: Option<&String>,
+) -> test::TestFn {
+    let config = config.clone();
+    let testpaths = testpaths.clone();
+    let revision = revision.cloned();
+    test::DynTestFn(Box::new(move || {
+        runtest::run(config, &testpaths, revision.as_deref());
+        Ok(())
+    }))
+}
+
+/// Returns `true` if the given target is an Android target for the
+/// purposes of GDB testing.
+fn is_android_gdb_target(target: &str) -> bool {
+    matches!(
+        &target[..],
+        "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android"
+    )
+}
+
+/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing.
+fn is_pc_windows_msvc_target(target: &str) -> bool {
+    target.ends_with("-pc-windows-msvc")
+}
+
+fn find_cdb(target: &str) -> Option<OsString> {
+    if !(cfg!(windows) && is_pc_windows_msvc_target(target)) {
+        return None;
+    }
+
+    let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?;
+    let cdb_arch = if cfg!(target_arch = "x86") {
+        "x86"
+    } else if cfg!(target_arch = "x86_64") {
+        "x64"
+    } else if cfg!(target_arch = "aarch64") {
+        "arm64"
+    } else if cfg!(target_arch = "arm") {
+        "arm"
+    } else {
+        return None; // No compatible CDB.exe in the Windows 10 SDK
+    };
+
+    let mut path = PathBuf::new();
+    path.push(pf86);
+    path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too?
+    path.push(cdb_arch);
+    path.push(r"cdb.exe");
+
+    if !path.exists() {
+        return None;
+    }
+
+    Some(path.into_os_string())
+}
+
+/// Returns Path to CDB
+fn analyze_cdb(cdb: Option<String>, target: &str) -> (Option<OsString>, Option<[u16; 4]>) {
+    let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target));
+
+    let mut version = None;
+    if let Some(cdb) = cdb.as_ref() {
+        if let Ok(output) = Command::new(cdb).arg("/version").output() {
+            if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() {
+                version = extract_cdb_version(&first_line);
+            }
+        }
+    }
+
+    (cdb, version)
+}
+
+fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> {
+    // Example full_version_line: "cdb version 10.0.18362.1"
+    let version = full_version_line.rsplit(' ').next()?;
+    let mut components = version.split('.');
+    let major: u16 = components.next().unwrap().parse().unwrap();
+    let minor: u16 = components.next().unwrap().parse().unwrap();
+    let patch: u16 = components.next().unwrap_or("0").parse().unwrap();
+    let build: u16 = components.next().unwrap_or("0").parse().unwrap();
+    Some([major, minor, patch, build])
+}
+
+/// Returns (Path to GDB, GDB Version, GDB has Rust Support)
+fn analyze_gdb(
+    gdb: Option<String>,
+    target: &str,
+    android_cross_path: &PathBuf,
+) -> (Option<String>, Option<u32>, bool) {
+    #[cfg(not(windows))]
+    const GDB_FALLBACK: &str = "gdb";
+    #[cfg(windows)]
+    const GDB_FALLBACK: &str = "gdb.exe";
+
+    const MIN_GDB_WITH_RUST: u32 = 7011010;
+
+    let fallback_gdb = || {
+        if is_android_gdb_target(target) {
+            let mut gdb_path = match android_cross_path.to_str() {
+                Some(x) => x.to_owned(),
+                None => panic!("cannot find android cross path"),
+            };
+            gdb_path.push_str("/bin/gdb");
+            gdb_path
+        } else {
+            GDB_FALLBACK.to_owned()
+        }
+    };
+
+    let gdb = match gdb {
+        None => fallback_gdb(),
+        Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb
+        Some(ref s) => s.to_owned(),
+    };
+
+    let mut version_line = None;
+    if let Ok(output) = Command::new(&gdb).arg("--version").output() {
+        if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() {
+            version_line = Some(first_line.to_string());
+        }
+    }
+
+    let version = match version_line {
+        Some(line) => extract_gdb_version(&line),
+        None => return (None, None, false),
+    };
+
+    let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST);
+
+    (Some(gdb), version, gdb_native_rust)
+}
+
+fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
+    let full_version_line = full_version_line.trim();
+
+    // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both
+    // of the ? sections being optional
+
+    // We will parse up to 3 digits for each component, ignoring the date
+
+    // We skip text in parentheses.  This avoids accidentally parsing
+    // the openSUSE version, which looks like:
+    //  GNU gdb (GDB; openSUSE Leap 15.0) 8.1
+    // This particular form is documented in the GNU coding standards:
+    // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
+
+    let unbracketed_part = full_version_line.split('[').next().unwrap();
+    let mut splits = unbracketed_part.trim_end().rsplit(' ');
+    let version_string = splits.next().unwrap();
+
+    let mut splits = version_string.split('.');
+    let major = splits.next().unwrap();
+    let minor = splits.next().unwrap();
+    let patch = splits.next();
+
+    let major: u32 = major.parse().unwrap();
+    let (minor, patch): (u32, u32) = match minor.find(not_a_digit) {
+        None => {
+            let minor = minor.parse().unwrap();
+            let patch: u32 = match patch {
+                Some(patch) => match patch.find(not_a_digit) {
+                    None => patch.parse().unwrap(),
+                    Some(idx) if idx > 3 => 0,
+                    Some(idx) => patch[..idx].parse().unwrap(),
+                },
+                None => 0,
+            };
+            (minor, patch)
+        }
+        // There is no patch version after minor-date (e.g. "4-2012").
+        Some(idx) => {
+            let minor = minor[..idx].parse().unwrap();
+            (minor, 0)
+        }
+    };
+
+    Some(((major * 1000) + minor) * 1000 + patch)
+}
+
+/// Returns (LLDB version, LLDB is rust-enabled)
+fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
+    // Extract the major LLDB version from the given version string.
+    // LLDB version strings are different for Apple and non-Apple platforms.
+    // The Apple variant looks like this:
+    //
+    // LLDB-179.5 (older versions)
+    // lldb-300.2.51 (new versions)
+    //
+    // We are only interested in the major version number, so this function
+    // will return `Some(179)` and `Some(300)` respectively.
+    //
+    // Upstream versions look like:
+    // lldb version 6.0.1
+    //
+    // There doesn't seem to be a way to correlate the Apple version
+    // with the upstream version, and since the tests were originally
+    // written against Apple versions, we make a fake Apple version by
+    // multiplying the first number by 100.  This is a hack, but
+    // normally fine because the only non-Apple version we test is
+    // rust-enabled.
+
+    let full_version_line = full_version_line.trim();
+
+    if let Some(apple_ver) =
+        full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-"))
+    {
+        if let Some(idx) = apple_ver.find(not_a_digit) {
+            let version: u32 = apple_ver[..idx].parse().unwrap();
+            return Some((version, full_version_line.contains("rust-enabled")));
+        }
+    } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") {
+        if let Some(idx) = lldb_ver.find(not_a_digit) {
+            let version: u32 = lldb_ver[..idx].parse().ok()?;
+            return Some((version * 100, full_version_line.contains("rust-enabled")));
+        }
+    }
+    None
+}
+
+fn not_a_digit(c: char) -> bool {
+    !c.is_digit(10)
+}
+
+fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) {
+    let mut collisions = Vec::new();
+    for path in found_paths {
+        for ancestor in path.ancestors().skip(1) {
+            if found_paths.contains(ancestor) {
+                collisions.push((path, ancestor.clone()));
+            }
+        }
+    }
+    if !collisions.is_empty() {
+        let collisions: String = collisions
+            .into_iter()
+            .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n"))
+            .collect();
+        panic!(
+            "{collisions}\n\
+            Tests cannot have overlapping names. Make sure they use unique prefixes."
+        );
+    }
+}
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index c4bef99..34d4855 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -1,45 +1,6 @@
-#![crate_name = "compiletest"]
-// The `test` crate is the only unstable feature
-// allowed here, just to share similar code.
-#![feature(test)]
+use std::{env, sync::Arc};
 
-extern crate test;
-
-use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
-use crate::common::{Config, Debugger, Mode, PassMode, TestPaths};
-use crate::util::logv;
-use build_helper::git::{get_git_modified_files, get_git_untracked_files};
-use core::panic;
-use getopts::Options;
-use lazycell::AtomicLazyCell;
-use std::collections::BTreeSet;
-use std::ffi::OsString;
-use std::fs;
-use std::io::{self, ErrorKind};
-use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
-use std::time::SystemTime;
-use std::{env, vec};
-use test::ColorConfig;
-use tracing::*;
-use walkdir::WalkDir;
-
-use self::header::{make_test_description, EarlyProps};
-use crate::header::HeadersCache;
-use std::sync::Arc;
-
-#[cfg(test)]
-mod tests;
-
-pub mod common;
-pub mod compute_diff;
-pub mod errors;
-pub mod header;
-mod json;
-mod raise_fd_limit;
-mod read2;
-pub mod runtest;
-pub mod util;
+use compiletest::{common::Mode, log_config, parse_config, run_tests};
 
 fn main() {
     tracing_subscriber::fmt::init();
@@ -57,1097 +18,3 @@ fn main() {
     log_config(&config);
     run_tests(config);
 }
-
-pub fn parse_config(args: Vec<String>) -> Config {
-    let mut opts = Options::new();
-    opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH")
-        .reqopt("", "run-lib-path", "path to target shared libraries", "PATH")
-        .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH")
-        .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
-        .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH")
-        .reqopt("", "python", "path to python to use for doc tests", "PATH")
-        .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH")
-        .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH")
-        .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
-        .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind")
-        .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH")
-        .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR")
-        .reqopt("", "src-base", "directory to scan for test files", "PATH")
-        .reqopt("", "build-base", "directory to deposit test outputs", "PATH")
-        .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH")
-        .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET")
-        .reqopt(
-            "",
-            "mode",
-            "which sort of compile tests to run",
-            "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
-            | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly",
-        )
-        .reqopt(
-            "",
-            "suite",
-            "which suite of compile tests to run. used for nicer error reporting.",
-            "SUITE",
-        )
-        .optopt(
-            "",
-            "pass",
-            "force {check,build,run}-pass tests to this mode.",
-            "check | build | run",
-        )
-        .optopt("", "run", "whether to execute run-* tests", "auto | always | never")
-        .optflag("", "ignored", "run tests marked as ignored")
-        .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING")
-        .optflag("", "exact", "filters match exactly")
-        .optopt(
-            "",
-            "runtool",
-            "supervisor program to run tests under \
-             (eg. emulator, valgrind)",
-            "PROGRAM",
-        )
-        .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
-        .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
-        .optflag("", "optimize-tests", "run tests with optimizations enabled")
-        .optflag("", "verbose", "run tests verbosely, showing all output")
-        .optflag(
-            "",
-            "bless",
-            "overwrite stderr/stdout files instead of complaining about a mismatch",
-        )
-        .optflag("", "quiet", "print one character per test instead of one line")
-        .optopt("", "color", "coloring: auto, always, never", "WHEN")
-        .optflag("", "json", "emit json output instead of plaintext output")
-        .optopt("", "logfile", "file to log test execution to", "FILE")
-        .optopt("", "target", "the target to build for", "TARGET")
-        .optopt("", "host", "the host to build for", "HOST")
-        .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH")
-        .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH")
-        .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING")
-        .optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING")
-        .optflag("", "system-llvm", "is LLVM the system LLVM")
-        .optopt("", "android-cross-path", "Android NDK standalone path", "PATH")
-        .optopt("", "adb-path", "path to the android debugger", "PATH")
-        .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH")
-        .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH")
-        .reqopt("", "cc", "path to a C compiler", "PATH")
-        .reqopt("", "cxx", "path to a C++ compiler", "PATH")
-        .reqopt("", "cflags", "flags for the C compiler", "FLAGS")
-        .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS")
-        .optopt("", "ar", "path to an archiver", "PATH")
-        .optopt("", "target-linker", "path to a linker for the target", "PATH")
-        .optopt("", "host-linker", "path to a linker for the host", "PATH")
-        .reqopt("", "llvm-components", "list of LLVM components built in", "LIST")
-        .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH")
-        .optopt("", "nodejs", "the name of nodejs", "PATH")
-        .optopt("", "npm", "the name of npm", "PATH")
-        .optopt("", "remote-test-client", "path to the remote test client", "PATH")
-        .optopt(
-            "",
-            "compare-mode",
-            "mode describing what file the actual ui output will be compared to",
-            "COMPARE MODE",
-        )
-        .optflag(
-            "",
-            "rustfix-coverage",
-            "enable this to generate a Rustfix coverage file, which is saved in \
-            `./<build_base>/rustfix_missing_coverage.txt`",
-        )
-        .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
-        .optflag("", "only-modified", "only run tests that result been modified")
-        .optflag("", "nocapture", "")
-        .optflag("h", "help", "show this message")
-        .reqopt("", "channel", "current Rust channel", "CHANNEL")
-        .optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries")
-        .optopt("", "edition", "default Rust edition", "EDITION");
-
-    let (argv0, args_) = args.split_first().unwrap();
-    if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
-        let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
-        println!("{}", opts.usage(&message));
-        println!();
-        panic!()
-    }
-
-    let matches = &match opts.parse(args_) {
-        Ok(m) => m,
-        Err(f) => panic!("{:?}", f),
-    };
-
-    if matches.opt_present("h") || matches.opt_present("help") {
-        let message = format!("Usage: {} [OPTIONS]  [TESTNAME...]", argv0);
-        println!("{}", opts.usage(&message));
-        println!();
-        panic!()
-    }
-
-    fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
-        match m.opt_str(nm) {
-            Some(s) => PathBuf::from(&s),
-            None => panic!("no option (=path) found for {}", nm),
-        }
-    }
-
-    fn make_absolute(path: PathBuf) -> PathBuf {
-        if path.is_relative() { env::current_dir().unwrap().join(path) } else { path }
-    }
-
-    let target = opt_str2(matches.opt_str("target"));
-    let android_cross_path = opt_path(matches, "android-cross-path");
-    let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target);
-    let (gdb, gdb_version, gdb_native_rust) =
-        analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path);
-    let (lldb_version, lldb_native_rust) = matches
-        .opt_str("lldb-version")
-        .as_deref()
-        .and_then(extract_lldb_version)
-        .map(|(v, b)| (Some(v), b))
-        .unwrap_or((None, false));
-    let color = match matches.opt_str("color").as_deref() {
-        Some("auto") | None => ColorConfig::AutoColor,
-        Some("always") => ColorConfig::AlwaysColor,
-        Some("never") => ColorConfig::NeverColor,
-        Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
-    };
-    let llvm_version =
-        matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else(
-            || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
-        );
-
-    let src_base = opt_path(matches, "src-base");
-    let run_ignored = matches.opt_present("ignored");
-    let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode");
-    let has_tidy = if mode == Mode::Rustdoc {
-        Command::new("tidy")
-            .arg("--version")
-            .stdout(Stdio::null())
-            .status()
-            .map_or(false, |status| status.success())
-    } else {
-        // Avoid spawning an external command when we know tidy won't be used.
-        false
-    };
-    Config {
-        bless: matches.opt_present("bless"),
-        compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
-        run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
-        rustc_path: opt_path(matches, "rustc-path"),
-        rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
-        rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from),
-        python: matches.opt_str("python").unwrap(),
-        jsondocck_path: matches.opt_str("jsondocck-path"),
-        jsondoclint_path: matches.opt_str("jsondoclint-path"),
-        valgrind_path: matches.opt_str("valgrind-path"),
-        force_valgrind: matches.opt_present("force-valgrind"),
-        run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
-        llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from),
-        llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from),
-        src_base,
-        build_base: opt_path(matches, "build-base"),
-        sysroot_base: opt_path(matches, "sysroot-base"),
-        stage_id: matches.opt_str("stage-id").unwrap(),
-        mode,
-        suite: matches.opt_str("suite").unwrap(),
-        debugger: None,
-        run_ignored,
-        filters: matches.free.clone(),
-        skip: matches.opt_strs("skip"),
-        filter_exact: matches.opt_present("exact"),
-        force_pass_mode: matches.opt_str("pass").map(|mode| {
-            mode.parse::<PassMode>()
-                .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode))
-        }),
-        run: matches.opt_str("run").and_then(|mode| match mode.as_str() {
-            "auto" => None,
-            "always" => Some(true),
-            "never" => Some(false),
-            _ => panic!("unknown `--run` option `{}` given", mode),
-        }),
-        logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
-        runtool: matches.opt_str("runtool"),
-        host_rustcflags: matches.opt_strs("host-rustcflags"),
-        target_rustcflags: matches.opt_strs("target-rustcflags"),
-        optimize_tests: matches.opt_present("optimize-tests"),
-        target,
-        host: opt_str2(matches.opt_str("host")),
-        cdb,
-        cdb_version,
-        gdb,
-        gdb_version,
-        gdb_native_rust,
-        lldb_version,
-        lldb_native_rust,
-        llvm_version,
-        system_llvm: matches.opt_present("system-llvm"),
-        android_cross_path,
-        adb_path: opt_str2(matches.opt_str("adb-path")),
-        adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")),
-        adb_device_status: opt_str2(matches.opt_str("target")).contains("android")
-            && "(none)" != opt_str2(matches.opt_str("adb-test-dir"))
-            && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
-        lldb_python_dir: matches.opt_str("lldb-python-dir"),
-        verbose: matches.opt_present("verbose"),
-        format: match (matches.opt_present("quiet"), matches.opt_present("json")) {
-            (true, true) => panic!("--quiet and --json are incompatible"),
-            (true, false) => test::OutputFormat::Terse,
-            (false, true) => test::OutputFormat::Json,
-            (false, false) => test::OutputFormat::Pretty,
-        },
-        only_modified: matches.opt_present("only-modified"),
-        color,
-        remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
-        compare_mode: matches
-            .opt_str("compare-mode")
-            .map(|s| s.parse().expect("invalid --compare-mode provided")),
-        rustfix_coverage: matches.opt_present("rustfix-coverage"),
-        has_tidy,
-        channel: matches.opt_str("channel").unwrap(),
-        git_hash: matches.opt_present("git-hash"),
-        edition: matches.opt_str("edition"),
-
-        cc: matches.opt_str("cc").unwrap(),
-        cxx: matches.opt_str("cxx").unwrap(),
-        cflags: matches.opt_str("cflags").unwrap(),
-        cxxflags: matches.opt_str("cxxflags").unwrap(),
-        ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")),
-        target_linker: matches.opt_str("target-linker"),
-        host_linker: matches.opt_str("host-linker"),
-        llvm_components: matches.opt_str("llvm-components").unwrap(),
-        nodejs: matches.opt_str("nodejs"),
-        npm: matches.opt_str("npm"),
-
-        force_rerun: matches.opt_present("force-rerun"),
-
-        target_cfgs: AtomicLazyCell::new(),
-
-        nocapture: matches.opt_present("nocapture"),
-    }
-}
-
-pub fn log_config(config: &Config) {
-    let c = config;
-    logv(c, "configuration:".to_string());
-    logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path));
-    logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
-    logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
-    logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
-    logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path));
-    logv(c, format!("src_base: {:?}", config.src_base.display()));
-    logv(c, format!("build_base: {:?}", config.build_base.display()));
-    logv(c, format!("stage_id: {}", config.stage_id));
-    logv(c, format!("mode: {}", config.mode));
-    logv(c, format!("run_ignored: {}", config.run_ignored));
-    logv(c, format!("filters: {:?}", config.filters));
-    logv(c, format!("skip: {:?}", config.skip));
-    logv(c, format!("filter_exact: {}", config.filter_exact));
-    logv(
-        c,
-        format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),),
-    );
-    logv(c, format!("runtool: {}", opt_str(&config.runtool)));
-    logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags));
-    logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags));
-    logv(c, format!("target: {}", config.target));
-    logv(c, format!("host: {}", config.host));
-    logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display()));
-    logv(c, format!("adb_path: {:?}", config.adb_path));
-    logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir));
-    logv(c, format!("adb_device_status: {}", config.adb_device_status));
-    logv(c, format!("ar: {}", config.ar));
-    logv(c, format!("target-linker: {:?}", config.target_linker));
-    logv(c, format!("host-linker: {:?}", config.host_linker));
-    logv(c, format!("verbose: {}", config.verbose));
-    logv(c, format!("format: {:?}", config.format));
-    logv(c, "\n".to_string());
-}
-
-pub fn opt_str(maybestr: &Option<String>) -> &str {
-    match *maybestr {
-        None => "(none)",
-        Some(ref s) => s,
-    }
-}
-
-pub fn opt_str2(maybestr: Option<String>) -> String {
-    match maybestr {
-        None => "(none)".to_owned(),
-        Some(s) => s,
-    }
-}
-
-pub fn run_tests(config: Arc<Config>) {
-    // If we want to collect rustfix coverage information,
-    // we first make sure that the coverage file does not exist.
-    // It will be created later on.
-    if config.rustfix_coverage {
-        let mut coverage_file_path = config.build_base.clone();
-        coverage_file_path.push("rustfix_missing_coverage.txt");
-        if coverage_file_path.exists() {
-            if let Err(e) = fs::remove_file(&coverage_file_path) {
-                panic!("Could not delete {} due to {}", coverage_file_path.display(), e)
-            }
-        }
-    }
-
-    // sadly osx needs some file descriptor limits raised for running tests in
-    // parallel (especially when we have lots and lots of child processes).
-    // For context, see #8904
-    unsafe {
-        raise_fd_limit::raise_fd_limit();
-    }
-    // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
-    // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
-    env::set_var("__COMPAT_LAYER", "RunAsInvoker");
-
-    // Let tests know which target they're running as
-    env::set_var("TARGET", &config.target);
-
-    let opts = test_opts(&config);
-
-    let mut configs = Vec::new();
-    if let Mode::DebugInfo = config.mode {
-        // Debugging emscripten code doesn't make sense today
-        if !config.target.contains("emscripten") {
-            configs.extend(configure_cdb(&config));
-            configs.extend(configure_gdb(&config));
-            configs.extend(configure_lldb(&config));
-        }
-    } else {
-        configs.push(config.clone());
-    };
-
-    let mut tests = Vec::new();
-    for c in configs {
-        let mut found_paths = BTreeSet::new();
-        make_tests(c, &mut tests, &mut found_paths);
-        check_overlapping_tests(&found_paths);
-    }
-
-    tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice()));
-
-    let res = test::run_tests_console(&opts, tests);
-    match res {
-        Ok(true) => {}
-        Ok(false) => {
-            // We want to report that the tests failed, but we also want to give
-            // some indication of just what tests we were running. Especially on
-            // CI, where there can be cross-compiled tests for a lot of
-            // architectures, without this critical information it can be quite
-            // easy to miss which tests failed, and as such fail to reproduce
-            // the failure locally.
-
-            println!(
-                "Some tests failed in compiletest suite={}{} mode={} host={} target={}",
-                config.suite,
-                config
-                    .compare_mode
-                    .as_ref()
-                    .map(|c| format!(" compare_mode={:?}", c))
-                    .unwrap_or_default(),
-                config.mode,
-                config.host,
-                config.target
-            );
-
-            std::process::exit(1);
-        }
-        Err(e) => {
-            // We don't know if tests passed or not, but if there was an error
-            // during testing we don't want to just succeed (we may not have
-            // tested something), so fail.
-            //
-            // This should realistically "never" happen, so don't try to make
-            // this a pretty error message.
-            panic!("I/O failure during tests: {:?}", e);
-        }
-    }
-}
-
-fn configure_cdb(config: &Config) -> Option<Arc<Config>> {
-    config.cdb.as_ref()?;
-
-    Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() }))
-}
-
-fn configure_gdb(config: &Config) -> Option<Arc<Config>> {
-    config.gdb_version?;
-
-    if config.matches_env("msvc") {
-        return None;
-    }
-
-    if config.remote_test_client.is_some() && !config.target.contains("android") {
-        println!(
-            "WARNING: debuginfo tests are not available when \
-             testing with remote"
-        );
-        return None;
-    }
-
-    if config.target.contains("android") {
-        println!(
-            "{} debug-info test uses tcp 5039 port.\
-             please reserve it",
-            config.target
-        );
-
-        // android debug-info test uses remote debugger so, we test 1 thread
-        // at once as they're all sharing the same TCP port to communicate
-        // over.
-        //
-        // we should figure out how to lift this restriction! (run them all
-        // on different ports allocated dynamically).
-        env::set_var("RUST_TEST_THREADS", "1");
-    }
-
-    Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() }))
-}
-
-fn configure_lldb(config: &Config) -> Option<Arc<Config>> {
-    config.lldb_python_dir.as_ref()?;
-
-    if let Some(350) = config.lldb_version {
-        println!(
-            "WARNING: The used version of LLDB (350) has a \
-             known issue that breaks debuginfo tests. See \
-             issue #32520 for more information. Skipping all \
-             LLDB-based tests!",
-        );
-        return None;
-    }
-
-    Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() }))
-}
-
-pub fn test_opts(config: &Config) -> test::TestOpts {
-    if env::var("RUST_TEST_NOCAPTURE").is_ok() {
-        eprintln!(
-            "WARNING: RUST_TEST_NOCAPTURE is no longer used. \
-                   Use the `--nocapture` flag instead."
-        );
-    }
-
-    test::TestOpts {
-        exclude_should_panic: false,
-        filters: config.filters.clone(),
-        filter_exact: config.filter_exact,
-        run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
-        format: config.format,
-        logfile: config.logfile.clone(),
-        run_tests: true,
-        bench_benchmarks: true,
-        nocapture: config.nocapture,
-        color: config.color,
-        shuffle: false,
-        shuffle_seed: None,
-        test_threads: None,
-        skip: config.skip.clone(),
-        list: false,
-        options: test::Options::new(),
-        time_options: None,
-        force_run_in_process: false,
-        fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
-    }
-}
-
-pub fn make_tests(
-    config: Arc<Config>,
-    tests: &mut Vec<test::TestDescAndFn>,
-    found_paths: &mut BTreeSet<PathBuf>,
-) {
-    debug!("making tests from {:?}", config.src_base.display());
-    let inputs = common_inputs_stamp(&config);
-    let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| {
-        panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err)
-    });
-
-    let cache = HeadersCache::load(&config);
-    let mut poisoned = false;
-    collect_tests_from_dir(
-        config.clone(),
-        &cache,
-        &config.src_base,
-        &PathBuf::new(),
-        &inputs,
-        tests,
-        found_paths,
-        &modified_tests,
-        &mut poisoned,
-    )
-    .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display()));
-
-    if poisoned {
-        eprintln!();
-        panic!("there are errors in tests");
-    }
-}
-
-/// Returns a stamp constructed from input files common to all test cases.
-fn common_inputs_stamp(config: &Config) -> Stamp {
-    let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root");
-
-    let mut stamp = Stamp::from_path(&config.rustc_path);
-
-    // Relevant pretty printer files
-    let pretty_printer_files = [
-        "src/etc/rust_types.py",
-        "src/etc/gdb_load_rust_pretty_printers.py",
-        "src/etc/gdb_lookup.py",
-        "src/etc/gdb_providers.py",
-        "src/etc/lldb_batchmode.py",
-        "src/etc/lldb_lookup.py",
-        "src/etc/lldb_providers.py",
-    ];
-    for file in &pretty_printer_files {
-        let path = rust_src_dir.join(file);
-        stamp.add_path(&path);
-    }
-
-    stamp.add_dir(&rust_src_dir.join("src/etc/natvis"));
-
-    stamp.add_dir(&config.run_lib_path);
-
-    if let Some(ref rustdoc_path) = config.rustdoc_path {
-        stamp.add_path(&rustdoc_path);
-        stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py"));
-    }
-
-    // Compiletest itself.
-    stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/"));
-
-    stamp
-}
-
-fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
-    if !config.only_modified {
-        return Ok(vec![]);
-    }
-    let files =
-        get_git_modified_files(Some(dir), &vec!["rs", "stderr", "fixed"])?.unwrap_or(vec![]);
-    // Add new test cases to the list, it will be convenient in daily development.
-    let untracked_files = get_git_untracked_files(None)?.unwrap_or(vec![]);
-
-    let all_paths = [&files[..], &untracked_files[..]].concat();
-    let full_paths = {
-        let mut full_paths: Vec<PathBuf> = all_paths
-            .into_iter()
-            .map(|f| PathBuf::from(f).with_extension("").with_extension("rs"))
-            .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None })
-            .collect();
-        full_paths.dedup();
-        full_paths.sort_unstable();
-        full_paths
-    };
-    Ok(full_paths)
-}
-
-fn collect_tests_from_dir(
-    config: Arc<Config>,
-    cache: &HeadersCache,
-    dir: &Path,
-    relative_dir_path: &Path,
-    inputs: &Stamp,
-    tests: &mut Vec<test::TestDescAndFn>,
-    found_paths: &mut BTreeSet<PathBuf>,
-    modified_tests: &Vec<PathBuf>,
-    poisoned: &mut bool,
-) -> io::Result<()> {
-    // Ignore directories that contain a file named `compiletest-ignore-dir`.
-    if dir.join("compiletest-ignore-dir").exists() {
-        return Ok(());
-    }
-
-    if config.mode == Mode::RunMake && dir.join("Makefile").exists() {
-        let paths = TestPaths {
-            file: dir.to_path_buf(),
-            relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
-        };
-        tests.extend(make_test(config, cache, &paths, inputs, poisoned));
-        return Ok(());
-    }
-
-    // If we find a test foo/bar.rs, we have to build the
-    // output directory `$build/foo` so we can write
-    // `$build/foo/bar` into it. We do this *now* in this
-    // sequential loop because otherwise, if we do it in the
-    // tests themselves, they race for the privilege of
-    // creating the directories and sometimes fail randomly.
-    let build_dir = output_relative_path(&config, relative_dir_path);
-    fs::create_dir_all(&build_dir).unwrap();
-
-    // Add each `.rs` file as a test, and recurse further on any
-    // subdirectories we find, except for `aux` directories.
-    for file in fs::read_dir(dir)? {
-        let file = file?;
-        let file_path = file.path();
-        let file_name = file.file_name();
-        if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) {
-            debug!("found test file: {:?}", file_path.display());
-            let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap());
-            found_paths.insert(rel_test_path);
-            let paths =
-                TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() };
-
-            tests.extend(make_test(config.clone(), cache, &paths, inputs, poisoned))
-        } else if file_path.is_dir() {
-            let relative_file_path = relative_dir_path.join(file.file_name());
-            if &file_name != "auxiliary" {
-                debug!("found directory: {:?}", file_path.display());
-                collect_tests_from_dir(
-                    config.clone(),
-                    cache,
-                    &file_path,
-                    &relative_file_path,
-                    inputs,
-                    tests,
-                    found_paths,
-                    modified_tests,
-                    poisoned,
-                )?;
-            }
-        } else {
-            debug!("found other file/directory: {:?}", file_path.display());
-        }
-    }
-    Ok(())
-}
-
-/// Returns true if `file_name` looks like a proper test file name.
-pub fn is_test(file_name: &OsString) -> bool {
-    let file_name = file_name.to_str().unwrap();
-
-    if !file_name.ends_with(".rs") {
-        return false;
-    }
-
-    // `.`, `#`, and `~` are common temp-file prefixes.
-    let invalid_prefixes = &[".", "#", "~"];
-    !invalid_prefixes.iter().any(|p| file_name.starts_with(p))
-}
-
-fn make_test(
-    config: Arc<Config>,
-    cache: &HeadersCache,
-    testpaths: &TestPaths,
-    inputs: &Stamp,
-    poisoned: &mut bool,
-) -> Vec<test::TestDescAndFn> {
-    let test_path = if config.mode == Mode::RunMake {
-        // Parse directives in the Makefile
-        testpaths.file.join("Makefile")
-    } else {
-        PathBuf::from(&testpaths.file)
-    };
-    let early_props = EarlyProps::from_file(&config, &test_path);
-
-    // Incremental tests are special, they inherently cannot be run in parallel.
-    // `runtest::run` will be responsible for iterating over revisions.
-    let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental {
-        vec![None]
-    } else {
-        early_props.revisions.iter().map(Some).collect()
-    };
-
-    revisions
-        .into_iter()
-        .map(|revision| {
-            let src_file =
-                std::fs::File::open(&test_path).expect("open test file to parse ignores");
-            let cfg = revision.map(|v| &**v);
-            let test_name = crate::make_test_name(&config, testpaths, revision);
-            let mut desc = make_test_description(
-                &config, cache, test_name, &test_path, src_file, cfg, poisoned,
-            );
-            // Ignore tests that already run and are up to date with respect to inputs.
-            if !config.force_rerun {
-                desc.ignore |= is_up_to_date(
-                    &config,
-                    testpaths,
-                    &early_props,
-                    revision.map(|s| s.as_str()),
-                    inputs,
-                );
-            }
-            test::TestDescAndFn {
-                desc,
-                testfn: make_test_closure(config.clone(), testpaths, revision),
-            }
-        })
-        .collect()
-}
-
-fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
-    output_base_dir(config, testpaths, revision).join("stamp")
-}
-
-fn files_related_to_test(
-    config: &Config,
-    testpaths: &TestPaths,
-    props: &EarlyProps,
-    revision: Option<&str>,
-) -> Vec<PathBuf> {
-    let mut related = vec![];
-
-    if testpaths.file.is_dir() {
-        // run-make tests use their individual directory
-        for entry in WalkDir::new(&testpaths.file) {
-            let path = entry.unwrap().into_path();
-            if path.is_file() {
-                related.push(path);
-            }
-        }
-    } else {
-        related.push(testpaths.file.clone());
-    }
-
-    for aux in &props.aux {
-        let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux);
-        related.push(path);
-    }
-
-    // UI test files.
-    for extension in UI_EXTENSIONS {
-        let path = expected_output_path(testpaths, revision, &config.compare_mode, extension);
-        related.push(path);
-    }
-
-    related
-}
-
-fn is_up_to_date(
-    config: &Config,
-    testpaths: &TestPaths,
-    props: &EarlyProps,
-    revision: Option<&str>,
-    inputs: &Stamp,
-) -> bool {
-    let stamp_name = stamp(config, testpaths, revision);
-    // Check hash.
-    let contents = match fs::read_to_string(&stamp_name) {
-        Ok(f) => f,
-        Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"),
-        Err(_) => return false,
-    };
-    let expected_hash = runtest::compute_stamp_hash(config);
-    if contents != expected_hash {
-        return false;
-    }
-
-    // Check timestamps.
-    let mut inputs = inputs.clone();
-    for path in files_related_to_test(config, testpaths, props, revision) {
-        inputs.add_path(&path);
-    }
-
-    inputs < Stamp::from_path(&stamp_name)
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-struct Stamp {
-    time: SystemTime,
-}
-
-impl Stamp {
-    fn from_path(path: &Path) -> Self {
-        let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH };
-        stamp.add_path(path);
-        stamp
-    }
-
-    fn add_path(&mut self, path: &Path) {
-        let modified = fs::metadata(path)
-            .and_then(|metadata| metadata.modified())
-            .unwrap_or(SystemTime::UNIX_EPOCH);
-        self.time = self.time.max(modified);
-    }
-
-    fn add_dir(&mut self, path: &Path) {
-        for entry in WalkDir::new(path) {
-            let entry = entry.unwrap();
-            if entry.file_type().is_file() {
-                let modified = entry
-                    .metadata()
-                    .ok()
-                    .and_then(|metadata| metadata.modified().ok())
-                    .unwrap_or(SystemTime::UNIX_EPOCH);
-                self.time = self.time.max(modified);
-            }
-        }
-    }
-}
-
-fn make_test_name(
-    config: &Config,
-    testpaths: &TestPaths,
-    revision: Option<&String>,
-) -> test::TestName {
-    // Print the name of the file, relative to the repository root.
-    // `src_base` looks like `/path/to/rust/tests/ui`
-    let root_directory = config.src_base.parent().unwrap().parent().unwrap();
-    let path = testpaths.file.strip_prefix(root_directory).unwrap();
-    let debugger = match config.debugger {
-        Some(d) => format!("-{}", d),
-        None => String::new(),
-    };
-    let mode_suffix = match config.compare_mode {
-        Some(ref mode) => format!(" ({})", mode.to_str()),
-        None => String::new(),
-    };
-
-    test::DynTestName(format!(
-        "[{}{}{}] {}{}",
-        config.mode,
-        debugger,
-        mode_suffix,
-        path.display(),
-        revision.map_or("".to_string(), |rev| format!("#{}", rev))
-    ))
-}
-
-fn make_test_closure(
-    config: Arc<Config>,
-    testpaths: &TestPaths,
-    revision: Option<&String>,
-) -> test::TestFn {
-    let config = config.clone();
-    let testpaths = testpaths.clone();
-    let revision = revision.cloned();
-    test::DynTestFn(Box::new(move || {
-        runtest::run(config, &testpaths, revision.as_deref());
-        Ok(())
-    }))
-}
-
-/// Returns `true` if the given target is an Android target for the
-/// purposes of GDB testing.
-fn is_android_gdb_target(target: &str) -> bool {
-    matches!(
-        &target[..],
-        "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android"
-    )
-}
-
-/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing.
-fn is_pc_windows_msvc_target(target: &str) -> bool {
-    target.ends_with("-pc-windows-msvc")
-}
-
-fn find_cdb(target: &str) -> Option<OsString> {
-    if !(cfg!(windows) && is_pc_windows_msvc_target(target)) {
-        return None;
-    }
-
-    let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?;
-    let cdb_arch = if cfg!(target_arch = "x86") {
-        "x86"
-    } else if cfg!(target_arch = "x86_64") {
-        "x64"
-    } else if cfg!(target_arch = "aarch64") {
-        "arm64"
-    } else if cfg!(target_arch = "arm") {
-        "arm"
-    } else {
-        return None; // No compatible CDB.exe in the Windows 10 SDK
-    };
-
-    let mut path = PathBuf::new();
-    path.push(pf86);
-    path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too?
-    path.push(cdb_arch);
-    path.push(r"cdb.exe");
-
-    if !path.exists() {
-        return None;
-    }
-
-    Some(path.into_os_string())
-}
-
-/// Returns Path to CDB
-fn analyze_cdb(cdb: Option<String>, target: &str) -> (Option<OsString>, Option<[u16; 4]>) {
-    let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target));
-
-    let mut version = None;
-    if let Some(cdb) = cdb.as_ref() {
-        if let Ok(output) = Command::new(cdb).arg("/version").output() {
-            if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() {
-                version = extract_cdb_version(&first_line);
-            }
-        }
-    }
-
-    (cdb, version)
-}
-
-fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> {
-    // Example full_version_line: "cdb version 10.0.18362.1"
-    let version = full_version_line.rsplit(' ').next()?;
-    let mut components = version.split('.');
-    let major: u16 = components.next().unwrap().parse().unwrap();
-    let minor: u16 = components.next().unwrap().parse().unwrap();
-    let patch: u16 = components.next().unwrap_or("0").parse().unwrap();
-    let build: u16 = components.next().unwrap_or("0").parse().unwrap();
-    Some([major, minor, patch, build])
-}
-
-/// Returns (Path to GDB, GDB Version, GDB has Rust Support)
-fn analyze_gdb(
-    gdb: Option<String>,
-    target: &str,
-    android_cross_path: &PathBuf,
-) -> (Option<String>, Option<u32>, bool) {
-    #[cfg(not(windows))]
-    const GDB_FALLBACK: &str = "gdb";
-    #[cfg(windows)]
-    const GDB_FALLBACK: &str = "gdb.exe";
-
-    const MIN_GDB_WITH_RUST: u32 = 7011010;
-
-    let fallback_gdb = || {
-        if is_android_gdb_target(target) {
-            let mut gdb_path = match android_cross_path.to_str() {
-                Some(x) => x.to_owned(),
-                None => panic!("cannot find android cross path"),
-            };
-            gdb_path.push_str("/bin/gdb");
-            gdb_path
-        } else {
-            GDB_FALLBACK.to_owned()
-        }
-    };
-
-    let gdb = match gdb {
-        None => fallback_gdb(),
-        Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb
-        Some(ref s) => s.to_owned(),
-    };
-
-    let mut version_line = None;
-    if let Ok(output) = Command::new(&gdb).arg("--version").output() {
-        if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() {
-            version_line = Some(first_line.to_string());
-        }
-    }
-
-    let version = match version_line {
-        Some(line) => extract_gdb_version(&line),
-        None => return (None, None, false),
-    };
-
-    let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST);
-
-    (Some(gdb), version, gdb_native_rust)
-}
-
-fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
-    let full_version_line = full_version_line.trim();
-
-    // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both
-    // of the ? sections being optional
-
-    // We will parse up to 3 digits for each component, ignoring the date
-
-    // We skip text in parentheses.  This avoids accidentally parsing
-    // the openSUSE version, which looks like:
-    //  GNU gdb (GDB; openSUSE Leap 15.0) 8.1
-    // This particular form is documented in the GNU coding standards:
-    // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
-
-    let unbracketed_part = full_version_line.split('[').next().unwrap();
-    let mut splits = unbracketed_part.trim_end().rsplit(' ');
-    let version_string = splits.next().unwrap();
-
-    let mut splits = version_string.split('.');
-    let major = splits.next().unwrap();
-    let minor = splits.next().unwrap();
-    let patch = splits.next();
-
-    let major: u32 = major.parse().unwrap();
-    let (minor, patch): (u32, u32) = match minor.find(not_a_digit) {
-        None => {
-            let minor = minor.parse().unwrap();
-            let patch: u32 = match patch {
-                Some(patch) => match patch.find(not_a_digit) {
-                    None => patch.parse().unwrap(),
-                    Some(idx) if idx > 3 => 0,
-                    Some(idx) => patch[..idx].parse().unwrap(),
-                },
-                None => 0,
-            };
-            (minor, patch)
-        }
-        // There is no patch version after minor-date (e.g. "4-2012").
-        Some(idx) => {
-            let minor = minor[..idx].parse().unwrap();
-            (minor, 0)
-        }
-    };
-
-    Some(((major * 1000) + minor) * 1000 + patch)
-}
-
-/// Returns (LLDB version, LLDB is rust-enabled)
-fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
-    // Extract the major LLDB version from the given version string.
-    // LLDB version strings are different for Apple and non-Apple platforms.
-    // The Apple variant looks like this:
-    //
-    // LLDB-179.5 (older versions)
-    // lldb-300.2.51 (new versions)
-    //
-    // We are only interested in the major version number, so this function
-    // will return `Some(179)` and `Some(300)` respectively.
-    //
-    // Upstream versions look like:
-    // lldb version 6.0.1
-    //
-    // There doesn't seem to be a way to correlate the Apple version
-    // with the upstream version, and since the tests were originally
-    // written against Apple versions, we make a fake Apple version by
-    // multiplying the first number by 100.  This is a hack, but
-    // normally fine because the only non-Apple version we test is
-    // rust-enabled.
-
-    let full_version_line = full_version_line.trim();
-
-    if let Some(apple_ver) =
-        full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-"))
-    {
-        if let Some(idx) = apple_ver.find(not_a_digit) {
-            let version: u32 = apple_ver[..idx].parse().unwrap();
-            return Some((version, full_version_line.contains("rust-enabled")));
-        }
-    } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") {
-        if let Some(idx) = lldb_ver.find(not_a_digit) {
-            let version: u32 = lldb_ver[..idx].parse().ok()?;
-            return Some((version * 100, full_version_line.contains("rust-enabled")));
-        }
-    }
-    None
-}
-
-fn not_a_digit(c: char) -> bool {
-    !c.is_digit(10)
-}
-
-fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) {
-    let mut collisions = Vec::new();
-    for path in found_paths {
-        for ancestor in path.ancestors().skip(1) {
-            if found_paths.contains(ancestor) {
-                collisions.push((path, ancestor.clone()));
-            }
-        }
-    }
-    if !collisions.is_empty() {
-        let collisions: String = collisions
-            .into_iter()
-            .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n"))
-            .collect();
-        panic!(
-            "{collisions}\n\
-            Tests cannot have overlapping names. Make sure they use unique prefixes."
-        );
-    }
-}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 5bc4d16..a799d93 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2045,7 +2045,10 @@ fn make_compile_args(
                 if let Some(pass) = &self.props.mir_unit_test {
                     rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]);
                 } else {
-                    rustc.arg("-Zmir-opt-level=4");
+                    rustc.args(&[
+                        "-Zmir-opt-level=4",
+                        "-Zmir-enable-passes=+ReorderBasicBlocks,+ReorderLocals",
+                    ]);
                 }
 
                 let mir_dump_dir = self.get_mir_dump_dir();
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 748240c..17bed38 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -104,6 +104,8 @@
     "x86_64-unknown-openbsd",
 ];
 
+pub const SAFESTACK_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
+
 pub fn make_new_path(path: &str) -> String {
     assert!(cfg!(windows));
     // Windows just uses PATH as the library search path, so we have to
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index d85cac7..25c8df4 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -133,10 +133,15 @@ pub struct Thread<'mir, 'tcx> {
     /// The join status.
     join_status: ThreadJoinStatus,
 
-    /// The temporary used for storing the argument of
-    /// the call to `miri_start_panic` (the panic payload) when unwinding.
+    /// Stack of active panic payloads for the current thread. Used for storing
+    /// the argument of the call to `miri_start_panic` (the panic payload) when unwinding.
     /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`.
-    pub(crate) panic_payload: Option<Scalar<Provenance>>,
+    ///
+    /// In real unwinding, the payload gets passed as an argument to the landing pad,
+    /// which then forwards it to 'Resume'. However this argument is implicit in MIR,
+    /// so we have to store it out-of-band. When there are multiple active unwinds,
+    /// the innermost one is always caught first, so we can store them as a stack.
+    pub(crate) panic_payloads: Vec<Scalar<Provenance>>,
 
     /// Last OS error location in memory. It is a 32-bit integer.
     pub(crate) last_error: Option<MPlaceTy<'tcx, Provenance>>,
@@ -206,7 +211,7 @@ fn new(name: Option<&str>, on_stack_empty: Option<StackEmptyCallback<'mir, 'tcx>
             stack: Vec::new(),
             top_user_relevant_frame: None,
             join_status: ThreadJoinStatus::Joinable,
-            panic_payload: None,
+            panic_payloads: Vec::new(),
             last_error: None,
             on_stack_empty,
         }
@@ -216,7 +221,7 @@ fn new(name: Option<&str>, on_stack_empty: Option<StackEmptyCallback<'mir, 'tcx>
 impl VisitTags for Thread<'_, '_> {
     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let Thread {
-            panic_payload,
+            panic_payloads: panic_payload,
             last_error,
             stack,
             top_user_relevant_frame: _,
@@ -226,7 +231,9 @@ fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
             on_stack_empty: _, // we assume the closure captures no GC-relevant state
         } = self;
 
-        panic_payload.visit_tags(visit);
+        for payload in panic_payload {
+            payload.visit_tags(visit);
+        }
         last_error.visit_tags(visit);
         for frame in stack {
             frame.visit_tags(visit)
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 18ae01a..7aefdfc 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -63,8 +63,7 @@ fn handle_miri_start_panic(
         let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?;
         let payload = this.read_scalar(payload)?;
         let thread = this.active_thread_mut();
-        assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics");
-        thread.panic_payload = Some(payload);
+        thread.panic_payloads.push(payload);
 
         // Jump to the unwind block to begin unwinding.
         this.unwind_to_block(unwind)?;
@@ -146,7 +145,7 @@ fn handle_stack_pop_unwind(
 
             // The Thread's `panic_payload` holds what was passed to `miri_start_panic`.
             // This is exactly the second argument we need to pass to `catch_fn`.
-            let payload = this.active_thread_mut().panic_payload.take().unwrap();
+            let payload = this.active_thread_mut().panic_payloads.pop().unwrap();
 
             // Push the `catch_fn` stackframe.
             let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?;
diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs
index 9378adb..adb3071 100644
--- a/src/tools/miri/tests/fail/panic/double_panic.rs
+++ b/src/tools/miri/tests/fail/panic/double_panic.rs
@@ -1,6 +1,4 @@
-//@error-in-other-file: the program aborted
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
 //@normalize-stderr-test: "\n  +[0-9]+:[^\n]+" -> "$1"
 //@normalize-stderr-test: "\n at [^\n]+" -> "$1"
 
@@ -11,6 +9,7 @@ fn drop(&mut self) {
     }
 }
 fn main() {
+    //~^ERROR: panic in a function that cannot unwind
     let _foo = Foo;
     panic!("first");
 }
diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr
index 77d5fc5..b6ac56f 100644
--- a/src/tools/miri/tests/fail/panic/double_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/double_panic.stderr
@@ -2,30 +2,17 @@
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC
 stack backtrace:
-thread panicked while panicking. aborting.
-error: abnormal termination: the program aborted execution
-  --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC
-   |
-LL |     ABORT();
-   | ^ the program aborted execution
-   |
-   = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC
-   = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-note: inside `<Foo as std::ops::Drop>::drop`
+error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/double_panic.rs:LL:CC
    |
-LL |         panic!("second");
-   | ^
-   = note: inside `std::ptr::drop_in_place::<Foo> - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
-note: inside `main`
-  --> $DIR/double_panic.rs:LL:CC
+LL | / fn main() {
+LL | |
+LL | |     let _foo = Foo;
+LL | |     panic!("first");
+LL | | }
+   | |_^ panic in a function that cannot unwind
    |
-LL | }
-   | ^
-   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: inside `main` at $DIR/double_panic.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.rs b/src/tools/miri/tests/pass/panic/nested_panic_caught.rs
new file mode 100644
index 0000000..8848131
--- /dev/null
+++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.rs
@@ -0,0 +1,25 @@
+//@normalize-stderr-test: "\| +\^+" -> "| ^"
+//@normalize-stderr-test: "\n  +[0-9]+:[^\n]+" -> "$1"
+//@normalize-stderr-test: "\n at [^\n]+" -> "$1"
+
+// Checks that nested panics work correctly.
+
+use std::panic::catch_unwind;
+
+fn double() {
+    struct Double;
+
+    impl Drop for Double {
+        fn drop(&mut self) {
+            let _ = catch_unwind(|| panic!("twice"));
+        }
+    }
+
+    let _d = Double;
+
+    panic!("once");
+}
+
+fn main() {
+    assert!(catch_unwind(|| double()).is_err());
+}
diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr
new file mode 100644
index 0000000..4e25932
--- /dev/null
+++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr
@@ -0,0 +1,4 @@
+thread 'main' panicked at 'once', $DIR/nested_panic_caught.rs:LL:CC
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+thread 'main' panicked at 'twice', $DIR/nested_panic_caught.rs:LL:CC
+stack backtrace:
diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml
new file mode 100644
index 0000000..f0c5b36
--- /dev/null
+++ b/src/tools/rustdoc-gui-test/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "rustdoc-gui-test"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+compiletest = { path = "../compiletest" }
+getopts = "0.2"
+walkdir = "2"
diff --git a/src/tools/rustdoc-gui-test/src/config.rs b/src/tools/rustdoc-gui-test/src/config.rs
new file mode 100644
index 0000000..dc4c56a
--- /dev/null
+++ b/src/tools/rustdoc-gui-test/src/config.rs
@@ -0,0 +1,62 @@
+use getopts::Options;
+use std::{env, path::PathBuf};
+
+pub(crate) struct Config {
+    pub(crate) nodejs: PathBuf,
+    pub(crate) npm: PathBuf,
+    pub(crate) rust_src: PathBuf,
+    pub(crate) out_dir: PathBuf,
+    pub(crate) initial_cargo: PathBuf,
+    pub(crate) jobs: String,
+    pub(crate) test_args: Vec<PathBuf>,
+    pub(crate) goml_files: Vec<PathBuf>,
+    pub(crate) rustc: PathBuf,
+    pub(crate) rustdoc: PathBuf,
+    pub(crate) verbose: bool,
+}
+
+impl Config {
+    pub(crate) fn from_args(args: Vec<String>) -> Self {
+        let mut opts = Options::new();
+        opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH")
+            .reqopt("", "npm", "absolute path of npm", "PATH")
+            .reqopt("", "out-dir", "output path of doc compilation", "PATH")
+            .reqopt("", "rust-src", "root source of the rust source", "PATH")
+            .reqopt(
+                "",
+                "initial-cargo",
+                "path to cargo to use for compiling tests/rustdoc-gui/src/*",
+                "PATH",
+            )
+            .reqopt("", "jobs", "jobs arg of browser-ui-test", "JOBS")
+            .optflag("", "verbose", "run tests verbosely, showing all output")
+            .optmulti("", "test-arg", "args for browser-ui-test", "FLAGS")
+            .optmulti("", "goml-file", "goml files for testing with browser-ui-test", "LIST");
+
+        let (argv0, args_) = args.split_first().unwrap();
+        if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
+            let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
+            println!("{}", opts.usage(&message));
+            std::process::exit(1);
+        }
+
+        let matches = &match opts.parse(args_) {
+            Ok(m) => m,
+            Err(f) => panic!("{:?}", f),
+        };
+
+        Self {
+            nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"),
+            npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"),
+            rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(),
+            out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(),
+            initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(),
+            jobs: matches.opt_str("jobs").unwrap(),
+            goml_files: matches.opt_strs("goml-file").iter().map(PathBuf::from).collect(),
+            test_args: matches.opt_strs("test-arg").iter().map(PathBuf::from).collect(),
+            rustc: env::var("RUSTC").map(PathBuf::from).unwrap(),
+            rustdoc: env::var("RUSTDOC").map(PathBuf::from).unwrap(),
+            verbose: matches.opt_present("verbose"),
+        }
+    }
+}
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
new file mode 100644
index 0000000..8dc18df
--- /dev/null
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -0,0 +1,162 @@
+use compiletest::header::TestProps;
+use config::Config;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use std::sync::Arc;
+use std::{env, fs};
+
+mod config;
+
+fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> {
+    let mut command = Command::new(&npm);
+    command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
+    if global {
+        command.arg("--global");
+    }
+    let lines = command
+        .output()
+        .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
+        .unwrap_or(String::new());
+    lines
+        .lines()
+        .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
+        .map(|v| v.to_owned())
+}
+
+fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
+    get_browser_ui_test_version_inner(npm, false)
+        .or_else(|| get_browser_ui_test_version_inner(npm, true))
+}
+
+fn compare_browser_ui_test_version(installed_version: &str, src: &Path) {
+    match fs::read_to_string(
+        src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"),
+    ) {
+        Ok(v) => {
+            if v.trim() != installed_version {
+                eprintln!(
+                    "⚠️ Installed version of browser-ui-test (`{}`) is different than the \
+                     one used in the CI (`{}`)",
+                    installed_version, v
+                );
+                eprintln!(
+                    "You can install this version using `npm update browser-ui-test` or by using \
+                     `npm install browser-ui-test@{}`",
+                    v,
+                );
+            }
+        }
+        Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e),
+    }
+}
+
+fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
+    for entry in walkdir::WalkDir::new(path) {
+        let entry = entry.ok()?;
+        if entry.file_type().is_file() && entry.file_name() == "lib.rs" {
+            return Some(entry.path().to_path_buf());
+        }
+    }
+    None
+}
+
+// FIXME: move `bootstrap::util::try_run` into `build_helper` crate
+// and use that one instead of creating this function.
+fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
+    let status = match cmd.status() {
+        Ok(status) => status,
+        Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cmd, e),
+    };
+    if !status.success() && print_cmd_on_fail {
+        println!(
+            "\n\ncommand did not execute successfully: {:?}\n\
+             expected success, got: {}\n\n",
+            cmd, status
+        );
+    }
+    status.success()
+}
+
+fn main() {
+    let config = Arc::new(Config::from_args(env::args().collect()));
+
+    // The goal here is to check if the necessary packages are installed, and if not, we
+    // panic.
+    match get_browser_ui_test_version(&config.npm) {
+        Some(version) => {
+            // We also check the version currently used in CI and emit a warning if it's not the
+            // same one.
+            compare_browser_ui_test_version(&version, &config.rust_src);
+        }
+        None => {
+            eprintln!(
+                r#"
+error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing.
+
+If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test`
+"#,
+            );
+
+            panic!("Cannot run rustdoc-gui tests");
+        }
+    }
+
+    let src_path = config.rust_src.join("tests/rustdoc-gui/src");
+    for entry in src_path.read_dir().expect("read_dir call failed") {
+        if let Ok(entry) = entry {
+            let path = entry.path();
+
+            if !path.is_dir() {
+                continue;
+            }
+
+            let mut cargo = Command::new(&config.initial_cargo);
+            cargo
+                .arg("doc")
+                .arg("--target-dir")
+                .arg(&config.out_dir)
+                .env("RUSTC_BOOTSTRAP", "1")
+                .env("RUSTDOC", &config.rustdoc)
+                .env("RUSTC", &config.rustc)
+                .current_dir(path);
+
+            if let Some(librs) = find_librs(entry.path()) {
+                let compiletest_c = compiletest::common::Config {
+                    edition: None,
+                    mode: compiletest::common::Mode::Rustdoc,
+                    ..Default::default()
+                };
+
+                let test_props = TestProps::from_file(&librs, None, &compiletest_c);
+
+                if !test_props.compile_flags.is_empty() {
+                    cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" "));
+                }
+
+                if let Some(flags) = &test_props.run_flags {
+                    cargo.arg(flags);
+                }
+            }
+
+            try_run(&mut cargo, config.verbose);
+        }
+    }
+
+    let mut command = Command::new(&config.nodejs);
+    command
+        .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js"))
+        .arg("--jobs")
+        .arg(&config.jobs)
+        .arg("--doc-folder")
+        .arg(config.out_dir.join("doc"))
+        .arg("--tests-folder")
+        .arg(config.rust_src.join("tests/rustdoc-gui"));
+
+    for file in &config.goml_files {
+        command.arg("--file").arg(file);
+    }
+
+    command.args(&config.test_args);
+
+    try_run(&mut command, config.verbose);
+}
diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs
new file mode 100644
index 0000000..5f8eaeb
--- /dev/null
+++ b/src/tools/tidy/src/fluent_alphabetical.rs
@@ -0,0 +1,72 @@
+//! Checks that all Flunt files have messages in alphabetical order
+
+use crate::walk::{filter_dirs, walk};
+use std::{fs::OpenOptions, io::Write, path::Path};
+
+use regex::Regex;
+
+lazy_static::lazy_static! {
+    static ref MESSAGE: Regex = Regex::new(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#).unwrap();
+}
+
+fn filter_fluent(path: &Path) -> bool {
+    if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
+}
+
+fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) {
+    let mut matches = MESSAGE.captures_iter(fluent).peekable();
+    while let Some(m) = matches.next() {
+        if let Some(next) = matches.peek() {
+            let name = m.get(1).unwrap();
+            let next = next.get(1).unwrap();
+            if name.as_str() > next.as_str() {
+                tidy_error!(
+                    bad,
+                    "{filename}: message `{}` appears before `{}`, but is alphabetically later than it
+run tidy with `--bless` to sort the file correctly",
+                    name.as_str(),
+                    next.as_str()
+                );
+            }
+        } else {
+            break;
+        }
+    }
+}
+
+fn sort_messages(fluent: &str) -> String {
+    let mut chunks = vec![];
+    let mut cur = String::new();
+    for line in fluent.lines() {
+        if MESSAGE.is_match(line) {
+            chunks.push(std::mem::take(&mut cur));
+        }
+        cur += line;
+        cur.push('\n');
+    }
+    chunks.push(cur);
+    chunks.sort();
+    let mut out = chunks.join("");
+    out = out.trim().to_string();
+    out.push('\n');
+    out
+}
+
+pub fn check(path: &Path, bless: bool, bad: &mut bool) {
+    walk(
+        path,
+        |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
+        &mut |ent, contents| {
+            if bless {
+                let sorted = sort_messages(contents);
+                if sorted != contents {
+                    let mut f =
+                        OpenOptions::new().write(true).truncate(true).open(ent.path()).unwrap();
+                    f.write(sorted.as_bytes()).unwrap();
+                }
+            } else {
+                check_alphabetic(ent.path().to_str().unwrap(), contents, bad);
+            }
+        },
+    );
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 3500032..e467514 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -59,6 +59,7 @@ fn tidy_error(bad: &mut bool, args: impl Display) -> std::io::Result<()> {
 pub mod error_codes;
 pub mod extdeps;
 pub mod features;
+pub mod fluent_alphabetical;
 pub mod mir_opt_tests;
 pub mod pal;
 pub mod primitive_docs;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index f59406c..1c4d96c 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -96,6 +96,7 @@ macro_rules! check {
 
         // Checks that only make sense for the compiler.
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
+        check!(fluent_alphabetical, &compiler_path, bless);
 
         // Checks that only make sense for the std libs.
         check!(pal, &library_path);
diff --git a/src/version b/src/version
index df484cb..0834888 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.71.0
+1.72.0
diff --git a/tests/codegen/sanitizer-safestack-attr-check.rs b/tests/codegen/sanitizer-safestack-attr-check.rs
new file mode 100644
index 0000000..b73ed00
--- /dev/null
+++ b/tests/codegen/sanitizer-safestack-attr-check.rs
@@ -0,0 +1,11 @@
+// This tests that the safestack attribute is applied when enabling the safe-stack sanitizer.
+//
+// needs-sanitizer-safestack
+// compile-flags: -Zsanitizer=safestack
+
+#![crate_type = "lib"]
+
+// CHECK: ; Function Attrs:{{.*}}safestack
+pub fn tagged() {}
+
+// CHECK: attributes #0 = {{.*}}safestack
diff --git a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
index 97826ed..bcdb120 100644
--- a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
+++ b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
@@ -3,41 +3,33 @@
 fn foo(_1: Option<String>) -> i32 {
     debug s => _1;                       // in scope 0 at $DIR/string.rs:+0:12: +0:13
     let mut _0: i32;                     // return place in scope 0 at $DIR/string.rs:+0:34: +0:37
-    let mut _2: &std::string::String;    // in scope 0 at $DIR/string.rs:+2:14: +2:17
-    let mut _3: &str;                    // in scope 0 at $DIR/string.rs:+2:14: +2:17
-    let mut _4: bool;                    // in scope 0 at $DIR/string.rs:+2:14: +2:17
-    let mut _5: isize;                   // in scope 0 at $DIR/string.rs:+2:9: +2:18
-    let _6: std::option::Option<std::string::String>; // in scope 0 at $DIR/string.rs:+3:9: +3:10
-    let mut _7: bool;                    // in scope 0 at $DIR/string.rs:+5:1: +5:2
+    let mut _2: bool;                    // in scope 0 at $DIR/string.rs:+5:1: +5:2
+    let mut _3: isize;                   // in scope 0 at $DIR/string.rs:+2:9: +2:18
+    let mut _4: &std::string::String;    // in scope 0 at $DIR/string.rs:+2:14: +2:17
+    let mut _5: &str;                    // in scope 0 at $DIR/string.rs:+2:14: +2:17
+    let mut _6: bool;                    // in scope 0 at $DIR/string.rs:+2:14: +2:17
+    let _7: std::option::Option<std::string::String>; // in scope 0 at $DIR/string.rs:+3:9: +3:10
     scope 1 {
-        debug s => _6;                   // in scope 1 at $DIR/string.rs:+3:9: +3:10
+        debug s => _7;                   // in scope 1 at $DIR/string.rs:+3:9: +3:10
     }
 
     bb0: {
-        _7 = const false;                // scope 0 at $DIR/string.rs:+1:11: +1:12
-        _7 = const true;                 // scope 0 at $DIR/string.rs:+1:11: +1:12
-        _5 = discriminant(_1);           // scope 0 at $DIR/string.rs:+1:11: +1:12
-        switchInt(move _5) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/string.rs:+1:5: +1:12
+        _2 = const false;                // scope 0 at $DIR/string.rs:+1:11: +1:12
+        _2 = const true;                 // scope 0 at $DIR/string.rs:+1:11: +1:12
+        _3 = discriminant(_1);           // scope 0 at $DIR/string.rs:+1:11: +1:12
+        switchInt(move _3) -> [1: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+1:5: +1:12
     }
 
     bb1: {
-        StorageLive(_6);                 // scope 0 at $DIR/string.rs:+3:9: +3:10
-        _7 = const false;                // scope 0 at $DIR/string.rs:+3:9: +3:10
-        _6 = move _1;                    // scope 0 at $DIR/string.rs:+3:9: +3:10
-        _0 = const 4321_i32;             // scope 1 at $DIR/string.rs:+3:14: +3:18
-        drop(_6) -> [return: bb6, unwind unreachable]; // scope 0 at $DIR/string.rs:+3:17: +3:18
-    }
-
-    bb2: {
-        _2 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17
-        _3 = <String as Deref>::deref(move _2) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17
+        _4 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17
+        _5 = <String as Deref>::deref(move _4) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17
                                          // mir::Constant
                                          // + span: $DIR/string.rs:9:14: 9:17
                                          // + literal: Const { ty: for<'a> fn(&'a String) -> &'a <String as Deref>::Target {<String as Deref>::deref}, val: Value(<ZST>) }
     }
 
-    bb3: {
-        _4 = <str as PartialEq>::eq(_3, const "a") -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17
+    bb2: {
+        _6 = <str as PartialEq>::eq(_5, const "a") -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17
                                          // mir::Constant
                                          // + span: $DIR/string.rs:9:14: 9:17
                                          // + literal: Const { ty: for<'a, 'b> fn(&'a str, &'b str) -> bool {<str as PartialEq>::eq}, val: Value(<ZST>) }
@@ -46,29 +38,37 @@
                                          // + literal: Const { ty: &str, val: Value(Slice(..)) }
     }
 
+    bb3: {
+        switchInt(move _6) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/string.rs:+2:14: +2:17
+    }
+
     bb4: {
-        switchInt(move _4) -> [0: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+2:14: +2:17
+        _0 = const 1234_i32;             // scope 0 at $DIR/string.rs:+2:22: +2:26
+        goto -> bb7;                     // scope 0 at $DIR/string.rs:+2:22: +2:26
     }
 
     bb5: {
-        _0 = const 1234_i32;             // scope 0 at $DIR/string.rs:+2:22: +2:26
-        goto -> bb9;                     // scope 0 at $DIR/string.rs:+2:22: +2:26
+        StorageLive(_7);                 // scope 0 at $DIR/string.rs:+3:9: +3:10
+        _2 = const false;                // scope 0 at $DIR/string.rs:+3:9: +3:10
+        _7 = move _1;                    // scope 0 at $DIR/string.rs:+3:9: +3:10
+        _0 = const 4321_i32;             // scope 1 at $DIR/string.rs:+3:14: +3:18
+        drop(_7) -> [return: bb6, unwind unreachable]; // scope 0 at $DIR/string.rs:+3:17: +3:18
     }
 
     bb6: {
-        StorageDead(_6);                 // scope 0 at $DIR/string.rs:+3:17: +3:18
-        goto -> bb9;                     // scope 0 at $DIR/string.rs:+3:17: +3:18
+        StorageDead(_7);                 // scope 0 at $DIR/string.rs:+3:17: +3:18
+        goto -> bb7;                     // scope 0 at $DIR/string.rs:+3:17: +3:18
     }
 
     bb7: {
-        return;                          // scope 0 at $DIR/string.rs:+5:2: +5:2
+        switchInt(_2) -> [0: bb9, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2
     }
 
     bb8: {
-        drop(_1) -> [return: bb7, unwind unreachable]; // scope 0 at $DIR/string.rs:+5:1: +5:2
+        drop(_1) -> [return: bb9, unwind unreachable]; // scope 0 at $DIR/string.rs:+5:1: +5:2
     }
 
     bb9: {
-        switchInt(_7) -> [0: bb7, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2
+        return;                          // scope 0 at $DIR/string.rs:+5:2: +5:2
     }
 }
diff --git a/tests/mir-opt/inline/cycle.g.Inline.diff b/tests/mir-opt/inline/cycle.g.Inline.diff
index 1e6e30f..53bf14a 100644
--- a/tests/mir-opt/inline/cycle.g.Inline.diff
+++ b/tests/mir-opt/inline/cycle.g.Inline.diff
@@ -8,8 +8,8 @@
 +     let mut _5: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
 +     scope 1 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12
 +         debug g => _2;                   // in scope 1 at $DIR/cycle.rs:5:6: 5:7
-+         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         let mut _4: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
++         let mut _3: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
++         let _4: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
 +         }
 +     }
@@ -25,16 +25,16 @@
 -                                          // mir::Constant
                                            // + span: $DIR/cycle.rs:12:7: 12:11
                                            // + literal: Const { ty: fn() {main}, val: Value(<ZST>) }
-+         StorageLive(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:12
-+         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
-+         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
++         StorageLive(_4);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:12
++         StorageLive(_3);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
++         _3 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         _5 = const ();                   // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
++         _4 = move (*_3)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
-+         StorageDead(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:12
++         StorageDead(_4);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:12
 +         StorageDead(_2);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:12
           StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:+1:12: +1:13
           _0 = const ();                   // scope 0 at $DIR/cycle.rs:+0:8: +2:2
@@ -51,7 +51,7 @@
 + 
 +     bb4: {
 +         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
 +         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
diff --git a/tests/mir-opt/inline/cycle.main.Inline.diff b/tests/mir-opt/inline/cycle.main.Inline.diff
index 3156349..fdf6337 100644
--- a/tests/mir-opt/inline/cycle.main.Inline.diff
+++ b/tests/mir-opt/inline/cycle.main.Inline.diff
@@ -8,8 +8,8 @@
 +     let mut _5: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
 +     scope 1 (inlined f::<fn() {g}>) {    // at $DIR/cycle.rs:17:5: 17:9
 +         debug g => _2;                   // in scope 1 at $DIR/cycle.rs:5:6: 5:7
-+         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         let mut _4: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
++         let mut _3: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
++         let _4: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
 +         }
 +     }
@@ -25,16 +25,16 @@
 -                                          // mir::Constant
                                            // + span: $DIR/cycle.rs:17:7: 17:8
                                            // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
-+         StorageLive(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:9
-+         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
-+         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
++         StorageLive(_4);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:9
++         StorageLive(_3);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
++         _3 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         _5 = const ();                   // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
++         _4 = move (*_3)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
-+         StorageDead(_3);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:9
++         StorageDead(_4);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:9
 +         StorageDead(_2);                 // scope 0 at $DIR/cycle.rs:+1:5: +1:9
           StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:+1:9: +1:10
           _0 = const ();                   // scope 0 at $DIR/cycle.rs:+0:11: +2:2
@@ -51,7 +51,7 @@
 + 
 +     bb4: {
 +         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
 +         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
diff --git a/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
index b36711f..33bf3b7 100644
--- a/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
+++ b/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
@@ -17,10 +17,10 @@
             debug _q => _9;              // in scope 2 at $DIR/inline_closure_captures.rs:+1:14: +1:16
             debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline_closure_captures.rs:+0:23: +0:24
             debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline_closure_captures.rs:+0:17: +0:18
-            let mut _10: i32;            // in scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
-            let mut _11: T;              // in scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
-            let mut _12: &i32;           // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24
-            let mut _13: &T;             // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+            let mut _10: &i32;           // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+            let mut _11: i32;            // in scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
+            let mut _12: &T;             // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+            let mut _13: T;              // in scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
         }
     }
 
@@ -49,15 +49,15 @@
         _7 = (move _8,);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
         StorageLive(_9);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
         _9 = move (_7.0: i32);           // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
-        StorageLive(_10);                // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
-        _12 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
-        _10 = (*_12);                    // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
-        StorageLive(_11);                // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
-        _13 = deref_copy ((*_6).1: &T);  // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
-        _11 = (*_13);                    // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
-        _0 = (move _10, move _11);       // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
+        StorageLive(_11);                // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
+        _10 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
+        _11 = (*_10);                    // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
+        StorageLive(_13);                // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
+        _12 = deref_copy ((*_6).1: &T);  // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
+        _13 = (*_12);                    // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
+        _0 = (move _11, move _13);       // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
+        StorageDead(_13);                // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24
         StorageDead(_11);                // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24
-        StorageDead(_10);                // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24
         StorageDead(_9);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
         StorageDead(_8);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9
         StorageDead(_7);                 // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9
diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.diff
index d501b6c..255451e 100644
--- a/tests/mir-opt/inline/inline_diverging.h.Inline.diff
+++ b/tests/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -8,15 +8,15 @@
 +     let mut _8: ();                      // in scope 0 at $DIR/inline_diverging.rs:27:13: 27:16
 +     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline_diverging.rs:22:5: 22:22
 +         debug f => _2;                   // in scope 1 at $DIR/inline_diverging.rs:26:36: 26:37
-+         let _3: !;                       // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10
-+         let mut _4: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
++         let mut _3: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
++         let _4: !;                       // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10
 +         let mut _5: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:14
-+         let mut _6: !;                   // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7
-+         let mut _7: !;                   // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10
++         let mut _6: !;                   // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10
++         let mut _7: !;                   // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7
 +         scope 2 {
-+             debug a => _3;               // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10
++             debug a => _4;               // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10
 +             scope 3 {
-+                 debug b => _7;           // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
++                 debug b => _6;           // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
 +             }
 +         }
 +         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
@@ -34,22 +34,22 @@
 -                                          // mir::Constant
                                            // + span: $DIR/inline_diverging.rs:22:16: 22:21
                                            // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) }
-+         StorageLive(_7);                 // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
-+         StorageLive(_3);                 // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10
-+         StorageLive(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
-+         _4 = &_2;                        // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
++         StorageLive(_6);                 // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
++         StorageLive(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10
++         StorageLive(_3);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
++         _3 = &_2;                        // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         StorageLive(_8);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
 +         _8 = const ();                   // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+         _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
++         _4 = move (*_3)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
 +     }
 + 
 +     bb1: {
 +         StorageDead(_5);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
-+         StorageLive(_6);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
-+         _6 = move _3;                    // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
-+         _1 = (move _6, move _7);         // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
-+         StorageDead(_6);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
-+         StorageDead(_3);                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         StorageLive(_7);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
++         _7 = move _4;                    // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
++         _1 = (move _7, move _6);         // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++         StorageDead(_7);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
++         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +         drop(_2) -> bb2;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
@@ -58,7 +58,7 @@
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_3) -> [return: bb4, unwind terminate]; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_4) -> [return: bb4, unwind terminate]; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
 +     bb4 (cleanup): {
@@ -71,10 +71,10 @@
 + 
 +     bb6: {
 +         StorageDead(_8);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageDead(_3);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
 +         StorageLive(_5);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
 +         _5 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         _7 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++         _6 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
 +                                          // mir::Constant
 +                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
 +                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.diff b/tests/mir-opt/inline/inline_generator.main.Inline.diff
index c3ca2d7..0dcae1e 100644
--- a/tests/mir-opt/inline/inline_generator.main.Inline.diff
+++ b/tests/mir-opt/inline/inline_generator.main.Inline.diff
@@ -23,9 +23,9 @@
 +     }
 +     scope 6 (inlined g::{closure#0}) {   // at $DIR/inline_generator.rs:9:33: 9:46
 +         debug a => _5;                   // in scope 6 at $DIR/inline_generator.rs:15:6: 15:7
-+         let mut _6: i32;                 // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39
++         let mut _6: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
 +         let mut _7: u32;                 // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
-+         let mut _8: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++         let mut _8: i32;                 // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39
 +         let mut _9: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
 +         let mut _10: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
 +     }
@@ -70,9 +70,9 @@
 -                                          // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) }
 +         StorageLive(_5);                 // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
 +         _5 = const false;                // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
-+         _8 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
-+         _7 = discriminant((*_8));        // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
-+         switchInt(move _7) -> [0: bb3, 1: bb8, 3: bb7, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++         _6 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++         _7 = discriminant((*_6));        // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++         switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
       }
   
 -     bb3: {
@@ -91,40 +91,40 @@
 +     }
 + 
 +     bb3: {
-+         StorageLive(_6);                 // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
-+         switchInt(_5) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
++         StorageLive(_8);                 // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
++         switchInt(_5) -> [0: bb4, otherwise: bb5]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
 +     }
 + 
 +     bb4: {
-+         _6 = const 7_i32;                // scope 6 at $DIR/inline_generator.rs:15:24: 15:25
++         _8 = const 13_i32;               // scope 6 at $DIR/inline_generator.rs:15:35: 15:37
 +         goto -> bb6;                     // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
 +     }
 + 
 +     bb5: {
-+         _6 = const 13_i32;               // scope 6 at $DIR/inline_generator.rs:15:35: 15:37
++         _8 = const 7_i32;                // scope 6 at $DIR/inline_generator.rs:15:24: 15:25
 +         goto -> bb6;                     // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
 +     }
 + 
 +     bb6: {
-+         _1 = GeneratorState::<i32, bool>::Yielded(move _6); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
++         _1 = GeneratorState::<i32, bool>::Yielded(move _8); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
 +         _9 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
 +         discriminant((*_9)) = 3;         // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
 +         goto -> bb1;                     // scope 0 at $DIR/inline_generator.rs:15:11: 15:39
 +     }
 + 
 +     bb7: {
-+         StorageLive(_6);                 // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
-+         StorageDead(_6);                 // scope 6 at $DIR/inline_generator.rs:15:38: 15:39
++         assert(const false, "generator resumed after completion") -> [success: bb7, unwind: bb2]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++     }
++ 
++     bb8: {
++         StorageLive(_8);                 // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++         StorageDead(_8);                 // scope 6 at $DIR/inline_generator.rs:15:38: 15:39
 +         _1 = GeneratorState::<i32, bool>::Complete(_5); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         _10 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         discriminant((*_10)) = 1;        // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
 +         goto -> bb1;                     // scope 0 at $DIR/inline_generator.rs:15:41: 15:41
 +     }
 + 
-+     bb8: {
-+         assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
-+     }
-+ 
 +     bb9: {
 +         unreachable;                     // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
       }
diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.diff
index 3aebfb6..5fed54f 100644
--- a/tests/mir-opt/inline/issue_106141.outer.Inline.diff
+++ b/tests/mir-opt/inline/issue_106141.outer.Inline.diff
@@ -4,9 +4,9 @@
   fn outer() -> usize {
       let mut _0: usize;                   // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24
 +     scope 1 (inlined inner) {            // at $DIR/issue_106141.rs:3:5: 3:12
-+         let mut _1: bool;                // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21
++         let mut _1: &[bool; 1];          // in scope 1 at $DIR/issue_106141.rs:12:18: 12:25
 +         let mut _2: bool;                // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21
-+         let mut _3: &[bool; 1];          // in scope 1 at $DIR/issue_106141.rs:12:18: 12:25
++         let mut _3: bool;                // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21
 +         scope 2 {
 +             debug buffer => const _;     // in scope 2 at $DIR/issue_106141.rs:12:9: 12:15
 +             scope 3 {
@@ -17,8 +17,8 @@
   
       bb0: {
 -         _0 = inner() -> bb1;             // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
-+         StorageLive(_3);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
-+         _3 = const _;                    // scope 1 at $DIR/issue_106141.rs:12:18: 12:25
++         StorageLive(_1);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
++         _1 = const _;                    // scope 1 at $DIR/issue_106141.rs:12:18: 12:25
                                            // mir::Constant
 -                                          // + span: $DIR/issue_106141.rs:3:5: 3:10
 -                                          // + literal: Const { ty: fn() -> usize {inner}, val: Value(<ZST>) }
@@ -31,14 +31,14 @@
       }
   
       bb1: {
-+         StorageLive(_1);                 // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
++         StorageLive(_3);                 // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
 +         _2 = Lt(_0, const 1_usize);      // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
 +         assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
 +     }
 + 
 +     bb2: {
-+         _1 = (*_3)[_0];                  // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
-+         switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
++         _3 = (*_1)[_0];                  // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
++         switchInt(move _3) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
 +     }
 + 
 +     bb3: {
@@ -47,8 +47,8 @@
 +     }
 + 
 +     bb4: {
-+         StorageDead(_1);                 // scope 3 at $DIR/issue_106141.rs:18:5: 18:6
-+         StorageDead(_3);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
++         StorageDead(_3);                 // scope 3 at $DIR/issue_106141.rs:18:5: 18:6
++         StorageDead(_1);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
           return;                          // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir
index 3c175ed..f4b2416 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir
@@ -7,38 +7,38 @@
     scope 1 (inlined core::num::<impl u16>::unchecked_shl) { // at $DIR/unchecked_shifts.rs:11:7: 11:23
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         debug rhs => _2;                 // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-        let mut _3: u16;                 // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        let mut _4: (u32,);              // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        let mut _5: u32;                 // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        let mut _3: (u32,);              // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        let mut _4: u32;                 // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        let mut _13: u16;                // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
         scope 2 {
             scope 3 (inlined core::num::<impl u16>::unchecked_shl::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                debug x => _5;           // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                let mut _6: std::option::Option<u16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                let mut _7: std::result::Result<u16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+                debug x => _4;           // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+                let mut _8: std::result::Result<u16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+                let mut _11: std::option::Option<u16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
                 scope 4 {
                     scope 5 (inlined <u32 as TryInto<u16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                        debug self => _5; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                        debug self => _4; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
                         scope 6 (inlined convert::num::<impl TryFrom<u32> for u16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                            debug u => _5; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-                            let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-                            let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-                            let mut _10: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                            debug u => _4; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                            let mut _5: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                            let mut _6: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                            let mut _7: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
                         }
                     }
                     scope 7 (inlined Result::<u16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                        debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-                        let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-                        let _12: u16;    // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+                        debug self => _8; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+                        let mut _9: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+                        let _10: u16;    // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
                         scope 8 {
-                            debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+                            debug x => _10; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
                         }
                     }
                     scope 9 (inlined #[track_caller] Option::<u16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                        debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-                        let mut _13: &std::option::Option<u16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-                        let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                        debug self => _11; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                        let mut _12: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                        let mut _14: &std::option::Option<u16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
                         scope 10 {
-                            debug val => _3; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
+                            debug val => _13; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
                         }
                         scope 11 {
                             scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
@@ -49,7 +49,7 @@
                             }
                         }
                         scope 12 (inlined Option::<u16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
-                            debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
+                            debug self => _14; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
                         }
                     }
                 }
@@ -58,81 +58,81 @@
     }
 
     bb0: {
+        StorageLive(_13);                // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
         StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _3 = (_2,);                      // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
         StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _4 = (_2,);                      // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _5 = move (_4.0: u32);           // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_6);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_7);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_8);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        StorageLive(_9);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        _9 = const 65535_u32;            // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        _8 = Gt(_5, move _9);            // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        StorageDead(_9);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _4 = move (_3.0: u32);           // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageLive(_8);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageLive(_6);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageLive(_5);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _5 = const 65535_u32;            // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _6 = Gt(_4, move _5);            // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_5);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        switchInt(move _6) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb1: {
-        StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-        return;                          // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2
+        StorageLive(_7);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _7 = _4 as u16 (IntToInt);       // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _8 = Result::<u16, TryFromIntError>::Ok(move _7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_7);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        goto -> bb3;                     // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb2: {
-        _7 = Result::<u16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _8 = Result::<u16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
                                          // mir::Constant
                                          // + span: no-location
                                          // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) }
-        goto -> bb4;                     // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        goto -> bb3;                     // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb3: {
-        StorageLive(_10);                // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        _10 = _5 as u16 (IntToInt);      // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        _7 = Result::<u16, TryFromIntError>::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        StorageDead(_10);                // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        goto -> bb4;                     // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_6);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _9 = discriminant(_8);           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb9]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb4: {
-        StorageDead(_8);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        StorageLive(_12);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _11 = discriminant(_7);          // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        _10 = move ((_8 as Ok).0: u16);  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        _11 = Option::<u16>::Some(move _10); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+        goto -> bb6;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb5: {
-        _6 = Option::<u16>::None;        // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        goto -> bb8;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        _11 = Option::<u16>::None;       // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        goto -> bb6;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb6: {
-        unreachable;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        StorageDead(_10);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageDead(_8);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageLive(_14);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _12 = discriminant(_11);         // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+        switchInt(move _12) -> [1: bb7, otherwise: bb9]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
     }
 
     bb7: {
-        _12 = move ((_7 as Ok).0: u16);  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        _6 = Option::<u16>::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        goto -> bb8;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-    }
-
-    bb8: {
-        StorageDead(_12);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageDead(_7);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_13);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _14 = discriminant(_6);          // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-        switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-    }
-
-    bb9: {
-        _3 = move ((_6 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-        StorageDead(_13);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageDead(_6);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _13 = move ((_11 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+        StorageDead(_14);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
         StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _0 = unchecked_shl::<u16>(_1, move _3) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+        StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _0 = unchecked_shl::<u16>(_1, move _13) -> [return: bb8, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::<u16>}, val: Value(<ZST>) }
     }
+
+    bb8: {
+        StorageDead(_13);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+        return;                          // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2
+    }
+
+    bb9: {
+        unreachable;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+    }
 }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir
index 724b3c5..67f0fe8 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir
@@ -7,38 +7,38 @@
     scope 1 (inlined core::num::<impl i16>::unchecked_shr) { // at $DIR/unchecked_shifts.rs:17:7: 17:23
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         debug rhs => _2;                 // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-        let mut _3: i16;                 // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        let mut _4: (u32,);              // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        let mut _5: u32;                 // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        let mut _3: (u32,);              // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        let mut _4: u32;                 // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        let mut _13: i16;                // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL
         scope 2 {
             scope 3 (inlined core::num::<impl i16>::unchecked_shr::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                debug x => _5;           // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                let mut _6: std::option::Option<i16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                let mut _7: std::result::Result<i16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+                debug x => _4;           // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+                let mut _8: std::result::Result<i16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+                let mut _11: std::option::Option<i16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL
                 scope 4 {
                     scope 5 (inlined <u32 as TryInto<i16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                        debug self => _5; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                        debug self => _4; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
                         scope 6 (inlined convert::num::<impl TryFrom<u32> for i16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                            debug u => _5; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-                            let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-                            let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-                            let mut _10: i16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                            debug u => _4; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                            let mut _5: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                            let mut _6: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                            let mut _7: i16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
                         }
                     }
                     scope 7 (inlined Result::<i16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                        debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-                        let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-                        let _12: i16;    // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+                        debug self => _8; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+                        let mut _9: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+                        let _10: i16;    // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
                         scope 8 {
-                            debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+                            debug x => _10; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
                         }
                     }
                     scope 9 (inlined #[track_caller] Option::<i16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL
-                        debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-                        let mut _13: &std::option::Option<i16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-                        let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                        debug self => _11; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                        let mut _12: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                        let mut _14: &std::option::Option<i16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
                         scope 10 {
-                            debug val => _3; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
+                            debug val => _13; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
                         }
                         scope 11 {
                             scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
@@ -49,7 +49,7 @@
                             }
                         }
                         scope 12 (inlined Option::<i16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
-                            debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
+                            debug self => _14; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
                         }
                     }
                 }
@@ -58,81 +58,81 @@
     }
 
     bb0: {
+        StorageLive(_13);                // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
         StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _3 = (_2,);                      // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
         StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _4 = (_2,);                      // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _5 = move (_4.0: u32);           // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_6);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_7);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_8);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        StorageLive(_9);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        _9 = const 32767_u32;            // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        _8 = Gt(_5, move _9);            // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        StorageDead(_9);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _4 = move (_3.0: u32);           // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageLive(_8);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageLive(_6);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageLive(_5);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _5 = const 32767_u32;            // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _6 = Gt(_4, move _5);            // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_5);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        switchInt(move _6) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb1: {
-        StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-        return;                          // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2
+        StorageLive(_7);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _7 = _4 as i16 (IntToInt);       // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _8 = Result::<i16, TryFromIntError>::Ok(move _7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_7);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        goto -> bb3;                     // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb2: {
-        _7 = Result::<i16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _8 = Result::<i16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
                                          // mir::Constant
                                          // + span: no-location
                                          // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) }
-        goto -> bb4;                     // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        goto -> bb3;                     // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb3: {
-        StorageLive(_10);                // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        _10 = _5 as i16 (IntToInt);      // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        _7 = Result::<i16, TryFromIntError>::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        StorageDead(_10);                // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        goto -> bb4;                     // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_6);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _9 = discriminant(_8);           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb9]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb4: {
-        StorageDead(_8);                 // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL
-        StorageLive(_12);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _11 = discriminant(_7);          // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        _10 = move ((_8 as Ok).0: i16);  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        _11 = Option::<i16>::Some(move _10); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+        goto -> bb6;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb5: {
-        _6 = Option::<i16>::None;        // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        goto -> bb8;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        _11 = Option::<i16>::None;       // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        goto -> bb6;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb6: {
-        unreachable;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        StorageDead(_10);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageDead(_8);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageLive(_14);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _12 = discriminant(_11);         // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+        switchInt(move _12) -> [1: bb7, otherwise: bb9]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
     }
 
     bb7: {
-        _12 = move ((_7 as Ok).0: i16);  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        _6 = Option::<i16>::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        goto -> bb8;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-    }
-
-    bb8: {
-        StorageDead(_12);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageDead(_7);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageLive(_13);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _14 = discriminant(_6);          // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-        switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-    }
-
-    bb9: {
-        _3 = move ((_6 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
-        StorageDead(_13);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageDead(_6);                 // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _13 = move ((_11 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+        StorageDead(_14);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL
         StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
-        _0 = unchecked_shr::<i16>(_1, move _3) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+        StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL
+        _0 = unchecked_shr::<i16>(_1, move _13) -> [return: bb8, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL
                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::<i16>}, val: Value(<ZST>) }
     }
+
+    bb8: {
+        StorageDead(_13);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+        return;                          // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2
+    }
+
+    bb9: {
+        unreachable;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+    }
 }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir
index c5e2469..601d83702 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir
@@ -5,8 +5,8 @@
     let mut _0: T;                       // return place in scope 0 at $DIR/unwrap_unchecked.rs:+0:54: +0:55
     scope 1 (inlined #[track_caller] Option::<T>::unwrap_unchecked) { // at $DIR/unwrap_unchecked.rs:10:9: 10:27
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
-        let mut _2: &std::option::Option<T>; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
-        let mut _3: isize;               // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
+        let mut _2: isize;               // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
+        let mut _3: &std::option::Option<T>; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
         scope 2 {
             debug val => _0;             // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
         }
@@ -19,23 +19,23 @@
             }
         }
         scope 4 (inlined Option::<T>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
-            debug self => _2;            // in scope 4 at $SRC_DIR/core/src/option.rs:LL:COL
+            debug self => _3;            // in scope 4 at $SRC_DIR/core/src/option.rs:LL:COL
         }
     }
 
     bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27
-        _3 = discriminant(_1);           // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
-        switchInt(move _3) -> [1: bb2, otherwise: bb1]; // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
+        StorageLive(_3);                 // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27
+        _2 = discriminant(_1);           // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
+        switchInt(move _2) -> [1: bb1, otherwise: bb2]; // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
     }
 
     bb1: {
-        unreachable;                     // scope 6 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+        _0 = move ((_1 as Some).0: T);   // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
+        StorageDead(_3);                 // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27
+        return;                          // scope 0 at $DIR/unwrap_unchecked.rs:+2:2: +2:2
     }
 
     bb2: {
-        _0 = move ((_1 as Some).0: T);   // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL
-        StorageDead(_2);                 // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27
-        return;                          // scope 0 at $DIR/unwrap_unchecked.rs:+2:2: +2:2
+        unreachable;                     // scope 6 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
     }
 }
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff
index d048b9e..2f68f65 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.diff
+++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff
@@ -18,8 +18,8 @@
       let mut _13: bool;                   // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       scope 1 (inlined imm8) {             // at $DIR/issue_101973.rs:15:5: 15:17
           debug x => _1;                   // in scope 1 at $DIR/issue_101973.rs:6:13: 6:14
-          let mut _14: u32;                // in scope 1 at $DIR/issue_101973.rs:8:12: 8:27
-          let mut _15: u32;                // in scope 1 at $DIR/issue_101973.rs:8:12: 8:20
+          let mut _14: u32;                // in scope 1 at $DIR/issue_101973.rs:8:12: 8:20
+          let mut _15: u32;                // in scope 1 at $DIR/issue_101973.rs:8:12: 8:27
           scope 2 {
               debug out => _4;             // in scope 2 at $DIR/issue_101973.rs:7:9: 7:16
           }
@@ -33,13 +33,13 @@
           StorageLive(_2);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
           StorageLive(_3);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58
           StorageLive(_4);                 // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17
-          StorageLive(_14);                // scope 2 at $DIR/issue_101973.rs:8:12: 8:27
-          StorageLive(_15);                // scope 2 at $DIR/issue_101973.rs:8:12: 8:20
-          _15 = Shr(_1, const 0_i32);      // scope 2 at $DIR/issue_101973.rs:8:12: 8:20
-          _14 = BitAnd(move _15, const 255_u32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27
-          StorageDead(_15);                // scope 2 at $DIR/issue_101973.rs:8:26: 8:27
-          _4 = BitOr(const 0_u32, move _14); // scope 2 at $DIR/issue_101973.rs:8:5: 8:27
+          StorageLive(_15);                // scope 2 at $DIR/issue_101973.rs:8:12: 8:27
+          StorageLive(_14);                // scope 2 at $DIR/issue_101973.rs:8:12: 8:20
+          _14 = Shr(_1, const 0_i32);      // scope 2 at $DIR/issue_101973.rs:8:12: 8:20
+          _15 = BitAnd(move _14, const 255_u32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27
           StorageDead(_14);                // scope 2 at $DIR/issue_101973.rs:8:26: 8:27
+          _4 = BitOr(const 0_u32, move _15); // scope 2 at $DIR/issue_101973.rs:8:5: 8:27
+          StorageDead(_15);                // scope 2 at $DIR/issue_101973.rs:8:26: 8:27
           StorageLive(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageLive(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageLive(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
index 9f955b4..fac4b8a 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
@@ -3,19 +3,19 @@
 fn num_to_digit(_1: char) -> u32 {
     debug num => _1;                     // in scope 0 at $DIR/issue_59352.rs:+0:21: +0:24
     let mut _0: u32;                     // return place in scope 0 at $DIR/issue_59352.rs:+0:35: +0:38
-    let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
+    let mut _5: std::option::Option<u32>; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
     scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue_59352.rs:15:12: 15:23
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         debug radix => const 8_u32;      // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
+        let _2: std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         let mut _3: &std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
-        let _4: std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         scope 2 (inlined Option::<u32>::is_some) { // at $SRC_DIR/core/src/char/methods.rs:LL:COL
             debug self => _3;            // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
-            let mut _5: isize;           // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
+            let mut _4: isize;           // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
         }
     }
     scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue_59352.rs:15:42: 15:50
-        debug self => _2;                // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
+        debug self => _5;                // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
         let mut _6: isize;               // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
         let mut _7: !;                   // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
         scope 4 {
@@ -25,44 +25,35 @@
 
     bb0: {
         StorageLive(_3);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
-        StorageLive(_4);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
-        _4 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
+        StorageLive(_2);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
+        _2 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb1; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/char/methods.rs:LL:COL
                                          // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) }
     }
 
     bb1: {
-        StorageLive(_2);                 // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
-        _2 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb2; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
+        _3 = &_2;                        // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
+        _4 = discriminant((*_3));        // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
+        StorageDead(_3);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
+        StorageDead(_2);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
+        switchInt(move _4) -> [1: bb2, otherwise: bb7]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+    }
+
+    bb2: {
+        StorageLive(_5);                 // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
+        _5 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb3; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
                                          // mir::Constant
                                          // + span: $DIR/issue_59352.rs:15:30: 15:38
                                          // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) }
     }
 
-    bb2: {
-        _6 = discriminant(_2);           // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
-        switchInt(move _6) -> [0: bb6, 1: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
-    }
-
     bb3: {
-        _0 = const 0_u32;                // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61
-        goto -> bb4;                     // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63
+        _6 = discriminant(_5);           // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
+        switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
     }
 
     bb4: {
-        return;                          // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2
-    }
-
-    bb5: {
-        _3 = &_4;                        // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
-        _5 = discriminant((*_3));        // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
-        StorageDead(_3);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
-        StorageDead(_4);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
-        switchInt(move _5) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
-    }
-
-    bb6: {
         _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value"); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/option.rs:LL:COL
@@ -72,13 +63,22 @@
                                          // + literal: Const { ty: &str, val: Value(Slice(..)) }
     }
 
-    bb7: {
+    bb5: {
+        _0 = move ((_5 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
+        StorageDead(_5);                 // scope 0 at $DIR/issue_59352.rs:+2:49: +2:50
+        goto -> bb8;                     // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63
+    }
+
+    bb6: {
         unreachable;                     // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
     }
 
+    bb7: {
+        _0 = const 0_u32;                // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61
+        goto -> bb8;                     // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63
+    }
+
     bb8: {
-        _0 = move ((_2 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
-        StorageDead(_2);                 // scope 0 at $DIR/issue_59352.rs:+2:49: +2:50
-        goto -> bb4;                     // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63
+        return;                          // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2
     }
 }
diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
index 0e885cf..6b80516 100644
--- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
@@ -13,15 +13,15 @@
 
     bb0: {
         _2 = discriminant(_1);           // scope 0 at $DIR/duplicate_switch_targets.rs:+1:11: +1:12
-        switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/duplicate_switch_targets.rs:+1:5: +1:12
+        switchInt(move _2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/duplicate_switch_targets.rs:+1:5: +1:12
     }
 
     bb1: {
-        unreachable;                     // scope 2 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+        _0 = move _1;                    // scope 0 at $DIR/duplicate_switch_targets.rs:+2:21: +2:22
+        return;                          // scope 0 at $DIR/duplicate_switch_targets.rs:+5:2: +5:2
     }
 
     bb2: {
-        _0 = move _1;                    // scope 0 at $DIR/duplicate_switch_targets.rs:+2:21: +2:22
-        return;                          // scope 0 at $DIR/duplicate_switch_targets.rs:+5:2: +5:2
+        unreachable;                     // scope 2 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
     }
 }
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir
index 343a4a5..9856cdd 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir
@@ -7,20 +7,20 @@
     let mut _0: ();                      // return place in scope 0 at $DIR/range_iter.rs:+0:60: +0:60
     let mut _4: std::ops::Range<u32>;    // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24
     let mut _5: std::ops::Range<u32>;    // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24
-    let _6: ();                          // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24
+    let mut _6: &mut std::ops::Range<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24
     let mut _7: std::option::Option<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24
-    let mut _8: &mut std::ops::Range<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24
-    let mut _9: isize;                   // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6
-    let mut _11: &impl Fn(u32);          // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10
-    let mut _12: (u32,);                 // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13
+    let mut _8: isize;                   // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6
+    let mut _10: &impl Fn(u32);          // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10
+    let mut _11: (u32,);                 // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13
+    let _12: ();                         // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24
     scope 1 {
         debug iter => _5;                // in scope 1 at $DIR/range_iter.rs:+1:14: +1:24
-        let _10: u32;                    // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10
+        let _9: u32;                     // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10
         scope 2 {
-            debug x => _10;              // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10
+            debug x => _9;               // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10
         }
         scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) { // at $DIR/range_iter.rs:21:14: 21:24
-            debug self => _8;            // in scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL
+            debug self => _6;            // in scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL
         }
     }
     scope 3 (inlined <std::ops::Range<u32> as IntoIterator>::into_iter) { // at $DIR/range_iter.rs:21:14: 21:24
@@ -36,56 +36,56 @@
 
     bb1: {
         StorageLive(_7);                 // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
-        _8 = &mut _5;                    // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
-        _7 = <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next(_8) -> [return: bb9, unwind: bb7]; // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL
+        _6 = &mut _5;                    // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
+        _7 = <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next(_6) -> [return: bb2, unwind: bb8]; // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL
                                          // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range<u32>) -> Option<<std::ops::Range<u32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) }
     }
 
     bb2: {
-        _10 = ((_7 as Some).0: u32);     // scope 1 at $DIR/range_iter.rs:+1:9: +1:10
-        StorageLive(_11);                // scope 2 at $DIR/range_iter.rs:+2:9: +2:10
-        _11 = &_3;                       // scope 2 at $DIR/range_iter.rs:+2:9: +2:10
-        StorageLive(_12);                // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
-        _12 = (_10,);                    // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
-        _6 = <impl Fn(u32) as Fn<(u32,)>>::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
+        _8 = discriminant(_7);           // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
+        switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb7]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
+    }
+
+    bb3: {
+        StorageDead(_7);                 // scope 1 at $DIR/range_iter.rs:+3:5: +3:6
+        StorageDead(_5);                 // scope 0 at $DIR/range_iter.rs:+3:5: +3:6
+        drop(_3) -> bb4;                 // scope 0 at $DIR/range_iter.rs:+4:1: +4:2
+    }
+
+    bb4: {
+        return;                          // scope 0 at $DIR/range_iter.rs:+4:2: +4:2
+    }
+
+    bb5: {
+        _9 = ((_7 as Some).0: u32);      // scope 1 at $DIR/range_iter.rs:+1:9: +1:10
+        StorageLive(_10);                // scope 2 at $DIR/range_iter.rs:+2:9: +2:10
+        _10 = &_3;                       // scope 2 at $DIR/range_iter.rs:+2:9: +2:10
+        StorageLive(_11);                // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
+        _11 = (_9,);                     // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
+        _12 = <impl Fn(u32) as Fn<(u32,)>>::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
                                          // mir::Constant
                                          // + span: $DIR/range_iter.rs:22:9: 22:10
                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> <impl Fn(u32) as FnOnce<(u32,)>>::Output {<impl Fn(u32) as Fn<(u32,)>>::call}, val: Value(<ZST>) }
     }
 
-    bb3: {
-        unreachable;                     // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
-    }
-
-    bb4: {
-        StorageDead(_7);                 // scope 1 at $DIR/range_iter.rs:+3:5: +3:6
-        StorageDead(_5);                 // scope 0 at $DIR/range_iter.rs:+3:5: +3:6
-        drop(_3) -> bb6;                 // scope 0 at $DIR/range_iter.rs:+4:1: +4:2
-    }
-
-    bb5: {
-        StorageDead(_12);                // scope 2 at $DIR/range_iter.rs:+2:12: +2:13
+    bb6: {
         StorageDead(_11);                // scope 2 at $DIR/range_iter.rs:+2:12: +2:13
+        StorageDead(_10);                // scope 2 at $DIR/range_iter.rs:+2:12: +2:13
         StorageDead(_7);                 // scope 1 at $DIR/range_iter.rs:+3:5: +3:6
         goto -> bb1;                     // scope 1 at $DIR/range_iter.rs:+1:5: +3:6
     }
 
-    bb6: {
-        return;                          // scope 0 at $DIR/range_iter.rs:+4:2: +4:2
-    }
-
-    bb7 (cleanup): {
-        drop(_3) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2
+    bb7: {
+        unreachable;                     // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
     }
 
     bb8 (cleanup): {
-        resume;                          // scope 0 at $DIR/range_iter.rs:+0:1: +4:2
+        drop(_3) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2
     }
 
-    bb9: {
-        _9 = discriminant(_7);           // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
-        switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24
+    bb9 (cleanup): {
+        resume;                          // scope 0 at $DIR/range_iter.rs:+0:1: +4:2
     }
 }
diff --git a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir
index f45eabb..a187d65 100644
--- a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir
@@ -7,20 +7,20 @@
     let mut _0: ();                      // return place in scope 0 at $DIR/range_iter.rs:+0:62: +0:62
     let mut _4: std::ops::RangeInclusive<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25
     let mut _5: std::ops::RangeInclusive<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25
-    let _6: ();                          // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25
+    let mut _6: &mut std::ops::RangeInclusive<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25
     let mut _7: std::option::Option<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25
-    let mut _8: &mut std::ops::RangeInclusive<u32>; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25
-    let mut _9: isize;                   // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6
-    let mut _11: &impl Fn(u32);          // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10
-    let mut _12: (u32,);                 // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13
+    let mut _8: isize;                   // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6
+    let mut _10: &impl Fn(u32);          // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10
+    let mut _11: (u32,);                 // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13
+    let _12: ();                         // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25
     scope 1 {
         debug iter => _5;                // in scope 1 at $DIR/range_iter.rs:+1:14: +1:25
-        let _10: u32;                    // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10
+        let _9: u32;                     // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10
         scope 2 {
-            debug x => _10;              // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10
+            debug x => _9;               // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10
         }
         scope 5 (inlined iter::range::<impl Iterator for RangeInclusive<u32>>::next) { // at $DIR/range_iter.rs:28:14: 28:25
-            debug self => _8;            // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
+            debug self => _6;            // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
         }
     }
     scope 3 (inlined RangeInclusive::<u32>::new) { // at $DIR/range_iter.rs:28:14: 28:25
@@ -40,56 +40,56 @@
 
     bb1: {
         StorageLive(_7);                 // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
-        _8 = &mut _5;                    // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
-        _7 = <RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::spec_next(_8) -> [return: bb9, unwind: bb7]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
+        _6 = &mut _5;                    // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
+        _7 = <RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::spec_next(_6) -> [return: bb2, unwind: bb8]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL
                                          // + literal: Const { ty: for<'a> fn(&'a mut RangeInclusive<u32>) -> Option<<RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::Item> {<RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::spec_next}, val: Value(<ZST>) }
     }
 
     bb2: {
-        _10 = ((_7 as Some).0: u32);     // scope 1 at $DIR/range_iter.rs:+1:9: +1:10
-        StorageLive(_11);                // scope 2 at $DIR/range_iter.rs:+2:9: +2:10
-        _11 = &_3;                       // scope 2 at $DIR/range_iter.rs:+2:9: +2:10
-        StorageLive(_12);                // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
-        _12 = (_10,);                    // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
-        _6 = <impl Fn(u32) as Fn<(u32,)>>::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
+        _8 = discriminant(_7);           // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
+        switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb7]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
+    }
+
+    bb3: {
+        StorageDead(_7);                 // scope 1 at $DIR/range_iter.rs:+3:5: +3:6
+        StorageDead(_5);                 // scope 0 at $DIR/range_iter.rs:+3:5: +3:6
+        drop(_3) -> bb4;                 // scope 0 at $DIR/range_iter.rs:+4:1: +4:2
+    }
+
+    bb4: {
+        return;                          // scope 0 at $DIR/range_iter.rs:+4:2: +4:2
+    }
+
+    bb5: {
+        _9 = ((_7 as Some).0: u32);      // scope 1 at $DIR/range_iter.rs:+1:9: +1:10
+        StorageLive(_10);                // scope 2 at $DIR/range_iter.rs:+2:9: +2:10
+        _10 = &_3;                       // scope 2 at $DIR/range_iter.rs:+2:9: +2:10
+        StorageLive(_11);                // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
+        _11 = (_9,);                     // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
+        _12 = <impl Fn(u32) as Fn<(u32,)>>::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13
                                          // mir::Constant
                                          // + span: $DIR/range_iter.rs:29:9: 29:10
                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> <impl Fn(u32) as FnOnce<(u32,)>>::Output {<impl Fn(u32) as Fn<(u32,)>>::call}, val: Value(<ZST>) }
     }
 
-    bb3: {
-        unreachable;                     // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
-    }
-
-    bb4: {
-        StorageDead(_7);                 // scope 1 at $DIR/range_iter.rs:+3:5: +3:6
-        StorageDead(_5);                 // scope 0 at $DIR/range_iter.rs:+3:5: +3:6
-        drop(_3) -> bb6;                 // scope 0 at $DIR/range_iter.rs:+4:1: +4:2
-    }
-
-    bb5: {
-        StorageDead(_12);                // scope 2 at $DIR/range_iter.rs:+2:12: +2:13
+    bb6: {
         StorageDead(_11);                // scope 2 at $DIR/range_iter.rs:+2:12: +2:13
+        StorageDead(_10);                // scope 2 at $DIR/range_iter.rs:+2:12: +2:13
         StorageDead(_7);                 // scope 1 at $DIR/range_iter.rs:+3:5: +3:6
         goto -> bb1;                     // scope 1 at $DIR/range_iter.rs:+1:5: +3:6
     }
 
-    bb6: {
-        return;                          // scope 0 at $DIR/range_iter.rs:+4:2: +4:2
-    }
-
-    bb7 (cleanup): {
-        drop(_3) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2
+    bb7: {
+        unreachable;                     // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
     }
 
     bb8 (cleanup): {
-        resume;                          // scope 0 at $DIR/range_iter.rs:+0:1: +4:2
+        drop(_3) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2
     }
 
-    bb9: {
-        _9 = discriminant(_7);           // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
-        switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25
+    bb9 (cleanup): {
+        resume;                          // scope 0 at $DIR/range_iter.rs:+0:1: +4:2
     }
 }
diff --git a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir
index 986ab35..089b0c2 100644
--- a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir
@@ -3,18 +3,18 @@
 fn ezmap(_1: Option<i32>) -> Option<i32> {
     debug x => _1;                       // in scope 0 at $DIR/simple_option_map.rs:+0:14: +0:15
     let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map.rs:+0:33: +0:44
-    let mut _6: i32;                     // in scope 0 at $DIR/simple_option_map.rs:11:25: 11:29
+    let mut _5: i32;                     // in scope 0 at $DIR/simple_option_map.rs:11:25: 11:29
     scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map.rs:18:12: 18:15]>) { // at $DIR/simple_option_map.rs:18:5: 18:22
         debug slf => _1;                 // in scope 1 at $DIR/simple_option_map.rs:6:17: 6:20
         debug f => const ZeroSized: [closure@$DIR/simple_option_map.rs:18:12: 18:15]; // in scope 1 at $DIR/simple_option_map.rs:6:33: 6:34
         let mut _2: isize;               // in scope 1 at $DIR/simple_option_map.rs:11:9: 11:16
         let _3: i32;                     // in scope 1 at $DIR/simple_option_map.rs:11:14: 11:15
-        let mut _4: i32;                 // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29
-        let mut _5: (i32,);              // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29
+        let mut _4: (i32,);              // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29
+        let mut _6: i32;                 // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29
         scope 2 {
             debug x => _3;               // in scope 2 at $DIR/simple_option_map.rs:11:14: 11:15
             scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map.rs:11:25: 11:29
-                debug n => _6;           // in scope 3 at $DIR/simple_option_map.rs:+1:13: +1:14
+                debug n => _5;           // in scope 3 at $DIR/simple_option_map.rs:+1:13: +1:14
             }
         }
     }
@@ -22,35 +22,35 @@
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/simple_option_map.rs:+1:5: +1:22
         _2 = discriminant(_1);           // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14
-        switchInt(move _2) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map.rs:10:5: 10:14
+        switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; // scope 1 at $DIR/simple_option_map.rs:10:5: 10:14
     }
 
     bb1: {
         _0 = Option::<i32>::None;        // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21
-        goto -> bb4;                     // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21
+        goto -> bb3;                     // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21
     }
 
     bb2: {
-        unreachable;                     // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14
+        _3 = ((_1 as Some).0: i32);      // scope 1 at $DIR/simple_option_map.rs:11:14: 11:15
+        StorageLive(_6);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
+        StorageLive(_4);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
+        _4 = (move _3,);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
+        StorageLive(_5);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
+        _5 = move (_4.0: i32);           // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
+        _6 = Add(_5, const 1_i32);       // scope 3 at $DIR/simple_option_map.rs:+1:16: +1:21
+        StorageDead(_5);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
+        StorageDead(_4);                 // scope 2 at $DIR/simple_option_map.rs:11:28: 11:29
+        _0 = Option::<i32>::Some(move _6); // scope 2 at $DIR/simple_option_map.rs:11:20: 11:30
+        StorageDead(_6);                 // scope 2 at $DIR/simple_option_map.rs:11:29: 11:30
+        goto -> bb3;                     // scope 1 at $DIR/simple_option_map.rs:14:1: 14:2
     }
 
     bb3: {
-        _3 = ((_1 as Some).0: i32);      // scope 1 at $DIR/simple_option_map.rs:11:14: 11:15
-        StorageLive(_4);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
-        StorageLive(_5);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
-        _5 = (move _3,);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
-        StorageLive(_6);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
-        _6 = move (_5.0: i32);           // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
-        _4 = Add(_6, const 1_i32);       // scope 3 at $DIR/simple_option_map.rs:+1:16: +1:21
-        StorageDead(_6);                 // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29
-        StorageDead(_5);                 // scope 2 at $DIR/simple_option_map.rs:11:28: 11:29
-        _0 = Option::<i32>::Some(move _4); // scope 2 at $DIR/simple_option_map.rs:11:20: 11:30
-        StorageDead(_4);                 // scope 2 at $DIR/simple_option_map.rs:11:29: 11:30
-        goto -> bb4;                     // scope 1 at $DIR/simple_option_map.rs:14:1: 14:2
+        StorageDead(_3);                 // scope 0 at $DIR/simple_option_map.rs:+1:5: +1:22
+        return;                          // scope 0 at $DIR/simple_option_map.rs:+2:2: +2:2
     }
 
     bb4: {
-        StorageDead(_3);                 // scope 0 at $DIR/simple_option_map.rs:+1:5: +1:22
-        return;                          // scope 0 at $DIR/simple_option_map.rs:+2:2: +2:2
+        unreachable;                     // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir
index 715a1e3..b05d44f 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir
@@ -10,17 +10,17 @@
         scope 2 (inlined <usize as SliceIndex<[u32]>>::get_mut) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL
             debug self => _2;            // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
             debug slice => _1;           // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-            let mut _3: bool;            // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+            let mut _3: &[u32];          // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
             let mut _4: usize;           // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-            let mut _5: &[u32];          // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-            let mut _6: &mut u32;        // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-            let mut _7: *mut u32;        // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-            let mut _8: *mut [u32];      // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+            let mut _5: bool;            // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+            let mut _6: *mut [u32];      // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+            let mut _8: *mut u32;        // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+            let mut _9: &mut u32;        // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
             scope 3 {
                 scope 4 (inlined <usize as SliceIndex<[u32]>>::get_unchecked_mut) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL
                     debug self => _2;    // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                    debug slice => _8;   // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                    let mut _9: *mut u32; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                    debug slice => _6;   // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                    let mut _7: *mut u32; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL
                     let mut _10: usize;  // in scope 4 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                     let mut _11: *mut [u32]; // in scope 4 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                     scope 5 {
@@ -40,10 +40,10 @@
                                 }
                             }
                             scope 11 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                                debug self => _8; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                debug self => _6; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                             }
                             scope 12 (inlined ptr::mut_ptr::<impl *mut u32>::add) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                                debug self => _9; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                debug self => _7; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                 debug count => _2; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                 scope 13 {
                                 }
@@ -56,40 +56,19 @@
     }
 
     bb0: {
-        StorageLive(_6);                 // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_9);                 // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _5 = &(*_1);                     // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _4 = Len((*_5));                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _3 = Lt(_2, move _4);            // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _3 = &(*_1);                     // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _4 = Len((*_3));                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _5 = Lt(_2, move _4);            // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        switchInt(move _3) -> [0: bb2, otherwise: bb1]; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
     }
 
     bb1: {
-        StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _8 = &raw mut (*_1);             // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_11);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_12);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_9);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _9 = _8 as *mut u32 (PtrToPtr);  // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        _7 = Offset(_9, _2);             // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageDead(_9);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_12);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _6 = &mut (*_7);                 // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _0 = Option::<&mut u32>::Some(_6); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_7);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        goto -> bb3;                     // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-    }
-
-    bb2: {
         _0 = const Option::<&mut u32>::None; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
                                          // mir::Constant
                                          // + span: no-location
@@ -97,9 +76,30 @@
         goto -> bb3;                     // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
     }
 
+    bb2: {
+        StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_6);                 // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _6 = &raw mut (*_1);             // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_11);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_12);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_7);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _7 = _6 as *mut u32 (PtrToPtr);  // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+        _8 = Offset(_7, _2);             // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+        StorageDead(_7);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_12);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_6);                 // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _9 = &mut (*_8);                 // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _0 = Option::<&mut u32>::Some(_9); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_8);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        goto -> bb3;                     // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+    }
+
     bb3: {
-        StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_6);                 // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_9);                 // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         return;                          // scope 0 at $DIR/slice_index.rs:+2:2: +2:2
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir
index 7a10b92..6d9ec5d 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir
@@ -8,61 +8,61 @@
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         debug index => _2;               // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         let mut _3: *mut [u32];          // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        let mut _4: *mut [u32];          // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        let mut _15: *mut [u32];         // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         scope 2 {
             scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL
                 debug self => _2;        // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                debug slice => _4;       // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                let _5: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                let mut _7: usize;       // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                debug slice => _3;       // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                let mut _4: usize;       // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                let mut _5: usize;       // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                let mut _7: *mut u32;    // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
                 let mut _8: usize;       // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
                 let mut _9: *mut u32;    // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                let mut _10: *mut u32;   // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                let mut _11: usize;      // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                let mut _12: usize;      // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                let mut _13: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-                let mut _14: *mut [u32]; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+                let mut _10: usize;      // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                let _16: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                let mut _17: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+                let mut _18: *mut [u32]; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                 scope 4 {
-                    debug this => _5;    // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+                    debug this => _16;   // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL
                     scope 5 {
                         let _6: usize;   // in scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
                         scope 6 {
                             debug new_len => _6; // in scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
                             scope 11 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                                debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                debug self => _3; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                             }
                             scope 12 (inlined ptr::mut_ptr::<impl *mut u32>::add) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                                debug self => _10; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-                                debug count => _11; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                debug self => _7; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                debug count => _8; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                 scope 13 {
                                 }
                             }
                             scope 14 (inlined slice_from_raw_parts_mut::<u32>) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL
                                 debug data => _9; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                debug len => _12; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                let mut _16: *mut (); // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+                                debug len => _10; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+                                let mut _11: *mut (); // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                 scope 15 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { // at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                     debug self => _9; // in scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                 }
                                 scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { // at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                    debug data_address => _16; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-                                    debug metadata => _12; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-                                    let mut _17: std::ptr::metadata::PtrRepr<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-                                    let mut _18: std::ptr::metadata::PtrComponents<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-                                    let mut _19: *const (); // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+                                    debug data_address => _11; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+                                    debug metadata => _10; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+                                    let mut _12: *const (); // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+                                    let mut _13: std::ptr::metadata::PtrComponents<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+                                    let mut _14: std::ptr::metadata::PtrRepr<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
                                     scope 17 {
                                     }
                                 }
                             }
                         }
                         scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-                            debug this => _13; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-                            debug slice => _14; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+                            debug this => _17; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+                            debug slice => _18; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                             scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL
-                                debug self => _14; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-                                let mut _15: *const [u32]; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                debug self => _18; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                let mut _19: *const [u32]; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                 scope 9 (inlined std::ptr::metadata::<[u32]>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-                                    debug ptr => _15; // in scope 9 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+                                    debug ptr => _19; // in scope 9 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
                                     scope 10 {
                                     }
                                 }
@@ -75,60 +75,60 @@
     }
 
     bb0: {
-        StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        _4 = &raw mut (*_1);             // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_13);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_14);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         StorageLive(_15);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        _3 = &raw mut (*_1);             // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_16);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_17);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_18);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_19);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         StorageLive(_6);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_7);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _7 = (_2.1: usize);              // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_8);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _8 = (_2.0: usize);              // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _6 = unchecked_sub::<usize>(move _7, move _8) -> [return: bb1, unwind unreachable]; // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_4);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _4 = (_2.1: usize);              // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_5);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _5 = (_2.0: usize);              // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _6 = unchecked_sub::<usize>(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/slice/index.rs:LL:COL
                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize, usize) -> usize {unchecked_sub::<usize>}, val: Value(<ZST>) }
     }
 
     bb1: {
-        StorageDead(_8);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_7);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_5);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_4);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         StorageLive(_9);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_7);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _7 = _3 as *mut u32 (PtrToPtr);  // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+        StorageLive(_8);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _8 = (_2.0: usize);              // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _9 = Offset(_7, _8);             // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+        StorageDead(_8);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageDead(_7);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         StorageLive(_10);                // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _10 = _4 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageLive(_11);                // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _11 = (_2.0: usize);             // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _9 = Offset(_10, _11);           // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageDead(_11);                // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        _10 = _6;                        // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
+        StorageLive(_11);                // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        _11 = _9 as *mut () (PtrToPtr);  // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+        StorageLive(_14);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        StorageLive(_13);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        StorageLive(_12);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        _12 = _11 as *const () (Pointer(MutToConstPointer)); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        _13 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _12, metadata: _10 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        StorageDead(_12);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        _14 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _13 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        StorageDead(_13);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        _15 = (_14.1: *mut [u32]);       // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        StorageDead(_14);                // scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
+        StorageDead(_11);                // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
         StorageDead(_10);                // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_12);                // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        _12 = _6;                        // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageLive(_16);                // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-        _16 = _9 as *mut () (PtrToPtr);  // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageLive(_17);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        StorageLive(_18);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        StorageLive(_19);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        _19 = _16 as *const () (Pointer(MutToConstPointer)); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        _18 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _19, metadata: _12 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        StorageDead(_19);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        _17 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _18 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        StorageDead(_18);                // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        _3 = (_17.1: *mut [u32]);        // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        StorageDead(_17);                // scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
-        StorageDead(_16);                // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-        StorageDead(_12);                // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         StorageDead(_9);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         StorageDead(_6);                 // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL
-        StorageDead(_15);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageDead(_14);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageDead(_13);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        _0 = &mut (*_3);                 // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageDead(_3);                 // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_19);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_18);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_17);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_16);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        _0 = &mut (*_15);                // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_15);                // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         return;                          // scope 0 at $DIR/slice_index.rs:+2:2: +2:2
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir
index 0da7e55..0cf1d68 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir
@@ -4,41 +4,41 @@
     debug slice => _1;                   // in scope 0 at $DIR/slice_iter.rs:+0:28: +0:33
     debug f => _2;                       // in scope 0 at $DIR/slice_iter.rs:+0:44: +0:45
     let mut _0: ();                      // return place in scope 0 at $DIR/slice_iter.rs:+0:60: +0:60
-    let mut _3: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-    let mut _4: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-    let _5: ();                          // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-    let mut _6: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-    let mut _7: &mut std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-    let mut _8: isize;                   // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6
-    let mut _10: &impl Fn(&T);           // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10
-    let mut _11: (&T,);                  // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13
+    let mut _13: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
+    let mut _14: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
+    let mut _15: &mut std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
+    let mut _16: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
+    let mut _17: isize;                  // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6
+    let mut _19: &impl Fn(&T);           // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10
+    let mut _20: (&T,);                  // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13
+    let _21: ();                         // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
     scope 1 {
-        debug iter => _4;                // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
-        let _9: &T;                      // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10
+        debug iter => _14;               // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
+        let _18: &T;                     // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10
         scope 2 {
-            debug x => _9;               // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10
+            debug x => _18;              // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) { // at $DIR/slice_iter.rs:28:20: 28:26
         debug self => _1;                // in scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         scope 4 (inlined std::slice::Iter::<'_, T>::new) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL
             debug slice => _1;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let _12: *const T;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _14: bool;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _15: usize;          // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _16: usize;          // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _17: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _18: *mut T;         // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _19: *const T;       // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let _4: *const T;            // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _5: bool;            // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _6: usize;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _8: usize;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _9: *mut T;          // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _11: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _12: *const T;       // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
             scope 5 {
-                debug ptr => _12;        // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+                debug ptr => _4;         // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                 scope 6 {
-                    let _13: *const T;   // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+                    let _7: *const T;    // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                     scope 7 {
-                        debug end => _13; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+                        debug end => _7; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                         scope 13 (inlined NonNull::<T>::new_unchecked) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-                            debug ptr => _18; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
-                            let mut _21: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+                            debug ptr => _9; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+                            let mut _10: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
                             let mut _22: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                             scope 14 {
                                 scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
@@ -65,13 +65,13 @@
                         }
                     }
                     scope 9 (inlined invalid::<T>) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-                        debug addr => _15; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+                        debug addr => _8; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                         scope 10 {
                         }
                     }
                     scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-                        debug self => _12; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-                        debug count => _16; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+                        debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+                        debug count => _6; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
                         scope 12 {
                         }
                     }
@@ -79,125 +79,125 @@
             }
             scope 8 (inlined core::slice::<impl [T]>::as_ptr) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                 debug self => _1;        // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-                let mut _20: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+                let mut _3: *const [T];  // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
             }
         }
     }
     scope 22 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:28:14: 28:26
-        debug self => _3;                // in scope 22 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+        debug self => _13;               // in scope 22 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
     }
 
     bb0: {
-        StorageLive(_12);                // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_20);                // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        _20 = &raw const (*_1);          // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        _12 = move _20 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageDead(_20);                // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_13);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_14);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _14 = const _;                   // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        switchInt(move _14) -> [0: bb11, otherwise: bb10]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_4);                 // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_3);                 // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        _3 = &raw const (*_1);           // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        _4 = move _3 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_3);                 // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_7);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_5);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _5 = const _;                    // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
     }
 
     bb1: {
-        StorageLive(_6);                 // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
-        _7 = &mut _4;                    // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
-        _6 = <std::slice::Iter<'_, T> as Iterator>::next(_7) -> [return: bb2, unwind: bb8]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
+        StorageLive(_6);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _6 = Len((*_1));                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _7 = Offset(_4, _6);             // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+        StorageDead(_6);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        goto -> bb3;                     // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+    }
+
+    bb2: {
+        StorageLive(_8);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _8 = Len((*_1));                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _7 = _8 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        StorageDead(_8);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        goto -> bb3;                     // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+    }
+
+    bb3: {
+        StorageDead(_5);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_11);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_9);                 // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _9 = _4 as *mut T (PtrToPtr);    // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_10);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_22);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_23);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _10 = _9 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+        _11 = NonNull::<T> { pointer: _10 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+        StorageDead(_23);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_22);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_10);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_9);                 // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_12);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _12 = _7;                        // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: no-location
+                                         // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) }
+                                         // adt
+                                         // + user_ty: UserType(1)
+        StorageDead(_12);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_11);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_7);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_4);                 // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_14);                // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
+        _14 = move _13;                  // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
+        goto -> bb4;                     // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6
+    }
+
+    bb4: {
+        StorageLive(_16);                // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
+        _15 = &mut _14;                  // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
+        _16 = <std::slice::Iter<'_, T> as Iterator>::next(_15) -> [return: bb5, unwind: bb11]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
                                          // mir::Constant
                                          // + span: $DIR/slice_iter.rs:28:14: 28:26
                                          // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as Iterator>::next}, val: Value(<ZST>) }
     }
 
-    bb2: {
-        _8 = discriminant(_6);           // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
-        switchInt(move _8) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
-    }
-
-    bb3: {
-        _9 = ((_6 as Some).0: &T);       // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10
-        StorageLive(_10);                // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10
-        _10 = &_2;                       // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10
-        StorageLive(_11);                // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
-        _11 = (_9,);                     // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
-        _5 = <impl Fn(&T) as Fn<(&T,)>>::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
-                                         // mir::Constant
-                                         // + span: $DIR/slice_iter.rs:29:9: 29:10
-                                         // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) }
-    }
-
-    bb4: {
-        unreachable;                     // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
-    }
-
     bb5: {
-        StorageDead(_6);                 // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6
-        StorageDead(_4);                 // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6
-        drop(_2) -> bb7;                 // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2
+        _17 = discriminant(_16);         // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
+        switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
     }
 
     bb6: {
-        StorageDead(_11);                // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13
-        StorageDead(_10);                // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13
-        StorageDead(_6);                 // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6
-        goto -> bb1;                     // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6
+        StorageDead(_16);                // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6
+        StorageDead(_14);                // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6
+        drop(_2) -> bb7;                 // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2
     }
 
     bb7: {
         return;                          // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2
     }
 
-    bb8 (cleanup): {
-        drop(_2) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2
+    bb8: {
+        _18 = ((_16 as Some).0: &T);     // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10
+        StorageLive(_19);                // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10
+        _19 = &_2;                       // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10
+        StorageLive(_20);                // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
+        _20 = (_18,);                    // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
+        _21 = <impl Fn(&T) as Fn<(&T,)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
+                                         // mir::Constant
+                                         // + span: $DIR/slice_iter.rs:29:9: 29:10
+                                         // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) }
     }
 
-    bb9 (cleanup): {
-        resume;                          // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2
+    bb9: {
+        StorageDead(_20);                // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13
+        StorageDead(_19);                // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13
+        StorageDead(_16);                // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6
+        goto -> bb4;                     // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6
     }
 
     bb10: {
-        StorageLive(_15);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _15 = Len((*_1));                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _13 = _15 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-        StorageDead(_15);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        goto -> bb12;                    // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        unreachable;                     // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26
     }
 
-    bb11: {
-        StorageLive(_16);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _16 = Len((*_1));                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _13 = Offset(_12, _16);          // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-        StorageDead(_16);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        goto -> bb12;                    // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+    bb11 (cleanup): {
+        drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2
     }
 
-    bb12: {
-        StorageDead(_14);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_17);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_18);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _18 = _12 as *mut T (PtrToPtr);  // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_21);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_22);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_23);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _21 = _18 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
-        _17 = NonNull::<T> { pointer: _21 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
-        StorageDead(_23);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_22);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_21);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_18);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_19);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _19 = _13;                       // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _3 = std::slice::Iter::<'_, T> { ptr: move _17, end: move _19, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-                                         // mir::Constant
-                                         // + span: no-location
-                                         // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) }
-                                         // adt
-                                         // + user_ty: UserType(1)
-        StorageDead(_19);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_17);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_13);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_12);                // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_4);                 // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-        _4 = move _3;                    // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-        goto -> bb1;                     // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6
+    bb12 (cleanup): {
+        resume;                          // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir
index 45b41b5..4fde50c 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir
@@ -4,61 +4,61 @@
     debug slice => _1;                   // in scope 0 at $DIR/slice_iter.rs:+0:28: +0:33
     debug f => _2;                       // in scope 0 at $DIR/slice_iter.rs:+0:44: +0:45
     let mut _0: ();                      // return place in scope 0 at $DIR/slice_iter.rs:+0:60: +0:60
-    let mut _3: std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
-    let mut _4: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-    let mut _5: std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
-    let _6: ();                          // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
-    let mut _7: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
-    let mut _8: &mut std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
-    let mut _9: isize;                   // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6
-    let mut _11: &impl Fn(&T);           // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10
-    let mut _12: (&T,);                  // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13
+    let mut _13: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
+    let mut _14: std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
+    let mut _15: std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
+    let mut _16: &mut std::iter::Rev<std::slice::Iter<'_, T>>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
+    let mut _18: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
+    let mut _19: isize;                  // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6
+    let mut _21: &impl Fn(&T);           // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10
+    let mut _22: (&T,);                  // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13
+    let _23: ();                         // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
     scope 1 {
-        debug iter => _5;                // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
-        let _10: &T;                     // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10
+        debug iter => _15;               // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
+        let _20: &T;                     // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10
         scope 2 {
-            debug x => _10;              // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10
+            debug x => _20;              // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10
         }
         scope 25 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) { // at $DIR/slice_iter.rs:35:14: 35:32
-            debug self => _8;            // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
-            let mut _25: &mut std::slice::Iter<'_, T>; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+            debug self => _16;           // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+            let mut _17: &mut std::slice::Iter<'_, T>; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) { // at $DIR/slice_iter.rs:35:20: 35:26
         debug self => _1;                // in scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
         scope 4 (inlined std::slice::Iter::<'_, T>::new) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL
             debug slice => _1;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let _13: *const T;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _15: bool;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _16: usize;          // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _17: usize;          // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _18: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _19: *mut T;         // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-            let mut _20: *const T;       // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let _4: *const T;            // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _5: bool;            // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _6: usize;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _8: usize;           // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _9: *mut T;          // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _11: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+            let mut _12: *const T;       // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
             scope 5 {
-                debug ptr => _13;        // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+                debug ptr => _4;         // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                 scope 6 {
-                    let _14: *const T;   // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+                    let _7: *const T;    // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                     scope 7 {
-                        debug end => _14; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+                        debug end => _7; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                         scope 13 (inlined NonNull::<T>::new_unchecked) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-                            debug ptr => _19; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
-                            let mut _22: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
-                            let mut _23: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+                            debug ptr => _9; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+                            let mut _10: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+                            let mut _24: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                             scope 14 {
                                 scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-                                    debug ptr => _23; // in scope 15 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+                                    debug ptr => _24; // in scope 15 at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                                     scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { // at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
-                                        debug self => _23; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-                                        let mut _24: *mut u8; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                        debug self => _24; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                        let mut _25: *mut u8; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                         scope 17 {
                                             scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-                                                debug ptr => _24; // in scope 18 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                                debug ptr => _25; // in scope 18 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                                 scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-                                                    debug self => _24; // in scope 19 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                                    debug self => _25; // in scope 19 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                                     scope 20 {
                                                         scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-                                                            debug self => _24; // in scope 21 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+                                                            debug self => _25; // in scope 21 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
                                                         }
                                                     }
                                                 }
@@ -70,13 +70,13 @@
                         }
                     }
                     scope 9 (inlined invalid::<T>) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-                        debug addr => _16; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+                        debug addr => _8; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                         scope 10 {
                         }
                     }
                     scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-                        debug self => _13; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-                        debug count => _17; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+                        debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+                        debug count => _6; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
                         scope 12 {
                         }
                     }
@@ -84,137 +84,137 @@
             }
             scope 8 (inlined core::slice::<impl [T]>::as_ptr) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                 debug self => _1;        // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-                let mut _21: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+                let mut _3: *const [T];  // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
             }
         }
     }
     scope 22 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) { // at $DIR/slice_iter.rs:35:27: 35:32
-        debug self => _4;                // in scope 22 at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+        debug self => _13;               // in scope 22 at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
         scope 23 (inlined Rev::<std::slice::Iter<'_, T>>::new) { // at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
-            debug iter => _4;            // in scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+            debug iter => _13;           // in scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
         }
     }
     scope 24 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:35:14: 35:32
-        debug self => _3;                // in scope 24 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+        debug self => _14;               // in scope 24 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
     }
 
     bb0: {
-        StorageLive(_4);                 // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
-        StorageLive(_13);                // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_21);                // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        _21 = &raw const (*_1);          // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        _13 = move _21 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageDead(_21);                // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        StorageLive(_14);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_15);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _15 = const _;                   // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        switchInt(move _15) -> [0: bb10, otherwise: bb9]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_13);                // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26
+        StorageLive(_4);                 // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_3);                 // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        _3 = &raw const (*_1);           // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        _4 = move _3 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageDead(_3);                 // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        StorageLive(_7);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_5);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _5 = const _;                    // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
     }
 
     bb1: {
-        StorageLive(_7);                 // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
-        _8 = &mut _5;                    // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
-        StorageLive(_25);                // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
-        _25 = &mut ((*_8).0: std::slice::Iter<'_, T>); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
-        _7 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _25) -> [return: bb12, unwind: bb7]; // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
-                                         // mir::Constant
-                                         // + span: $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
-                                         // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back}, val: Value(<ZST>) }
+        StorageLive(_6);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _6 = Len((*_1));                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _7 = Offset(_4, _6);             // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+        StorageDead(_6);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        goto -> bb3;                     // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
     }
 
     bb2: {
-        _10 = ((_7 as Some).0: &T);      // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10
-        StorageLive(_11);                // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10
-        _11 = &_2;                       // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10
-        StorageLive(_12);                // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
-        _12 = (_10,);                    // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
-        _6 = <impl Fn(&T) as Fn<(&T,)>>::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
-                                         // mir::Constant
-                                         // + span: $DIR/slice_iter.rs:36:9: 36:10
-                                         // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) }
+        StorageLive(_8);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _8 = Len((*_1));                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _7 = _8 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        StorageDead(_8);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        goto -> bb3;                     // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
     }
 
     bb3: {
-        unreachable;                     // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
-    }
-
-    bb4: {
-        StorageDead(_7);                 // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6
-        StorageDead(_5);                 // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6
-        drop(_2) -> bb6;                 // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2
-    }
-
-    bb5: {
-        StorageDead(_12);                // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13
-        StorageDead(_11);                // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13
-        StorageDead(_7);                 // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6
-        goto -> bb1;                     // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6
-    }
-
-    bb6: {
-        return;                          // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2
-    }
-
-    bb7 (cleanup): {
-        drop(_2) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2
-    }
-
-    bb8 (cleanup): {
-        resume;                          // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2
-    }
-
-    bb9: {
-        StorageLive(_16);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _16 = Len((*_1));                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _14 = _16 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-        StorageDead(_16);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        goto -> bb11;                    // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-    }
-
-    bb10: {
-        StorageLive(_17);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _17 = Len((*_1));                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _14 = Offset(_13, _17);          // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-        StorageDead(_17);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        goto -> bb11;                    // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-    }
-
-    bb11: {
-        StorageDead(_15);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_18);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_19);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _19 = _13 as *mut T (PtrToPtr);  // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_22);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_23);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_5);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_11);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_9);                 // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _9 = _4 as *mut T (PtrToPtr);    // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_10);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
         StorageLive(_24);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _22 = _19 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
-        _18 = NonNull::<T> { pointer: _22 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+        StorageLive(_25);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _10 = _9 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+        _11 = NonNull::<T> { pointer: _10 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL
+        StorageDead(_25);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
         StorageDead(_24);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_23);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_22);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_19);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageLive(_20);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _20 = _14;                       // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        _4 = std::slice::Iter::<'_, T> { ptr: move _18, end: move _20, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_10);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_9);                 // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageLive(_12);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _12 = _7;                        // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        _13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
                                          // mir::Constant
                                          // + span: no-location
                                          // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) }
                                          // adt
                                          // + user_ty: UserType(1)
-        StorageDead(_20);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_18);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_14);                // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
-        StorageDead(_13);                // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
-        _3 = Rev::<std::slice::Iter<'_, T>> { iter: move _4 }; // scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
-        StorageDead(_4);                 // scope 0 at $DIR/slice_iter.rs:+1:31: +1:32
-        StorageLive(_5);                 // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
-        _5 = move _3;                    // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
-        goto -> bb1;                     // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6
+        StorageDead(_12);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_11);                // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_7);                 // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL
+        StorageDead(_4);                 // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL
+        _14 = Rev::<std::slice::Iter<'_, T>> { iter: move _13 }; // scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+        StorageDead(_13);                // scope 0 at $DIR/slice_iter.rs:+1:31: +1:32
+        StorageLive(_15);                // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
+        _15 = move _14;                  // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32
+        goto -> bb4;                     // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6
     }
 
-    bb12: {
-        StorageDead(_25);                // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
-        _9 = discriminant(_7);           // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
-        switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
+    bb4: {
+        StorageLive(_18);                // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
+        _16 = &mut _15;                  // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
+        StorageLive(_17);                // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+        _17 = &mut ((*_16).0: std::slice::Iter<'_, T>); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+        _18 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _17) -> [return: bb5, unwind: bb11]; // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+                                         // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back}, val: Value(<ZST>) }
+    }
+
+    bb5: {
+        StorageDead(_17);                // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL
+        _19 = discriminant(_18);         // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
+        switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
+    }
+
+    bb6: {
+        StorageDead(_18);                // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6
+        StorageDead(_15);                // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6
+        drop(_2) -> bb7;                 // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2
+    }
+
+    bb7: {
+        return;                          // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2
+    }
+
+    bb8: {
+        _20 = ((_18 as Some).0: &T);     // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10
+        StorageLive(_21);                // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10
+        _21 = &_2;                       // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10
+        StorageLive(_22);                // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
+        _22 = (_20,);                    // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
+        _23 = <impl Fn(&T) as Fn<(&T,)>>::call(move _21, move _22) -> [return: bb9, unwind: bb11]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13
+                                         // mir::Constant
+                                         // + span: $DIR/slice_iter.rs:36:9: 36:10
+                                         // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) }
+    }
+
+    bb9: {
+        StorageDead(_22);                // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13
+        StorageDead(_21);                // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13
+        StorageDead(_18);                // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6
+        goto -> bb4;                     // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6
+    }
+
+    bb10: {
+        unreachable;                     // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32
+    }
+
+    bb11 (cleanup): {
+        drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2
+    }
+
+    bb12 (cleanup): {
+        resume;                          // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2
     }
 }
diff --git a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir
index 53971b4..c3f8745 100644
--- a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir
@@ -3,15 +3,15 @@
 fn new(_1: Result<T, E>) -> Result<T, E> {
     debug x => _1;                       // in scope 0 at $DIR/try_identity.rs:+0:14: +0:15
     let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity.rs:+0:34: +0:46
-    let mut _2: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity.rs:+2:15: +7:10
-    let mut _3: isize;                   // in scope 0 at $DIR/try_identity.rs:+4:17: +4:22
-    let _4: T;                           // in scope 0 at $DIR/try_identity.rs:+4:20: +4:21
+    let mut _2: isize;                   // in scope 0 at $DIR/try_identity.rs:+4:17: +4:22
+    let _3: T;                           // in scope 0 at $DIR/try_identity.rs:+4:20: +4:21
+    let mut _4: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity.rs:+2:15: +7:10
     let _5: E;                           // in scope 0 at $DIR/try_identity.rs:+5:21: +5:22
     let mut _6: isize;                   // in scope 0 at $DIR/try_identity.rs:+8:13: +8:37
     let _7: T;                           // in scope 0 at $DIR/try_identity.rs:+8:35: +8:36
     let _8: E;                           // in scope 0 at $DIR/try_identity.rs:+9:32: +9:33
     scope 1 {
-        debug v => _4;                   // in scope 1 at $DIR/try_identity.rs:+4:20: +4:21
+        debug v => _3;                   // in scope 1 at $DIR/try_identity.rs:+4:20: +4:21
     }
     scope 2 {
         debug e => _5;                   // in scope 2 at $DIR/try_identity.rs:+5:21: +5:22
@@ -24,47 +24,47 @@
     }
 
     bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/try_identity.rs:+2:15: +7:10
-        _3 = discriminant(_1);           // scope 0 at $DIR/try_identity.rs:+3:19: +3:20
-        switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+3:13: +3:20
+        StorageLive(_4);                 // scope 0 at $DIR/try_identity.rs:+2:15: +7:10
+        _2 = discriminant(_1);           // scope 0 at $DIR/try_identity.rs:+3:19: +3:20
+        switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb7]; // scope 0 at $DIR/try_identity.rs:+3:13: +3:20
     }
 
     bb1: {
-        _5 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity.rs:+5:21: +5:22
-        _2 = ControlFlow::<E, T>::Break(move _5); // scope 2 at $DIR/try_identity.rs:+5:27: +5:48
-        goto -> bb4;                     // scope 0 at $DIR/try_identity.rs:+5:47: +5:48
+        _3 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity.rs:+4:20: +4:21
+        _4 = ControlFlow::<E, T>::Continue(move _3); // scope 1 at $DIR/try_identity.rs:+4:26: +4:50
+        goto -> bb3;                     // scope 0 at $DIR/try_identity.rs:+4:49: +4:50
     }
 
     bb2: {
-        unreachable;                     // scope 0 at $DIR/try_identity.rs:+3:19: +3:20
+        _5 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity.rs:+5:21: +5:22
+        _4 = ControlFlow::<E, T>::Break(move _5); // scope 2 at $DIR/try_identity.rs:+5:27: +5:48
+        goto -> bb3;                     // scope 0 at $DIR/try_identity.rs:+5:47: +5:48
     }
 
     bb3: {
-        _4 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity.rs:+4:20: +4:21
-        _2 = ControlFlow::<E, T>::Continue(move _4); // scope 1 at $DIR/try_identity.rs:+4:26: +4:50
-        goto -> bb4;                     // scope 0 at $DIR/try_identity.rs:+4:49: +4:50
+        _6 = discriminant(_4);           // scope 0 at $DIR/try_identity.rs:+2:15: +7:10
+        switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb7]; // scope 0 at $DIR/try_identity.rs:+2:9: +7:10
     }
 
     bb4: {
-        _6 = discriminant(_2);           // scope 0 at $DIR/try_identity.rs:+2:15: +7:10
-        switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+2:9: +7:10
+        _7 = move ((_4 as Continue).0: T); // scope 0 at $DIR/try_identity.rs:+8:35: +8:36
+        _0 = Result::<T, E>::Ok(move _7); // scope 0 at $DIR/try_identity.rs:+1:5: +11:6
+        StorageDead(_4);                 // scope 0 at $DIR/try_identity.rs:+12:1: +12:2
+        goto -> bb6;                     // scope 0 at $DIR/try_identity.rs:+12:1: +12:2
     }
 
     bb5: {
-        _8 = move ((_2 as Break).0: E);  // scope 0 at $DIR/try_identity.rs:+9:32: +9:33
+        _8 = move ((_4 as Break).0: E);  // scope 0 at $DIR/try_identity.rs:+9:32: +9:33
         _0 = Result::<T, E>::Err(move _8); // scope 4 at $DIR/try_identity.rs:+9:45: +9:51
-        StorageDead(_2);                 // scope 0 at $DIR/try_identity.rs:+12:1: +12:2
-        goto -> bb7;                     // scope 0 at $DIR/try_identity.rs:+12:1: +12:2
+        StorageDead(_4);                 // scope 0 at $DIR/try_identity.rs:+12:1: +12:2
+        goto -> bb6;                     // scope 0 at $DIR/try_identity.rs:+12:1: +12:2
     }
 
     bb6: {
-        _7 = move ((_2 as Continue).0: T); // scope 0 at $DIR/try_identity.rs:+8:35: +8:36
-        _0 = Result::<T, E>::Ok(move _7); // scope 0 at $DIR/try_identity.rs:+1:5: +11:6
-        StorageDead(_2);                 // scope 0 at $DIR/try_identity.rs:+12:1: +12:2
-        goto -> bb7;                     // scope 0 at $DIR/try_identity.rs:+12:1: +12:2
+        return;                          // scope 0 at $DIR/try_identity.rs:+12:2: +12:2
     }
 
     bb7: {
-        return;                          // scope 0 at $DIR/try_identity.rs:+12:2: +12:2
+        unreachable;                     // scope 0 at $DIR/try_identity.rs:+3:19: +3:20
     }
 }
diff --git a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir
index e217d19..0487c6c 100644
--- a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir
@@ -15,26 +15,26 @@
 
     bb0: {
         _2 = discriminant(_1);           // scope 0 at $DIR/try_identity.rs:+2:15: +2:16
-        switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+2:9: +2:16
+        switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; // scope 0 at $DIR/try_identity.rs:+2:9: +2:16
     }
 
     bb1: {
-        _4 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity.rs:+4:17: +4:18
-        _0 = Result::<T, E>::Err(move _4); // scope 2 at $DIR/try_identity.rs:+4:30: +4:36
-        goto -> bb4;                     // scope 0 at $DIR/try_identity.rs:+7:1: +7:2
+        _3 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity.rs:+3:16: +3:17
+        _0 = Result::<T, E>::Ok(move _3); // scope 0 at $DIR/try_identity.rs:+1:5: +6:6
+        goto -> bb3;                     // scope 0 at $DIR/try_identity.rs:+7:1: +7:2
     }
 
     bb2: {
-        unreachable;                     // scope 0 at $DIR/try_identity.rs:+2:15: +2:16
+        _4 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity.rs:+4:17: +4:18
+        _0 = Result::<T, E>::Err(move _4); // scope 2 at $DIR/try_identity.rs:+4:30: +4:36
+        goto -> bb3;                     // scope 0 at $DIR/try_identity.rs:+7:1: +7:2
     }
 
     bb3: {
-        _3 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity.rs:+3:16: +3:17
-        _0 = Result::<T, E>::Ok(move _3); // scope 0 at $DIR/try_identity.rs:+1:5: +6:6
-        goto -> bb4;                     // scope 0 at $DIR/try_identity.rs:+7:1: +7:2
+        return;                          // scope 0 at $DIR/try_identity.rs:+7:2: +7:2
     }
 
     bb4: {
-        return;                          // scope 0 at $DIR/try_identity.rs:+7:2: +7:2
+        unreachable;                     // scope 0 at $DIR/try_identity.rs:+2:15: +2:16
     }
 }
diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff
index f908e8d..0b9ca29 100644
--- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff
+++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff
@@ -8,8 +8,6 @@
       let mut _3: std::option::Option<T>;  // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
       let mut _4: isize;                   // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:22: +1:26
       let mut _5: isize;                   // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:13: +1:20
--     let mut _7: bool;                    // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
--     let mut _8: u8;                      // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
       scope 1 {
           debug a => _6;                   // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
           let _6: u8;                      // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
@@ -34,10 +32,9 @@
       }
   
       bb2: {
+          StorageLive(_6);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
           _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
--         StorageLive(_7);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
--         _7 = Gt(_6, const 42_u8);        // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
--         StorageDead(_7);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+4:9: +4:10
+          StorageDead(_6);                 // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+5:5: +5:6
           goto -> bb3;                     // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:5: +5:6
       }
   
diff --git a/tests/mir-opt/switch_to_self.rs b/tests/mir-opt/switch_to_self.rs
new file mode 100644
index 0000000..6678e4b
--- /dev/null
+++ b/tests/mir-opt/switch_to_self.rs
@@ -0,0 +1,21 @@
+// Test that MatchBranchSimplification doesn't ICE on a SwitchInt where
+// one of the targets is the block that the SwitchInt terminates.
+#![crate_type = "lib"]
+#![feature(core_intrinsics, custom_mir)]
+use std::intrinsics::mir::*;
+
+// EMIT_MIR switch_to_self.test.MatchBranchSimplification.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub fn test(x: bool) {
+    mir!(
+        {
+            Goto(bb0)
+        }
+        bb0 = {
+            match x { false => bb0, _ => bb1 }
+        }
+        bb1 = {
+            match x { false => bb0, _ => bb1 }
+        }
+    )
+}
diff --git a/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff b/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff
new file mode 100644
index 0000000..b0a4f9f
--- /dev/null
+++ b/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff
@@ -0,0 +1,19 @@
+- // MIR for `test` before MatchBranchSimplification
++ // MIR for `test` after MatchBranchSimplification
+  
+  fn test(_1: bool) -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/switch_to_self.rs:+0:22: +0:22
+  
+      bb0: {
+          goto -> bb1;                     // scope 0 at $DIR/switch_to_self.rs:+3:13: +3:22
+      }
+  
+      bb1: {
+          switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/switch_to_self.rs:+6:13: +6:47
+      }
+  
+      bb2: {
+          switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/switch_to_self.rs:+9:13: +9:47
+      }
+  }
+  
diff --git a/tests/mir-opt/tls_access.main.PreCodegen.after.mir b/tests/mir-opt/tls_access.main.PreCodegen.after.mir
index 09453b8..03618ae 100644
--- a/tests/mir-opt/tls_access.main.PreCodegen.after.mir
+++ b/tests/mir-opt/tls_access.main.PreCodegen.after.mir
@@ -2,27 +2,27 @@
 
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/tls_access.rs:+0:11: +0:11
-    let _2: *mut u8;                     // in scope 0 at $DIR/tls_access.rs:+2:18: +2:21
+    let _1: *mut u8;                     // in scope 0 at $DIR/tls_access.rs:+2:18: +2:21
     let mut _3: *mut u8;                 // in scope 0 at $DIR/tls_access.rs:+3:9: +3:12
     scope 1 {
-        let _1: &u8;                     // in scope 1 at $DIR/tls_access.rs:+2:13: +2:14
+        let _2: &u8;                     // in scope 1 at $DIR/tls_access.rs:+2:13: +2:14
         scope 2 {
-            debug a => _1;               // in scope 2 at $DIR/tls_access.rs:+2:13: +2:14
+            debug a => _2;               // in scope 2 at $DIR/tls_access.rs:+2:13: +2:14
         }
     }
 
     bb0: {
-        StorageLive(_1);                 // scope 1 at $DIR/tls_access.rs:+2:13: +2:14
-        StorageLive(_2);                 // scope 1 at $DIR/tls_access.rs:+2:18: +2:21
-        _2 = &/*tls*/ mut FOO;           // scope 1 at $DIR/tls_access.rs:+2:18: +2:21
-        _1 = &(*_2);                     // scope 1 at $DIR/tls_access.rs:+2:17: +2:21
+        StorageLive(_2);                 // scope 1 at $DIR/tls_access.rs:+2:13: +2:14
+        StorageLive(_1);                 // scope 1 at $DIR/tls_access.rs:+2:18: +2:21
+        _1 = &/*tls*/ mut FOO;           // scope 1 at $DIR/tls_access.rs:+2:18: +2:21
+        _2 = &(*_1);                     // scope 1 at $DIR/tls_access.rs:+2:17: +2:21
         StorageLive(_3);                 // scope 2 at $DIR/tls_access.rs:+3:9: +3:12
         _3 = &/*tls*/ mut FOO;           // scope 2 at $DIR/tls_access.rs:+3:9: +3:12
         (*_3) = const 42_u8;             // scope 2 at $DIR/tls_access.rs:+3:9: +3:17
         StorageDead(_3);                 // scope 2 at $DIR/tls_access.rs:+3:17: +3:18
         _0 = const ();                   // scope 1 at $DIR/tls_access.rs:+1:5: +4:6
-        StorageDead(_2);                 // scope 1 at $DIR/tls_access.rs:+4:5: +4:6
         StorageDead(_1);                 // scope 1 at $DIR/tls_access.rs:+4:5: +4:6
+        StorageDead(_2);                 // scope 1 at $DIR/tls_access.rs:+4:5: +4:6
         return;                          // scope 0 at $DIR/tls_access.rs:+5:2: +5:2
     }
 }
diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir
index 811789a..8922eda 100644
--- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir
+++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir
@@ -31,18 +31,18 @@
     }
 
     bb4: {
-        switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+        switchInt(move _3) -> [0: bb5, otherwise: bb6]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
     }
 
     bb5: {
         StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
-        goto -> bb7;                     // scope 0 at no-location
+        StorageDead(_2);                 // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
+        goto -> bb1;                     // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
     }
 
     bb6: {
         StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
-        StorageDead(_2);                 // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
-        goto -> bb1;                     // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
+        goto -> bb7;                     // scope 0 at no-location
     }
 
     bb7: {
diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml
index ee5598e..bf096f6 100644
--- a/tests/rustdoc-gui/search-result-display.goml
+++ b/tests/rustdoc-gui/search-result-display.goml
@@ -57,22 +57,22 @@
 
 call-function: ("check-filter", {
     "theme": "ayu",
-    "border": "rgb(92, 103, 115)",
+    "border": "#5c6773",
     "filter": "invert(0.41) sepia(0.12) saturate(4.87) hue-rotate(171deg) brightness(0.94) contrast(0.94)",
-    "hover_border": "rgb(224, 224, 224)",
+    "hover_border": "#e0e0e0",
     "hover_filter": "invert(0.98) sepia(0.12) saturate(0.81) hue-rotate(343deg) brightness(1.13) contrast(0.76)",
 })
 call-function: ("check-filter", {
     "theme": "dark",
-    "border": "rgb(224, 224, 224)",
+    "border": "#e0e0e0",
     "filter": "invert(0.94) sepia(0) saturate(7.21) hue-rotate(255deg) brightness(0.9) contrast(0.9)",
-    "hover_border": "rgb(33, 150, 243)",
+    "hover_border": "#2196f3",
     "hover_filter": "invert(0.69) sepia(0.6) saturate(66.13) hue-rotate(184deg) brightness(1) contrast(0.91)",
 })
 call-function: ("check-filter", {
     "theme": "light",
-    "border": "rgb(224, 224, 224)",
+    "border": "#e0e0e0",
     "filter": "invert(1) sepia(0) saturate(42.23) hue-rotate(289deg) brightness(1.14) contrast(0.76)",
-    "hover_border": "rgb(113, 113, 113)",
+    "hover_border": "#717171",
     "hover_filter": "invert(0.44) sepia(0.18) saturate(0.23) hue-rotate(317deg) brightness(0.96) contrast(0.93)",
 })
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index 3d88d56..67f1497 100644
--- a/tests/rustdoc-gui/source-anchor-scroll.goml
+++ b/tests/rustdoc-gui/source-anchor-scroll.goml
@@ -8,13 +8,13 @@
 assert-property: ("html", {"scrollTop": "0"})
 
 click: '//a[text() = "barbar"]'
-assert-property: ("html", {"scrollTop": "125"})
+assert-property: ("html", {"scrollTop": "149"})
 click: '//a[text() = "bar"]'
-assert-property: ("html", {"scrollTop": "156"})
+assert-property: ("html", {"scrollTop": "180"})
 click: '//a[text() = "sub_fn"]'
-assert-property: ("html", {"scrollTop": "53"})
+assert-property: ("html", {"scrollTop": "77"})
 
 // We now check that clicking on lines doesn't change the scroll
 // Extra information: the "sub_fn" function header is on line 1.
 click: '//*[@id="6"]'
-assert-property: ("html", {"scrollTop": "53"})
+assert-property: ("html", {"scrollTop": "77"})
diff --git a/tests/rustdoc-gui/src/extend_css/lib.rs b/tests/rustdoc-gui/src/extend_css/lib.rs
index 3a3babf..2308c09 100644
--- a/tests/rustdoc-gui/src/extend_css/lib.rs
+++ b/tests/rustdoc-gui/src/extend_css/lib.rs
@@ -1 +1,2 @@
+// compile-flags: --extend-css extra.css
 //! <div class="extend">text in red</div>
diff --git a/tests/rustdoc-gui/src/link_to_definition/lib.rs b/tests/rustdoc-gui/src/link_to_definition/lib.rs
index 419a9cc..6fed79a 100644
--- a/tests/rustdoc-gui/src/link_to_definition/lib.rs
+++ b/tests/rustdoc-gui/src/link_to_definition/lib.rs
@@ -1,3 +1,4 @@
+// compile-flags: -Zunstable-options --generate-link-to-definition
 pub fn sub_fn() {
     barbar();
 }
diff --git a/tests/rustdoc-gui/src/scrape_examples/src/lib.rs b/tests/rustdoc-gui/src/scrape_examples/src/lib.rs
index 88b03cf..6666587 100644
--- a/tests/rustdoc-gui/src/scrape_examples/src/lib.rs
+++ b/tests/rustdoc-gui/src/scrape_examples/src/lib.rs
@@ -1,3 +1,4 @@
+// run-flags:-Zrustdoc-scrape-examples
 /// # Examples
 ///
 /// ```
diff --git a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr
index 8669b0c..6c834fd 100644
--- a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr
+++ b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr
@@ -36,7 +36,7 @@
 help: to link to the trait, prefix with `trait@`
    |
 LL - //! [`Clone ()`].
-LL + //! [`trait@Clone (`].
+LL + //! [`trait@Clone `].
    |
 
 error: incompatible link kind for `Clone`
@@ -47,8 +47,9 @@
    |
 help: to link to the derive macro, prefix with `derive@`
    |
-LL | //! [`derive@Clone !`].
-   |       +++++++
+LL - //! [`Clone !`].
+LL + //! [`derive@Clone `].
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs
new file mode 100644
index 0000000..ca18842
--- /dev/null
+++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs
@@ -0,0 +1,140 @@
+// Many examples are from
+// https://github.com/rust-lang/rust/issues/110111#issuecomment-1517800781
+#![deny(rustdoc::broken_intra_doc_links)]
+
+//! This test case is closely linked to [raphlinus/pulldown-cmark#441], getting offsets of
+//! link components. In particular, pulldown-cmark doesn't provide the offsets of the contents
+//! of a link.
+//!
+//! To work around this, rustdoc parses parts of a link definition itself. This is basically a
+//! test suite for that link syntax parser.
+//!
+//! [raphlinus/pulldown-cmark#441]: https://github.com/raphlinus/pulldown-cmark/issues/441
+
+use std::clone::Clone;
+
+// Basic version //
+
+/// [`struct@Clone`] //~ERROR link
+pub struct LinkToCloneWithBackquotes;
+
+/// [```struct@Clone```] //~ERROR link
+pub struct LinkToCloneWithMultipleBackquotes;
+
+/// [  `  struct@Clone  `  ] //~ERROR link
+pub struct LinkToCloneWithSpacesAndBackquotes;
+
+/// [  `Clone ()`  ] //~ERROR link
+pub struct LinkToCloneWithSpacesBackquotesAndParens;
+
+/// [`Clone ()`  ] //~ERROR link
+pub struct LinkToCloneWithSpacesEndBackquotesAndParens;
+
+/// [  `Clone ()`] //~ERROR link
+pub struct LinkToCloneWithSpacesStartBackquotesAndParens;
+
+/// [```Clone ()```] //~ERROR link
+pub struct LinkToCloneWithMultipleBackquotesAndParens;
+
+/// [```Clone \(\)```] // not URL-shaped enough
+pub struct LinkToCloneWithMultipleBackquotesAndEscapedParens;
+
+/// [  ```  Clone ()  ```  ] //~ERROR link
+pub struct LinkToCloneWithSpacesMultipleBackquotesAndParens;
+
+/// [ x \] ] // not URL-shaped enough
+pub struct LinkWithEscapedCloseBrace;
+
+/// [ x \[ ] // not URL-shaped enough
+pub struct LinkWithEscapedOpenBrace;
+
+/// [ x \( ] // not URL-shaped enough
+pub struct LinkWithEscapedCloseParen;
+
+/// [ x \) ] // not URL-shaped enough
+pub struct LinkWithEscapedOpenParen;
+
+/// [ Clone \(\) ] // not URL-shaped enough
+pub struct LinkWithEscapedParens;
+
+// [][] version //
+
+/// [x][ struct@Clone] //~ERROR link
+pub struct XLinkToCloneWithStartSpace;
+
+/// [x][struct@Clone ] //~ERROR link
+pub struct XLinkToCloneWithEndSpace;
+
+/// [x][Clone\(\)] not URL-shaped enough
+pub struct XLinkToCloneWithEscapedParens;
+
+/// [x][`Clone`] not URL-shaped enough
+pub struct XLinkToCloneWithBackquotes;
+
+/// [x][Clone()] //~ERROR link
+pub struct XLinkToCloneWithUnescapedParens;
+
+/// [x][Clone  ()] //~ERROR link
+pub struct XLinkToCloneWithUnescapedParensAndDoubleSpace;
+
+/// [x][Clone  [] //~ERROR unresolved link to `x`
+pub struct XLinkToCloneWithUnmatchedOpenParenAndDoubleSpace;
+
+/// [x][Clone  \[] // not URL-shaped enough
+pub struct XLinkToCloneWithUnmatchedEscapedOpenParenAndDoubleSpace;
+
+/// [x][Clone  \]] // not URL-shaped enough
+pub struct XLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace;
+
+// []() version //
+
+/// [w]( struct@Clone) //~ERROR link
+pub struct WLinkToCloneWithStartSpace;
+
+/// [w](struct@Clone ) //~ERROR link
+pub struct WLinkToCloneWithEndSpace;
+
+/// [w](Clone\(\)) //~ERROR link
+pub struct WLinkToCloneWithEscapedParens;
+
+/// [w](`Clone`) not URL-shaped enough
+pub struct WLinkToCloneWithBackquotes;
+
+/// [w](Clone()) //~ERROR link
+pub struct WLinkToCloneWithUnescapedParens;
+
+/// [w](Clone  ()) not URL-shaped enough
+pub struct WLinkToCloneWithUnescapedParensAndDoubleSpace;
+
+/// [w](Clone  () //~ERROR unresolved link to `w`
+pub struct WLinkToCloneWithUnmatchedOpenParenAndDoubleSpace;
+
+/// [w](Clone  \() //~ERROR unresolved link to `w`
+pub struct WLinkToCloneWithUnmatchedEscapedOpenParenAndDoubleSpace;
+
+/// [w](Clone  \)) //~ERROR unresolved link to `w`
+pub struct WLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace;
+
+// References
+
+/// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected //~ERROR link
+/// in Markdown for not being URL-shaped enough.
+///
+/// [cln]: Clone() //~ERROR link
+pub struct LinkToCloneWithParensInReference;
+
+/// The [cln][] link here is going to be unresolved, because `struct@Clone` gets //~ERROR link
+/// rejected in Markdown for not being URL-shaped enough.
+///
+/// [cln]: struct@Clone //~ERROR link
+pub struct LinkToCloneWithWrongPrefix;
+
+/// The [cln][] link here will produce a plain text suggestion //~ERROR link
+///
+/// [cln]: Clone\(\)
+pub struct LinkToCloneWithEscapedParensInReference;
+
+/// The [cln][] link here will produce a plain text suggestion //~ERROR link
+///
+/// [cln]: struct\@Clone
+pub struct LinkToCloneWithEscapedAtsInReference;
diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr
new file mode 100644
index 0000000..f50feb5
--- /dev/null
+++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr
@@ -0,0 +1,272 @@
+error: incompatible link kind for `Clone`
+  --> $DIR/weird-syntax.rs:18:7
+   |
+LL | /// [`struct@Clone`]
+   |       ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
+   |
+note: the lint level is defined here
+  --> $DIR/weird-syntax.rs:3:9
+   |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the trait, prefix with `trait@`
+   |
+LL | /// [`trait@Clone`]
+   |       ~~~~~~
+
+error: incompatible link kind for `Clone`
+  --> $DIR/weird-syntax.rs:21:9
+   |
+LL | /// [```struct@Clone```]
+   |         ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL | /// [```trait@Clone```]
+   |         ~~~~~~
+
+error: incompatible link kind for `Clone`
+  --> $DIR/weird-syntax.rs:24:11
+   |
+LL | /// [  `  struct@Clone  `  ]
+   |           ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL | /// [  `  trait@Clone  `  ]
+   |           ~~~~~~
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:27:9
+   |
+LL | /// [  `Clone ()`  ]
+   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [  `Clone ()`  ]
+LL + /// [  `trait@Clone `  ]
+   |
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:30:7
+   |
+LL | /// [`Clone ()`  ]
+   |       ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [`Clone ()`  ]
+LL + /// [`trait@Clone `  ]
+   |
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:33:9
+   |
+LL | /// [  `Clone ()`]
+   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [  `Clone ()`]
+LL + /// [  `trait@Clone `]
+   |
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:36:9
+   |
+LL | /// [```Clone ()```]
+   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [```Clone ()```]
+LL + /// [```trait@Clone ```]
+   |
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:42:13
+   |
+LL | /// [  ```  Clone ()  ```  ]
+   |             ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [  ```  Clone ()  ```  ]
+LL + /// [  ```  trait@Clone   ```  ]
+   |
+
+error: incompatible link kind for `Clone`
+  --> $DIR/weird-syntax.rs:62:10
+   |
+LL | /// [x][ struct@Clone]
+   |          ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL | /// [x][ trait@Clone]
+   |          ~~~~~~
+
+error: incompatible link kind for `Clone`
+  --> $DIR/weird-syntax.rs:65:9
+   |
+LL | /// [x][struct@Clone ]
+   |         ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL | /// [x][trait@Clone ]
+   |         ~~~~~~
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:74:9
+   |
+LL | /// [x][Clone()]
+   |         ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [x][Clone()]
+LL + /// [x][trait@Clone]
+   |
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:77:9
+   |
+LL | /// [x][Clone  ()]
+   |         ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [x][Clone  ()]
+LL + /// [x][trait@Clone  ]
+   |
+
+error: unresolved link to `x`
+  --> $DIR/weird-syntax.rs:80:6
+   |
+LL | /// [x][Clone  []
+   |      ^ no item named `x` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: incompatible link kind for `Clone`
+  --> $DIR/weird-syntax.rs:91:10
+   |
+LL | /// [w]( struct@Clone)
+   |          ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL | /// [w]( trait@Clone)
+   |          ~~~~~~
+
+error: incompatible link kind for `Clone`
+  --> $DIR/weird-syntax.rs:94:9
+   |
+LL | /// [w](struct@Clone )
+   |         ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL | /// [w](trait@Clone )
+   |         ~~~~~~
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:97:9
+   |
+LL | /// [w](Clone\(\))
+   |         ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [w](Clone\(\))
+LL + /// [w](trait@Clone)
+   |
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:103:9
+   |
+LL | /// [w](Clone())
+   |         ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+help: to link to the trait, prefix with `trait@`
+   |
+LL - /// [w](Clone())
+LL + /// [w](trait@Clone)
+   |
+
+error: unresolved link to `w`
+  --> $DIR/weird-syntax.rs:109:6
+   |
+LL | /// [w](Clone  ()
+   |      ^ no item named `w` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `w`
+  --> $DIR/weird-syntax.rs:112:6
+   |
+LL | /// [w](Clone  \()
+   |      ^ no item named `w` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `w`
+  --> $DIR/weird-syntax.rs:115:6
+   |
+LL | /// [w](Clone  \))
+   |      ^ no item named `w` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `cln`
+  --> $DIR/weird-syntax.rs:120:10
+   |
+LL | /// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected
+   |          ^^^ no item named `cln` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `cln`
+  --> $DIR/weird-syntax.rs:123:6
+   |
+LL | /// [cln]: Clone()
+   |      ^^^ no item named `cln` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `cln`
+  --> $DIR/weird-syntax.rs:126:10
+   |
+LL | /// The [cln][] link here is going to be unresolved, because `struct@Clone` gets
+   |          ^^^ no item named `cln` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `cln`
+  --> $DIR/weird-syntax.rs:129:6
+   |
+LL | /// [cln]: struct@Clone
+   |      ^^^ no item named `cln` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: unresolved link to `Clone`
+  --> $DIR/weird-syntax.rs:132:9
+   |
+LL | /// The [cln][] link here will produce a plain text suggestion
+   |         ^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |
+   = help: to link to the trait, prefix with `trait@`: trait@Clone
+
+error: incompatible link kind for `Clone`
+  --> $DIR/weird-syntax.rs:137:9
+   |
+LL | /// The [cln][] link here will produce a plain text suggestion
+   |         ^^^^^ this link resolved to a trait, which is not a struct
+   |
+   = help: to link to the trait, prefix with `trait@`: trait@Clone
+
+error: aborting due to 26 previous errors
+
diff --git a/tests/rustdoc/reexport-doc-hidden.rs b/tests/rustdoc/reexport-doc-hidden.rs
index 3ea5fde..d9ed954 100644
--- a/tests/rustdoc/reexport-doc-hidden.rs
+++ b/tests/rustdoc/reexport-doc-hidden.rs
@@ -21,6 +21,5 @@ macro_rules! foo {
     () => {};
 }
 
-// This is a bug: https://github.com/rust-lang/rust/issues/59368
-// @!has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;'
+// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;'
 pub use crate::foo as Macro;
diff --git a/tests/rustdoc/reexport-hidden-macro.rs b/tests/rustdoc/reexport-hidden-macro.rs
index afcfa97..47a21e3 100644
--- a/tests/rustdoc/reexport-hidden-macro.rs
+++ b/tests/rustdoc/reexport-hidden-macro.rs
@@ -5,6 +5,7 @@
 
 // @has 'foo/index.html'
 // @has - '//*[@id="main-content"]//a[@href="macro.Macro2.html"]' 'Macro2'
+// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;'
 
 // @has 'foo/macro.Macro2.html'
 // @has - '//*[@class="docblock"]' 'Displayed'
@@ -15,7 +16,6 @@ macro_rules! foo {
     () => {};
 }
 
-/// not displayed
 pub use crate::foo as Macro;
 /// Displayed
 #[doc(inline)]
diff --git a/tests/rustdoc/reexport-of-doc-hidden.rs b/tests/rustdoc/reexport-of-doc-hidden.rs
new file mode 100644
index 0000000..b733716
--- /dev/null
+++ b/tests/rustdoc/reexport-of-doc-hidden.rs
@@ -0,0 +1,42 @@
+// This test ensures that all re-exports of doc hidden elements are displayed.
+
+#![crate_name = "foo"]
+
+#[doc(hidden)]
+pub struct Bar;
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! foo {
+    () => {};
+}
+
+// @has 'foo/index.html'
+// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;'
+pub use crate::foo as Macro;
+// @has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;'
+pub use crate::foo as Macro2;
+// @has - '//*[@id="reexport.Boo"]/code' 'pub use crate::Bar as Boo;'
+pub use crate::Bar as Boo;
+// @has - '//*[@id="reexport.Boo2"]/code' 'pub use crate::Bar as Boo2;'
+pub use crate::Bar as Boo2;
+
+pub fn fofo() {}
+
+// @has - '//*[@id="reexport.f1"]/code' 'pub use crate::fofo as f1;'
+pub use crate::fofo as f1;
+// @has - '//*[@id="reexport.f2"]/code' 'pub use crate::fofo as f2;'
+pub use crate::fofo as f2;
+
+pub mod sub {
+    // @has 'foo/sub/index.html'
+    // @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;'
+    pub use crate::foo as Macro;
+    // @has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;'
+    pub use crate::foo as Macro2;
+
+    // @has - '//*[@id="reexport.f1"]/code' 'pub use crate::fofo as f1;'
+    pub use crate::fofo as f1;
+    // @has - '//*[@id="reexport.f2"]/code' 'pub use crate::fofo as f2;'
+    pub use crate::fofo as f2;
+}
diff --git a/tests/ui/backtrace.rs b/tests/ui/backtrace.rs
index dd73dd9..66b378f 100644
--- a/tests/ui/backtrace.rs
+++ b/tests/ui/backtrace.rs
@@ -104,13 +104,17 @@ fn runtest(me: &str) {
                 "bad output3: {}", s);
 
         // Make sure a stack trace isn't printed too many times
+        //
+        // Currently it is printed 3 times ("once", "twice" and "panic in a
+        // function that cannot unwind") but in the future the last one may be
+        // removed.
         let p = template(me).arg("double-fail")
                                     .env("RUST_BACKTRACE", "1").spawn().unwrap();
         let out = p.wait_with_output().unwrap();
         assert!(!out.status.success());
         let s = str::from_utf8(&out.stderr).unwrap();
         let mut i = 0;
-        for _ in 0..2 {
+        for _ in 0..3 {
             i += s[i + 10..].find("stack backtrace").unwrap() + 10;
         }
         assert!(s[i + 10..].find("stack backtrace").is_none(),
diff --git a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr
index 26453b4..2f397f6 100644
--- a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr
+++ b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr
@@ -4,7 +4,7 @@
 LL |      assert_static(&FOO);
    |                    ^^^^ thread-local variables cannot be borrowed beyond the end of the function
 LL | }
-   | - end of enclosing function is here
+   |  - end of enclosing function is here
 
 error: aborting due to previous error
 
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
index 127a3f5..1bda7a4 100644
--- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
+++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
@@ -8,7 +8,6 @@ fn a() {
         //~^ NOTE `vec[_]` is borrowed here
             vec[0] = Box::new(4); //~ ERROR cannot assign
             //~^ NOTE `vec[_]` is assigned to here
-            //~| NOTE in this expansion of desugaring of drop and replace
             _a.use_ref();
             //~^ NOTE borrow later used here
         }
@@ -23,7 +22,6 @@ fn b() {
         //~^ `vec[_]` is borrowed here
             vec[0] = Box::new(4); //~ ERROR cannot assign
             //~^ NOTE `vec[_]` is assigned to here
-            //~| NOTE in this expansion of desugaring of drop and replace
             _b.use_ref();
             //~^ NOTE borrow later used here
         }
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
index 5e1251b..70b9e4f 100644
--- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
+++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
@@ -6,24 +6,24 @@
 LL |
 LL |             vec[0] = Box::new(4);
    |             ^^^^^^ `vec[_]` is assigned to here but it was already borrowed
-...
+LL |
 LL |             _a.use_ref();
    |             ------------ borrow later used here
 
 error[E0506]: cannot assign to `vec[_]` because it is borrowed
-  --> $DIR/borrowck-vec-pattern-nesting.rs:24:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:23:13
    |
 LL |         &mut [ref _b @ ..] => {
    |               ------ `vec[_]` is borrowed here
 LL |
 LL |             vec[0] = Box::new(4);
    |             ^^^^^^ `vec[_]` is assigned to here but it was already borrowed
-...
+LL |
 LL |             _b.use_ref();
    |             ------------ borrow later used here
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:36:11
+  --> $DIR/borrowck-vec-pattern-nesting.rs:34:11
    |
 LL |     match vec {
    |           ^^^ cannot move out of here
@@ -41,7 +41,7 @@
    |
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:48:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:46:13
    |
 LL |     let a = vec[0];
    |             ^^^^^^
@@ -55,7 +55,7 @@
    |             +
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:57:11
+  --> $DIR/borrowck-vec-pattern-nesting.rs:55:11
    |
 LL |     match vec {
    |           ^^^ cannot move out of here
@@ -73,7 +73,7 @@
    |
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:67:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:65:13
    |
 LL |     let a = vec[0];
    |             ^^^^^^
@@ -87,7 +87,7 @@
    |             +
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:76:11
+  --> $DIR/borrowck-vec-pattern-nesting.rs:74:11
    |
 LL |     match vec {
    |           ^^^ cannot move out of here
@@ -106,7 +106,7 @@
    |
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:87:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:85:13
    |
 LL |     let a = vec[0];
    |             ^^^^^^
diff --git a/tests/ui/borrowck/issue-45199.rs b/tests/ui/borrowck/issue-45199.rs
index 6a6b255..ded46e5 100644
--- a/tests/ui/borrowck/issue-45199.rs
+++ b/tests/ui/borrowck/issue-45199.rs
@@ -5,7 +5,6 @@
     b = Box::new(1);    //~ NOTE first assignment
     b = Box::new(2);    //~ ERROR cannot assign twice to immutable variable `b`
                         //~| NOTE cannot assign twice to immutable
-                        //~| NOTE in this expansion of desugaring of drop and replace
 }
 
 fn test_call() {
@@ -14,14 +13,12 @@ fn test_call() {
                             //~| SUGGESTION mut b
     b = Box::new(2);        //~ ERROR cannot assign twice to immutable variable `b`
                             //~| NOTE cannot assign twice to immutable
-                            //~| NOTE in this expansion of desugaring of drop and replace
 }
 
 fn test_args(b: Box<i32>) {  //~ HELP consider making this binding mutable
                                 //~| SUGGESTION mut b
     b = Box::new(2);            //~ ERROR cannot assign to immutable argument `b`
                                 //~| NOTE cannot assign to immutable argument
-                                //~| NOTE in this expansion of desugaring of drop and replace
 }
 
 fn main() {}
diff --git a/tests/ui/borrowck/issue-45199.stderr b/tests/ui/borrowck/issue-45199.stderr
index 163f237..47aa309 100644
--- a/tests/ui/borrowck/issue-45199.stderr
+++ b/tests/ui/borrowck/issue-45199.stderr
@@ -10,7 +10,7 @@
    |     ^ cannot assign twice to immutable variable
 
 error[E0384]: cannot assign twice to immutable variable `b`
-  --> $DIR/issue-45199.rs:15:5
+  --> $DIR/issue-45199.rs:14:5
    |
 LL |     let b = Box::new(1);
    |         -
@@ -22,7 +22,7 @@
    |     ^ cannot assign twice to immutable variable
 
 error[E0384]: cannot assign to immutable argument `b`
-  --> $DIR/issue-45199.rs:22:5
+  --> $DIR/issue-45199.rs:20:5
    |
 LL | fn test_args(b: Box<i32>) {
    |              - help: consider making this binding mutable: `mut b`
diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs
index 85345d6..b22cab7 100644
--- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs
+++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs
@@ -1,7 +1,7 @@
-// check-pass
+// known-bug: #110395
 // known-bug: #97156
 
-#![feature(const_type_id, generic_const_exprs)]
+#![feature(const_type_id, const_trait_impl, generic_const_exprs)]
 #![allow(incomplete_features)]
 
 use std::any::TypeId;
@@ -26,7 +26,10 @@ impl<T: 'static> AssocCt for T {
 trait WithAssoc<U> {
     type Assoc;
 }
-impl<T: 'static> WithAssoc<()> for T where [(); <T as AssocCt>::ASSOC]: {
+impl<T: 'static> WithAssoc<()> for T
+where
+    [(); <T as AssocCt>::ASSOC]:,
+{
     type Assoc = [u8; <T as AssocCt>::ASSOC];
 }
 
@@ -38,7 +41,6 @@ fn generic<T: 'static, U>(x: <T as WithAssoc<U>>::Assoc) -> <T as WithAssoc<U>>:
     x
 }
 
-
 fn unsound<T>(x: <One as WithAssoc<T>>::Assoc) -> <Two as WithAssoc<T>>::Assoc
 where
     One: WithAssoc<T>,
diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
new file mode 100644
index 0000000..8cbd126
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
@@ -0,0 +1,11 @@
+error: to use a constant of type `TypeId` in a pattern, `TypeId` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/typeid-equality-by-subtyping.rs:18:9
+   |
+LL |         WHAT_A_TYPE => 0,
+   |         ^^^^^^^^^^^
+   |
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+
+error: aborting due to previous error
+
diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr
index 41b0981..3d1197a 100644
--- a/tests/ui/const-generics/transmute-fail.stderr
+++ b/tests/ui/const-generics/transmute-fail.stderr
@@ -4,8 +4,8 @@
 LL |     std::mem::transmute(v)
    |     ^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `[[u32; H+1]; W]` (generic size [const expr])
-   = note: target type: `[[u32; W+1]; H]` (generic size [const expr])
+   = note: source type: `[[u32; H+1]; W]` (generic size {const expr})
+   = note: target type: `[[u32; W+1]; H]` (generic size {const expr})
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:16:5
@@ -34,8 +34,8 @@
 LL |     std::mem::transmute(v)
    |     ^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `[[u32; H]; W]` (generic size [const expr])
-   = note: target type: `[u32; W * H * H]` (generic size [const expr])
+   = note: source type: `[[u32; H]; W]` (generic size {const expr})
+   = note: target type: `[u32; W * H * H]` (generic size {const expr})
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:30:5
diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr
index 319d2b9..dc2c702 100644
--- a/tests/ui/consts/const_cmp_type_id.stderr
+++ b/tests/ui/consts/const_cmp_type_id.stderr
@@ -20,7 +20,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: can't compare `TypeId` with `TypeId` in const contexts
   --> $DIR/const_cmp_type_id.rs:9:13
@@ -44,7 +43,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: can't compare `TypeId` with `TypeId` in const contexts
   --> $DIR/const_cmp_type_id.rs:10:22
diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr
index 95ab78b..09661d3 100644
--- a/tests/ui/consts/issue-73976-monomorphic.stderr
+++ b/tests/ui/consts/issue-73976-monomorphic.stderr
@@ -20,7 +20,6 @@
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.rs b/tests/ui/editions/edition-raw-pointer-method-2018.rs
index af0b2d6..0bae65a 100644
--- a/tests/ui/editions/edition-raw-pointer-method-2018.rs
+++ b/tests/ui/editions/edition-raw-pointer-method-2018.rs
@@ -7,5 +7,5 @@ fn main() {
     let x = 0;
     let y = &x as *const _;
     let _ = y.is_null();
-    //~^ error: the type of this value must be known to call a method on a raw pointer on it [E0699]
+    //~^ error: cannot call a method on a raw pointer with an unknown pointee type [E0699]
 }
diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.stderr b/tests/ui/editions/edition-raw-pointer-method-2018.stderr
index 2345249..b9afa01 100644
--- a/tests/ui/editions/edition-raw-pointer-method-2018.stderr
+++ b/tests/ui/editions/edition-raw-pointer-method-2018.stderr
@@ -1,4 +1,4 @@
-error[E0699]: the type of this value must be known to call a method on a raw pointer on it
+error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
   --> $DIR/edition-raw-pointer-method-2018.rs:9:15
    |
 LL |     let _ = y.is_null();
diff --git a/tests/ui/impl-trait/multiple-defining-usages-in-body.rs b/tests/ui/impl-trait/multiple-defining-usages-in-body.rs
new file mode 100644
index 0000000..c3a6f09
--- /dev/null
+++ b/tests/ui/impl-trait/multiple-defining-usages-in-body.rs
@@ -0,0 +1,12 @@
+trait Trait {}
+impl Trait for () {}
+
+fn foo<T: Trait, U: Trait>() -> impl Trait {
+    //~^ WARN function cannot return without recursing [unconditional_recursion]
+    let a: T = foo::<T, U>();
+    //~^ ERROR concrete type differs from previous defining opaque type use
+    loop {}
+    let _: T = foo::<U, T>();
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/multiple-defining-usages-in-body.stderr b/tests/ui/impl-trait/multiple-defining-usages-in-body.stderr
new file mode 100644
index 0000000..0699174
--- /dev/null
+++ b/tests/ui/impl-trait/multiple-defining-usages-in-body.stderr
@@ -0,0 +1,26 @@
+warning: function cannot return without recursing
+  --> $DIR/multiple-defining-usages-in-body.rs:4:1
+   |
+LL | fn foo<T: Trait, U: Trait>() -> impl Trait {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |     let a: T = foo::<T, U>();
+   |                ------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/multiple-defining-usages-in-body.rs:6:16
+   |
+LL |     let a: T = foo::<T, U>();
+   |                ^^^^^^^^^^^^^ expected `U`, got `T`
+   |
+note: previous use here
+  --> $DIR/multiple-defining-usages-in-body.rs:9:16
+   |
+LL |     let _: T = foo::<U, T>();
+   |                ^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/imports/issue-55884-2.rs b/tests/ui/imports/issue-55884-2.rs
index 75bb420..6f8d0cf 100644
--- a/tests/ui/imports/issue-55884-2.rs
+++ b/tests/ui/imports/issue-55884-2.rs
@@ -6,6 +6,7 @@ mod parser {
     pub use options::*;
     // Private single import shadows public glob import, but arrives too late for initial
     // resolution of `use parser::ParseOptions` because it depends on that resolution itself.
+    #[allow(hidden_glob_reexports)]
     use ParseOptions;
 }
 
diff --git a/tests/ui/imports/issue-55884-2.stderr b/tests/ui/imports/issue-55884-2.stderr
index 5adbc4b..67d4114 100644
--- a/tests/ui/imports/issue-55884-2.stderr
+++ b/tests/ui/imports/issue-55884-2.stderr
@@ -1,16 +1,16 @@
 error[E0603]: struct import `ParseOptions` is private
-  --> $DIR/issue-55884-2.rs:12:17
+  --> $DIR/issue-55884-2.rs:13:17
    |
 LL | pub use parser::ParseOptions;
    |                 ^^^^^^^^^^^^ private struct import
    |
 note: the struct import `ParseOptions` is defined here...
-  --> $DIR/issue-55884-2.rs:9:9
+  --> $DIR/issue-55884-2.rs:10:9
    |
 LL |     use ParseOptions;
    |         ^^^^^^^^^^^^
 note: ...and refers to the struct import `ParseOptions` which is defined here...
-  --> $DIR/issue-55884-2.rs:12:9
+  --> $DIR/issue-55884-2.rs:13:9
    |
 LL | pub use parser::ParseOptions;
    |         ^^^^^^^^^^^^^^^^^^^^ consider importing it directly
diff --git a/tests/ui/issues/issue-17954.stderr b/tests/ui/issues/issue-17954.stderr
index e08375f..3e3706b 100644
--- a/tests/ui/issues/issue-17954.stderr
+++ b/tests/ui/issues/issue-17954.stderr
@@ -5,7 +5,7 @@
    |             ^^^^ thread-local variables cannot be borrowed beyond the end of the function
 ...
 LL | }
-   | - end of enclosing function is here
+   |  - end of enclosing function is here
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issues/issue-52049.stderr b/tests/ui/issues/issue-52049.stderr
index b25dbd1..0812976 100644
--- a/tests/ui/issues/issue-52049.stderr
+++ b/tests/ui/issues/issue-52049.stderr
@@ -2,12 +2,10 @@
   --> $DIR/issue-52049.rs:6:10
    |
 LL |     foo(&unpromotable(5u32));
-   |     -----^^^^^^^^^^^^^^^^^^-
+   |     -----^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
    |     |    |
    |     |    creates a temporary value which is freed while still in use
    |     argument requires that borrow lasts for `'static`
-LL | }
-   | - temporary value is freed at the end of this statement
 
 error: aborting due to previous error
 
diff --git a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
index 3602de8..598f142 100644
--- a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
+++ b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
@@ -10,7 +10,7 @@
    |                -------- cast requires that `foo` is borrowed for `'static`
 ...
 LL | }
-   | - `foo` dropped here while still borrowed
+   |  - `foo` dropped here while still borrowed
 
 error: lifetime may not live long enough
   --> $DIR/issue-90600-expected-return-static-indirect.rs:9:16
diff --git a/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs b/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs
new file mode 100644
index 0000000..0cade7f
--- /dev/null
+++ b/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs
@@ -0,0 +1,7 @@
+// check-pass
+// compile-flags: -Dunused_attributes
+
+#![deny(unused_crate_dependencies)]
+#![feature(lint_reasons)]
+
+fn main() {}
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
index 293fdca..c9b16e4 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
@@ -5,7 +5,6 @@
     drop(b);
     b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b`
                      //~| NOTE cannot assign twice to immutable
-                     //~| NOTE in this expansion of desugaring of drop and replace
     drop(b);
 }
 
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs
index e88e244..b1db05a 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs
@@ -5,7 +5,7 @@
 // needs-unwind Asserting on contents of error message
 
 #![allow(path_statements, unused_allocation)]
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#![feature(core_intrinsics, generic_assert)]
 
 macro_rules! test {
   (
@@ -51,6 +51,7 @@ macro_rules! tests {
 
 const FOO: Foo = Foo { bar: 1 };
 
+
 #[derive(Clone, Copy, Debug, PartialEq)]
 struct Foo {
   bar: i32
@@ -83,9 +84,18 @@ fn main() {
     // cast
     [ elem as i32 == 3 ] => "Assertion failed: elem as i32 == 3\nWith captures:\n  elem = 1\n"
 
+    // if
+    [ if elem == 3 { true } else { false } ] => "Assertion failed: if elem == 3 { true } else { false }\nWith captures:\n  elem = 1\n"
+
     // index
     [ [1i32, 1][elem as usize] == 3 ] => "Assertion failed: [1i32, 1][elem as usize] == 3\nWith captures:\n  elem = 1\n"
 
+    // let
+    [ if let 3 = elem { true } else { false } ] => "Assertion failed: if let 3 = elem { true } else { false }\nWith captures:\n  elem = 1\n"
+
+    // match
+    [ match elem { 3 => true, _ => false, } ] => "Assertion failed: match elem { 3 => true, _ => false, }\nWith captures:\n  elem = 1\n"
+
     // method call
     [ FOO.add(elem, elem) == 3 ] => "Assertion failed: FOO.add(elem, elem) == 3\nWith captures:\n  elem = 1\n"
 
@@ -107,77 +117,4 @@ fn main() {
     // unary
     [ -elem == -3 ] => "Assertion failed: -elem == -3\nWith captures:\n  elem = 1\n"
   );
-
-  // ***** Disallowed *****
-
-  tests!(
-    let mut elem = 1i32;
-
-    // assign
-    [ { let local = elem; local } == 3 ] => "Assertion failed: { let local = elem; local } == 3"
-
-    // assign op
-    [ { elem += 1; elem } == 3 ] => "Assertion failed: { elem += 1; elem } == 3"
-
-    // async
-    [ { let _ = async { elem }; elem } == 3 ] => "Assertion failed: { let _ = async { elem }; elem } == 3"
-
-    // await
-
-    // block
-    [ { elem } == 3 ] => "Assertion failed: { elem } == 3"
-
-    // break
-    [ loop { break elem; } ==  3 ] => "Assertion failed: loop { break elem; } == 3"
-
-    // closure
-    [(|| elem)() ==  3 ] => "Assertion failed: (|| elem)() == 3"
-
-    // const block
-
-    // continue
-
-    // err
-
-    // field
-    [ FOO.bar ==  3 ] => "Assertion failed: FOO.bar == 3"
-
-    // for loop
-    [ { for _ in 0..elem { elem; } elem } ==  3 ] => "Assertion failed: { for _ in 0..elem { elem; } elem } == 3"
-
-    // if
-    [ if true { elem } else { elem } == 3 ] => "Assertion failed: if true { elem } else { elem } == 3"
-
-    // inline asm
-
-    // let
-    [ if let true = true { elem } else { elem } == 3 ] => "Assertion failed: if let true = true { elem } else { elem } == 3"
-
-    // lit
-
-    // loop
-    [ loop { elem; break elem; } == 3 ] => "Assertion failed: loop { elem; break elem; } == 3"
-
-    // mac call
-
-    // match
-    [ match elem { _ => elem } == 3 ] => "Assertion failed: (match elem { _ => elem, }) == 3"
-
-    // ret
-    [ (|| { return elem; })() == 3 ] => "Assertion failed: (|| { return elem; })() == 3"
-
-    // try
-    [ (|| { Some(Some(elem)?) })() == Some(3) ] => "Assertion failed: (|| { Some(Some(elem)?) })() == Some(3)"
-
-    // try block
-
-    // underscore
-
-    // while
-    [ { while false { elem; break; } elem } == 3 ] => "Assertion failed: { while false { elem; break; } elem } == 3"
-
-    // yeet
-
-    // yield
-  );
 }
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs
index d46f396..fcf4f36 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs
@@ -4,7 +4,7 @@
 // run-pass
 // needs-unwind Asserting on contents of error message
 
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#![feature(core_intrinsics, generic_assert)]
 
 extern crate common;
 
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
index 6a1435f..c8408d1 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
@@ -1,7 +1,7 @@
 // compile-flags: --test
 // run-pass
 
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#![feature(core_intrinsics, generic_assert)]
 
 #[should_panic(expected = "Custom user message")]
 #[test]
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
index 1f5a29a..0e3c14a 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
@@ -3,7 +3,7 @@
 // run-pass
 // needs-unwind Asserting on contents of error message
 
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#![feature(core_intrinsics, generic_assert)]
 
 extern crate common;
 
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
index 01860ad..0d2518d 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
@@ -2,7 +2,7 @@
 // ignore-tidy-linelength
 // run-pass
 
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#![feature(core_intrinsics, generic_assert)]
 
 use std::fmt::{Debug, Formatter};
 
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
index 5ec84b0..57b79a5 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
@@ -1,7 +1,7 @@
 // check-pass
 // compile-flags: -Z unpretty=expanded
 
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#![feature(core_intrinsics, generic_assert)]
 
 fn arbitrary_consuming_method_for_demonstration_purposes() {
     let elem = 1i32;
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
index b69b5bc..66321bc 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
@@ -3,7 +3,7 @@
 // check-pass
 // compile-flags: -Z unpretty=expanded
 
-#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#![feature(core_intrinsics, generic_assert)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
diff --git a/tests/ui/methods/call_method_unknown_pointee.rs b/tests/ui/methods/call_method_unknown_pointee.rs
new file mode 100644
index 0000000..fe4275f
--- /dev/null
+++ b/tests/ui/methods/call_method_unknown_pointee.rs
@@ -0,0 +1,28 @@
+// edition: 2018
+
+// tests that the pointee type of a raw pointer must be known to call methods on it
+// see also: `tests/ui/editions/edition-raw-pointer-method-2018.rs`
+
+fn main() {
+    let val = 1_u32;
+    let ptr = &val as *const u32;
+    unsafe {
+        let _a: i32 = (ptr as *const _).read();
+        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
+        let b = ptr as *const _;
+        let _b: u8 = b.read();
+        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
+        let _c = (ptr as *const u8).read(); // we know the type here
+    }
+
+    let mut val = 2_u32;
+    let ptr = &mut val as *mut u32;
+    unsafe {
+        let _a: i32 = (ptr as *mut _).read();
+        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
+        let b = ptr as *mut _;
+        b.write(10);
+        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
+        (ptr as *mut i32).write(1000); // we know the type here
+    }
+}
diff --git a/tests/ui/methods/call_method_unknown_pointee.stderr b/tests/ui/methods/call_method_unknown_pointee.stderr
new file mode 100644
index 0000000..84ecf04
--- /dev/null
+++ b/tests/ui/methods/call_method_unknown_pointee.stderr
@@ -0,0 +1,27 @@
+error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
+  --> $DIR/call_method_unknown_pointee.rs:10:41
+   |
+LL |         let _a: i32 = (ptr as *const _).read();
+   |                                         ^^^^
+
+error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
+  --> $DIR/call_method_unknown_pointee.rs:13:24
+   |
+LL |         let _b: u8 = b.read();
+   |                        ^^^^
+
+error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
+  --> $DIR/call_method_unknown_pointee.rs:21:39
+   |
+LL |         let _a: i32 = (ptr as *mut _).read();
+   |                                       ^^^^
+
+error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
+  --> $DIR/call_method_unknown_pointee.rs:24:11
+   |
+LL |         b.write(10);
+   |           ^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0699`.
diff --git a/tests/ui/mir/addrof_alignment.rs b/tests/ui/mir/addrof_alignment.rs
new file mode 100644
index 0000000..892638b
--- /dev/null
+++ b/tests/ui/mir/addrof_alignment.rs
@@ -0,0 +1,15 @@
+// run-pass
+// ignore-wasm32-bare: No panic messages
+// compile-flags: -C debug-assertions
+
+struct Misalignment {
+    a: u32,
+}
+
+fn main() {
+    let items: [Misalignment; 2] = [Misalignment { a: 0 }, Misalignment { a: 1 }];
+    unsafe {
+        let ptr: *const Misalignment = items.as_ptr().cast::<u8>().add(1).cast::<Misalignment>();
+        let _ptr = core::ptr::addr_of!((*ptr).a);
+    }
+}
diff --git a/tests/ui/panics/nested_panic_caught.rs b/tests/ui/panics/nested_panic_caught.rs
new file mode 100644
index 0000000..d43886e
--- /dev/null
+++ b/tests/ui/panics/nested_panic_caught.rs
@@ -0,0 +1,24 @@
+// run-pass
+// needs-unwind
+
+// Checks that nested panics work correctly.
+
+use std::panic::catch_unwind;
+
+fn double() {
+    struct Double;
+
+    impl Drop for Double {
+        fn drop(&mut self) {
+            let _ = catch_unwind(|| panic!("twice"));
+        }
+    }
+
+    let _d = Double;
+
+    panic!("once");
+}
+
+fn main() {
+    assert!(catch_unwind(|| double()).is_err());
+}
diff --git a/tests/ui/parser/issues/issue-111148.rs b/tests/ui/parser/issues/issue-111148.rs
new file mode 100644
index 0000000..2502bea
--- /dev/null
+++ b/tests/ui/parser/issues/issue-111148.rs
@@ -0,0 +1,2 @@
+fn a<<i<Y<w<>#
+//~^ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime, found `<`
diff --git a/tests/ui/parser/issues/issue-111148.stderr b/tests/ui/parser/issues/issue-111148.stderr
new file mode 100644
index 0000000..e6595a5
--- /dev/null
+++ b/tests/ui/parser/issues/issue-111148.stderr
@@ -0,0 +1,8 @@
+error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `<`
+  --> $DIR/issue-111148.rs:1:6
+   |
+LL | fn a<<i<Y<w<>#
+   |      ^ expected one of `#`, `>`, `const`, identifier, or lifetime
+
+error: aborting due to previous error
+
diff --git a/tests/ui/parser/typod-const-in-const-param-def.rs b/tests/ui/parser/typod-const-in-const-param-def.rs
new file mode 100644
index 0000000..85d3ebb
--- /dev/null
+++ b/tests/ui/parser/typod-const-in-const-param-def.rs
@@ -0,0 +1,16 @@
+pub fn foo<Const N: u8>() {}
+//~^ ERROR `const` keyword was mistyped as `Const`
+
+pub fn bar<Const>() {}
+// OK
+
+pub fn baz<Const N: u8, T>() {}
+//~^ ERROR `const` keyword was mistyped as `Const`
+
+pub fn qux<T, Const N: u8>() {}
+//~^ ERROR `const` keyword was mistyped as `Const`
+
+pub fn quux<T, Const N: u8, U>() {}
+//~^ ERROR `const` keyword was mistyped as `Const`
+
+fn main() {}
diff --git a/tests/ui/parser/typod-const-in-const-param-def.stderr b/tests/ui/parser/typod-const-in-const-param-def.stderr
new file mode 100644
index 0000000..75d73c6
--- /dev/null
+++ b/tests/ui/parser/typod-const-in-const-param-def.stderr
@@ -0,0 +1,46 @@
+error: `const` keyword was mistyped as `Const`
+  --> $DIR/typod-const-in-const-param-def.rs:1:12
+   |
+LL | pub fn foo<Const N: u8>() {}
+   |            ^^^^^
+   |
+help: use the `const` keyword
+   |
+LL | pub fn foo<const N: u8>() {}
+   |            ~~~~~
+
+error: `const` keyword was mistyped as `Const`
+  --> $DIR/typod-const-in-const-param-def.rs:7:12
+   |
+LL | pub fn baz<Const N: u8, T>() {}
+   |            ^^^^^
+   |
+help: use the `const` keyword
+   |
+LL | pub fn baz<const N: u8, T>() {}
+   |            ~~~~~
+
+error: `const` keyword was mistyped as `Const`
+  --> $DIR/typod-const-in-const-param-def.rs:10:15
+   |
+LL | pub fn qux<T, Const N: u8>() {}
+   |               ^^^^^
+   |
+help: use the `const` keyword
+   |
+LL | pub fn qux<T, const N: u8>() {}
+   |               ~~~~~
+
+error: `const` keyword was mistyped as `Const`
+  --> $DIR/typod-const-in-const-param-def.rs:13:16
+   |
+LL | pub fn quux<T, Const N: u8, U>() {}
+   |                ^^^^^
+   |
+help: use the `const` keyword
+   |
+LL | pub fn quux<T, const N: u8, U>() {}
+   |                ~~~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
index 5a145ef..49b6dfc 100644
--- a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/empty-match.rs:37:9
+  --> $DIR/empty-match.rs:58:9
    |
 LL |         _ => {},
    |         ^
@@ -11,37 +11,52 @@
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/empty-match.rs:40:9
+  --> $DIR/empty-match.rs:61:9
    |
 LL |         _ if false => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/empty-match.rs:47:9
+  --> $DIR/empty-match.rs:68:9
    |
 LL |         _ => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/empty-match.rs:50:9
+  --> $DIR/empty-match.rs:71:9
    |
 LL |         _ if false => {},
    |         ^
 
+error[E0005]: refutable pattern in local binding
+  --> $DIR/empty-match.rs:76:9
+   |
+LL |     let None = x;
+   |         ^^^^ pattern `Some(_)` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: pattern `Some(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
+   = note: the matched value is of type `Option<SecretlyUninhabitedForeignStruct>`
+help: you might want to use `if let` to ignore the variant that isn't matched
+   |
+LL |     if let None = x { todo!() };
+   |     ++              +++++++++++
+
 error: unreachable pattern
-  --> $DIR/empty-match.rs:57:9
+  --> $DIR/empty-match.rs:88:9
    |
 LL |         _ => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/empty-match.rs:60:9
+  --> $DIR/empty-match.rs:91:9
    |
 LL |         _ if false => {},
    |         ^
 
 error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/empty-match.rs:78:20
+  --> $DIR/empty-match.rs:109:20
    |
 LL |     match_no_arms!(0u8);
    |                    ^^^
@@ -50,13 +65,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
-  --> $DIR/empty-match.rs:79:20
+  --> $DIR/empty-match.rs:111:20
    |
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
    |
 note: `NonEmptyStruct1` defined here
-  --> $DIR/empty-match.rs:14:8
+  --> $DIR/empty-match.rs:15:8
    |
 LL | struct NonEmptyStruct1;
    |        ^^^^^^^^^^^^^^^
@@ -64,13 +79,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
-  --> $DIR/empty-match.rs:80:20
+  --> $DIR/empty-match.rs:113:20
    |
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
    |
 note: `NonEmptyStruct2` defined here
-  --> $DIR/empty-match.rs:15:8
+  --> $DIR/empty-match.rs:18:8
    |
 LL | struct NonEmptyStruct2(bool);
    |        ^^^^^^^^^^^^^^^
@@ -78,13 +93,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/empty-match.rs:81:20
+  --> $DIR/empty-match.rs:115:20
    |
 LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `NonEmptyUnion1` defined here
-  --> $DIR/empty-match.rs:16:7
+  --> $DIR/empty-match.rs:21:7
    |
 LL | union NonEmptyUnion1 {
    |       ^^^^^^^^^^^^^^
@@ -92,13 +107,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/empty-match.rs:82:20
+  --> $DIR/empty-match.rs:117:20
    |
 LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `NonEmptyUnion2` defined here
-  --> $DIR/empty-match.rs:19:7
+  --> $DIR/empty-match.rs:26:7
    |
 LL | union NonEmptyUnion2 {
    |       ^^^^^^^^^^^^^^
@@ -106,13 +121,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:83:20
+  --> $DIR/empty-match.rs:119:20
    |
 LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
    |
 note: `NonEmptyEnum1` defined here
-  --> $DIR/empty-match.rs:24:5
+  --> $DIR/empty-match.rs:33:5
    |
 LL | enum NonEmptyEnum1 {
    |      -------------
@@ -122,31 +137,32 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:84:20
+  --> $DIR/empty-match.rs:122:20
    |
 LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
    |
 note: `NonEmptyEnum2` defined here
-  --> $DIR/empty-match.rs:27:5
+  --> $DIR/empty-match.rs:40:5
    |
 LL | enum NonEmptyEnum2 {
    |      -------------
 LL |     Foo(bool),
    |     ^^^ not covered
+...
 LL |     Bar,
    |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:85:20
+  --> $DIR/empty-match.rs:125:20
    |
 LL |     match_no_arms!(NonEmptyEnum5::V1);
    |                    ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
    |
 note: `NonEmptyEnum5` defined here
-  --> $DIR/empty-match.rs:30:6
+  --> $DIR/empty-match.rs:49:6
    |
 LL | enum NonEmptyEnum5 {
    |      ^^^^^^^^^^^^^
@@ -154,7 +170,7 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/empty-match.rs:87:24
+  --> $DIR/empty-match.rs:129:24
    |
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `_` not covered
@@ -167,13 +183,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
-  --> $DIR/empty-match.rs:88:24
+  --> $DIR/empty-match.rs:133:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
    |
 note: `NonEmptyStruct1` defined here
-  --> $DIR/empty-match.rs:14:8
+  --> $DIR/empty-match.rs:15:8
    |
 LL | struct NonEmptyStruct1;
    |        ^^^^^^^^^^^^^^^
@@ -185,13 +201,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
-  --> $DIR/empty-match.rs:89:24
+  --> $DIR/empty-match.rs:137:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
    |
 note: `NonEmptyStruct2` defined here
-  --> $DIR/empty-match.rs:15:8
+  --> $DIR/empty-match.rs:18:8
    |
 LL | struct NonEmptyStruct2(bool);
    |        ^^^^^^^^^^^^^^^
@@ -203,13 +219,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/empty-match.rs:90:24
+  --> $DIR/empty-match.rs:141:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
    |
 note: `NonEmptyUnion1` defined here
-  --> $DIR/empty-match.rs:16:7
+  --> $DIR/empty-match.rs:21:7
    |
 LL | union NonEmptyUnion1 {
    |       ^^^^^^^^^^^^^^
@@ -221,13 +237,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/empty-match.rs:91:24
+  --> $DIR/empty-match.rs:145:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
    |
 note: `NonEmptyUnion2` defined here
-  --> $DIR/empty-match.rs:19:7
+  --> $DIR/empty-match.rs:26:7
    |
 LL | union NonEmptyUnion2 {
    |       ^^^^^^^^^^^^^^
@@ -239,13 +255,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:92:24
+  --> $DIR/empty-match.rs:149:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
    |
 note: `NonEmptyEnum1` defined here
-  --> $DIR/empty-match.rs:24:5
+  --> $DIR/empty-match.rs:33:5
    |
 LL | enum NonEmptyEnum1 {
    |      -------------
@@ -259,18 +275,19 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:93:24
+  --> $DIR/empty-match.rs:153:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
    |
 note: `NonEmptyEnum2` defined here
-  --> $DIR/empty-match.rs:27:5
+  --> $DIR/empty-match.rs:40:5
    |
 LL | enum NonEmptyEnum2 {
    |      -------------
 LL |     Foo(bool),
    |     ^^^ not covered
+...
 LL |     Bar,
    |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
@@ -281,13 +298,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:94:24
+  --> $DIR/empty-match.rs:157:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum5::V1);
    |                        ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
    |
 note: `NonEmptyEnum5` defined here
-  --> $DIR/empty-match.rs:30:6
+  --> $DIR/empty-match.rs:49:6
    |
 LL | enum NonEmptyEnum5 {
    |      ^^^^^^^^^^^^^
@@ -298,6 +315,7 @@
 LL +             _ => todo!()
    |
 
-error: aborting due to 22 previous errors
+error: aborting due to 23 previous errors
 
-For more information about this error, try `rustc --explain E0004`.
+Some errors have detailed explanations: E0004, E0005.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr
index 5a145ef..f54a3f3 100644
--- a/tests/ui/pattern/usefulness/empty-match.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/empty-match.rs:37:9
+  --> $DIR/empty-match.rs:58:9
    |
 LL |         _ => {},
    |         ^
@@ -11,37 +11,51 @@
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/empty-match.rs:40:9
+  --> $DIR/empty-match.rs:61:9
    |
 LL |         _ if false => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/empty-match.rs:47:9
+  --> $DIR/empty-match.rs:68:9
    |
 LL |         _ => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/empty-match.rs:50:9
+  --> $DIR/empty-match.rs:71:9
    |
 LL |         _ if false => {},
    |         ^
 
+error[E0005]: refutable pattern in local binding
+  --> $DIR/empty-match.rs:76:9
+   |
+LL |     let None = x;
+   |         ^^^^ pattern `Some(_)` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: the matched value is of type `Option<SecretlyUninhabitedForeignStruct>`
+help: you might want to use `if let` to ignore the variant that isn't matched
+   |
+LL |     if let None = x { todo!() };
+   |     ++              +++++++++++
+
 error: unreachable pattern
-  --> $DIR/empty-match.rs:57:9
+  --> $DIR/empty-match.rs:88:9
    |
 LL |         _ => {},
    |         ^
 
 error: unreachable pattern
-  --> $DIR/empty-match.rs:60:9
+  --> $DIR/empty-match.rs:91:9
    |
 LL |         _ if false => {},
    |         ^
 
 error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/empty-match.rs:78:20
+  --> $DIR/empty-match.rs:109:20
    |
 LL |     match_no_arms!(0u8);
    |                    ^^^
@@ -50,13 +64,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
-  --> $DIR/empty-match.rs:79:20
+  --> $DIR/empty-match.rs:111:20
    |
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
    |
 note: `NonEmptyStruct1` defined here
-  --> $DIR/empty-match.rs:14:8
+  --> $DIR/empty-match.rs:15:8
    |
 LL | struct NonEmptyStruct1;
    |        ^^^^^^^^^^^^^^^
@@ -64,13 +78,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
-  --> $DIR/empty-match.rs:80:20
+  --> $DIR/empty-match.rs:113:20
    |
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
    |
 note: `NonEmptyStruct2` defined here
-  --> $DIR/empty-match.rs:15:8
+  --> $DIR/empty-match.rs:18:8
    |
 LL | struct NonEmptyStruct2(bool);
    |        ^^^^^^^^^^^^^^^
@@ -78,13 +92,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/empty-match.rs:81:20
+  --> $DIR/empty-match.rs:115:20
    |
 LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `NonEmptyUnion1` defined here
-  --> $DIR/empty-match.rs:16:7
+  --> $DIR/empty-match.rs:21:7
    |
 LL | union NonEmptyUnion1 {
    |       ^^^^^^^^^^^^^^
@@ -92,13 +106,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/empty-match.rs:82:20
+  --> $DIR/empty-match.rs:117:20
    |
 LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `NonEmptyUnion2` defined here
-  --> $DIR/empty-match.rs:19:7
+  --> $DIR/empty-match.rs:26:7
    |
 LL | union NonEmptyUnion2 {
    |       ^^^^^^^^^^^^^^
@@ -106,13 +120,13 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:83:20
+  --> $DIR/empty-match.rs:119:20
    |
 LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
    |
 note: `NonEmptyEnum1` defined here
-  --> $DIR/empty-match.rs:24:5
+  --> $DIR/empty-match.rs:33:5
    |
 LL | enum NonEmptyEnum1 {
    |      -------------
@@ -122,31 +136,32 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:84:20
+  --> $DIR/empty-match.rs:122:20
    |
 LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
    |
 note: `NonEmptyEnum2` defined here
-  --> $DIR/empty-match.rs:27:5
+  --> $DIR/empty-match.rs:40:5
    |
 LL | enum NonEmptyEnum2 {
    |      -------------
 LL |     Foo(bool),
    |     ^^^ not covered
+...
 LL |     Bar,
    |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:85:20
+  --> $DIR/empty-match.rs:125:20
    |
 LL |     match_no_arms!(NonEmptyEnum5::V1);
    |                    ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
    |
 note: `NonEmptyEnum5` defined here
-  --> $DIR/empty-match.rs:30:6
+  --> $DIR/empty-match.rs:49:6
    |
 LL | enum NonEmptyEnum5 {
    |      ^^^^^^^^^^^^^
@@ -154,7 +169,7 @@
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/empty-match.rs:87:24
+  --> $DIR/empty-match.rs:129:24
    |
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `_` not covered
@@ -167,13 +182,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
-  --> $DIR/empty-match.rs:88:24
+  --> $DIR/empty-match.rs:133:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
    |
 note: `NonEmptyStruct1` defined here
-  --> $DIR/empty-match.rs:14:8
+  --> $DIR/empty-match.rs:15:8
    |
 LL | struct NonEmptyStruct1;
    |        ^^^^^^^^^^^^^^^
@@ -185,13 +200,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
-  --> $DIR/empty-match.rs:89:24
+  --> $DIR/empty-match.rs:137:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
    |
 note: `NonEmptyStruct2` defined here
-  --> $DIR/empty-match.rs:15:8
+  --> $DIR/empty-match.rs:18:8
    |
 LL | struct NonEmptyStruct2(bool);
    |        ^^^^^^^^^^^^^^^
@@ -203,13 +218,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/empty-match.rs:90:24
+  --> $DIR/empty-match.rs:141:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
    |
 note: `NonEmptyUnion1` defined here
-  --> $DIR/empty-match.rs:16:7
+  --> $DIR/empty-match.rs:21:7
    |
 LL | union NonEmptyUnion1 {
    |       ^^^^^^^^^^^^^^
@@ -221,13 +236,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/empty-match.rs:91:24
+  --> $DIR/empty-match.rs:145:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
    |
 note: `NonEmptyUnion2` defined here
-  --> $DIR/empty-match.rs:19:7
+  --> $DIR/empty-match.rs:26:7
    |
 LL | union NonEmptyUnion2 {
    |       ^^^^^^^^^^^^^^
@@ -239,13 +254,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:92:24
+  --> $DIR/empty-match.rs:149:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
    |
 note: `NonEmptyEnum1` defined here
-  --> $DIR/empty-match.rs:24:5
+  --> $DIR/empty-match.rs:33:5
    |
 LL | enum NonEmptyEnum1 {
    |      -------------
@@ -259,18 +274,19 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:93:24
+  --> $DIR/empty-match.rs:153:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
    |
 note: `NonEmptyEnum2` defined here
-  --> $DIR/empty-match.rs:27:5
+  --> $DIR/empty-match.rs:40:5
    |
 LL | enum NonEmptyEnum2 {
    |      -------------
 LL |     Foo(bool),
    |     ^^^ not covered
+...
 LL |     Bar,
    |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
@@ -281,13 +297,13 @@
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:94:24
+  --> $DIR/empty-match.rs:157:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum5::V1);
    |                        ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
    |
 note: `NonEmptyEnum5` defined here
-  --> $DIR/empty-match.rs:30:6
+  --> $DIR/empty-match.rs:49:6
    |
 LL | enum NonEmptyEnum5 {
    |      ^^^^^^^^^^^^^
@@ -298,6 +314,7 @@
 LL +             _ => todo!()
    |
 
-error: aborting due to 22 previous errors
+error: aborting due to 23 previous errors
 
-For more information about this error, try `rustc --explain E0004`.
+Some errors have detailed explanations: E0004, E0005.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.rs b/tests/ui/pattern/usefulness/empty-match.rs
index 9cdc041..062241f 100644
--- a/tests/ui/pattern/usefulness/empty-match.rs
+++ b/tests/ui/pattern/usefulness/empty-match.rs
@@ -6,28 +6,49 @@
 #![feature(never_type_fallback)]
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
 #![deny(unreachable_patterns)]
+//~^ NOTE the lint level is defined here
 
 extern crate empty;
 
 enum EmptyEnum {}
 
 struct NonEmptyStruct1;
+//~^ NOTE `NonEmptyStruct1` defined here
+//~| NOTE `NonEmptyStruct1` defined here
 struct NonEmptyStruct2(bool);
+//~^ NOTE `NonEmptyStruct2` defined here
+//~| NOTE `NonEmptyStruct2` defined here
 union NonEmptyUnion1 {
+    //~^ NOTE `NonEmptyUnion1` defined here
+    //~| NOTE `NonEmptyUnion1` defined here
     foo: (),
 }
 union NonEmptyUnion2 {
+    //~^ NOTE `NonEmptyUnion2` defined here
+    //~| NOTE `NonEmptyUnion2` defined here
     foo: (),
     bar: (),
 }
 enum NonEmptyEnum1 {
     Foo(bool),
+    //~^ NOTE `NonEmptyEnum1` defined here
+    //~| NOTE `NonEmptyEnum1` defined here
+    //~| NOTE not covered
+    //~| NOTE not covered
 }
 enum NonEmptyEnum2 {
     Foo(bool),
+    //~^ NOTE `NonEmptyEnum2` defined here
+    //~| NOTE `NonEmptyEnum2` defined here
+    //~| NOTE not covered
+    //~| NOTE not covered
     Bar,
+    //~^ NOTE not covered
+    //~| NOTE not covered
 }
 enum NonEmptyEnum5 {
+    //~^ NOTE `NonEmptyEnum5` defined here
+    //~| NOTE `NonEmptyEnum5` defined here
     V1, V2, V3, V4, V5,
 }
 
@@ -51,6 +72,16 @@ fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
     }
 }
 
+fn empty_foreign_enum_private(x: Option<empty::SecretlyUninhabitedForeignStruct>) {
+    let None = x;
+    //~^ ERROR refutable pattern in local binding
+    //~| NOTE `let` bindings require an "irrefutable pattern"
+    //~| NOTE for more information, visit
+    //~| NOTE the matched value is of type
+    //~| NOTE pattern `Some(_)` not covered
+    //[exhaustive_patterns]~| NOTE currently uninhabited, but this variant contains private fields
+}
+
 fn never(x: !) {
     match x {} // ok
     match x {
@@ -76,20 +107,55 @@ macro_rules! match_guarded_arm {
 
 fn main() {
     match_no_arms!(0u8); //~ ERROR type `u8` is non-empty
+                         //~| NOTE the matched value is of type
     match_no_arms!(NonEmptyStruct1); //~ ERROR type `NonEmptyStruct1` is non-empty
+                                     //~| NOTE the matched value is of type
     match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty
+                                           //~| NOTE the matched value is of type
     match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty
+                                                  //~| NOTE the matched value is of type
     match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty
+                                                  //~| NOTE the matched value is of type
     match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
+                                              //~| NOTE pattern `NonEmptyEnum1::Foo(_)` not covered
+                                              //~| NOTE the matched value is of type
     match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+                                              //~| NOTE patterns `NonEmptyEnum2::Foo(_)` and
+                                              //~| NOTE the matched value is of type
     match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+                                       //~| NOTE patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`
+                                       //~| NOTE the matched value is of type
 
     match_guarded_arm!(0u8); //~ ERROR `_` not covered
+                             //~| NOTE the matched value is of type
+                             //~| NOTE pattern `_` not covered
+                             //~| NOTE in this expansion of match_guarded_arm!
     match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered
+                                         //~| NOTE pattern `NonEmptyStruct1` not covered
+                                         //~| NOTE the matched value is of type
+                                         //~| NOTE in this expansion of match_guarded_arm!
     match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered
+                                               //~| NOTE the matched value is of type
+                                               //~| NOTE pattern `NonEmptyStruct2(_)` not covered
+                                               //~| NOTE in this expansion of match_guarded_arm!
     match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered
+                                                      //~| NOTE the matched value is of type
+                                                      //~| NOTE pattern `NonEmptyUnion1 { .. }` not covered
+                                                      //~| NOTE in this expansion of match_guarded_arm!
     match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered
+                                                      //~| NOTE the matched value is of type
+                                                      //~| NOTE pattern `NonEmptyUnion2 { .. }` not covered
+                                                      //~| NOTE in this expansion of match_guarded_arm!
     match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
+                                                  //~| NOTE the matched value is of type
+                                                  //~| NOTE pattern `NonEmptyEnum1::Foo(_)` not covered
+                                                  //~| NOTE in this expansion of match_guarded_arm!
     match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+                                                  //~| NOTE the matched value is of type
+                                                  //~| NOTE patterns `NonEmptyEnum2::Foo(_)` and
+                                                  //~| NOTE in this expansion of match_guarded_arm!
     match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+                                           //~| NOTE the matched value is of type
+                                           //~| NOTE patterns `NonEmptyEnum5::V1`,
+                                           //~| NOTE in this expansion of match_guarded_arm!
 }
diff --git a/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs
new file mode 100644
index 0000000..f413b50
--- /dev/null
+++ b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs
@@ -0,0 +1,33 @@
+mod b {
+    pub struct A(u32);
+}
+
+trait Id {
+    type Assoc;
+}
+impl Id for b::A {
+    type Assoc = b::A;
+}
+impl Id for u32 {
+    type Assoc = u32;
+}
+
+
+trait Trait<T> {
+    fn method(&self)
+    where
+        T: Id<Assoc = b::A>;
+}
+
+impl<T: Id> Trait<T> for <T as Id>::Assoc {
+    fn method(&self)
+    where
+        T: Id<Assoc = b::A>,
+    {
+        let Self(a) = self;
+        //~^ ERROR: tuple struct constructor `A` is private
+        println!("{a}");
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr
new file mode 100644
index 0000000..231a4da
--- /dev/null
+++ b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr
@@ -0,0 +1,9 @@
+error[E0603]: tuple struct constructor `A` is private
+  --> $DIR/issue-111220-2-tuple-struct-fields-projection.rs:27:13
+   |
+LL |         let Self(a) = self;
+   |             ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/tests/ui/privacy/issue-111220-tuple-struct-fields.rs b/tests/ui/privacy/issue-111220-tuple-struct-fields.rs
new file mode 100644
index 0000000..78d35fd
--- /dev/null
+++ b/tests/ui/privacy/issue-111220-tuple-struct-fields.rs
@@ -0,0 +1,46 @@
+mod b {
+    #[derive(Default)]
+    pub struct A(u32);
+}
+
+impl b::A {
+    fn inherent_bypass(&self) {
+        let Self(x) = self;
+        //~^ ERROR: tuple struct constructor `A` is private
+        println!("{x}");
+    }
+}
+
+pub trait B {
+    fn f(&self);
+}
+
+impl B for b::A {
+    fn f(&self) {
+        let Self(a) = self;
+        //~^ ERROR: tuple struct constructor `A` is private
+        println!("{}", a);
+    }
+}
+
+pub trait Projector {
+    type P;
+}
+
+impl Projector for () {
+    type P = b::A;
+}
+
+pub trait Bypass2 {
+    fn f2(&self);
+}
+
+impl Bypass2 for <() as Projector>::P {
+    fn f2(&self) {
+        let Self(a) = self;
+        //~^ ERROR: tuple struct constructor `A` is private
+        println!("{}", a);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr b/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr
new file mode 100644
index 0000000..17a3237
--- /dev/null
+++ b/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr
@@ -0,0 +1,21 @@
+error[E0603]: tuple struct constructor `A` is private
+  --> $DIR/issue-111220-tuple-struct-fields.rs:8:13
+   |
+LL |         let Self(x) = self;
+   |             ^^^^^^^
+
+error[E0603]: tuple struct constructor `A` is private
+  --> $DIR/issue-111220-tuple-struct-fields.rs:20:13
+   |
+LL |         let Self(a) = self;
+   |             ^^^^^^^
+
+error[E0603]: tuple struct constructor `A` is private
+  --> $DIR/issue-111220-tuple-struct-fields.rs:40:13
+   |
+LL |         let Self(a) = self;
+   |             ^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/tests/ui/resolve/hidden_glob_reexports.rs b/tests/ui/resolve/hidden_glob_reexports.rs
new file mode 100644
index 0000000..361243f
--- /dev/null
+++ b/tests/ui/resolve/hidden_glob_reexports.rs
@@ -0,0 +1,52 @@
+// check-pass
+
+pub mod upstream_a {
+    mod inner {
+        pub struct Foo {}
+        pub struct Bar {}
+    }
+
+    pub use self::inner::*;
+
+    struct Foo;
+    //~^ WARN private item shadows public glob re-export
+}
+
+pub mod upstream_b {
+    mod inner {
+        pub struct Foo {}
+        pub struct Qux {}
+    }
+
+    mod other {
+        pub struct Foo;
+    }
+
+    pub use self::inner::*;
+
+    use self::other::Foo;
+    //~^ WARN private item shadows public glob re-export
+}
+
+pub mod upstream_c {
+    mod no_def_id {
+        #![allow(non_camel_case_types)]
+        pub struct u8;
+        pub struct World;
+    }
+
+    pub use self::no_def_id::*;
+
+    use std::primitive::u8;
+    //~^ WARN private item shadows public glob re-export
+}
+
+// Downstream crate
+// mod downstream {
+//     fn proof() {
+//         let _ = crate::upstream_a::Foo;
+//         let _ = crate::upstream_b::Foo;
+//     }
+// }
+
+pub fn main() {}
diff --git a/tests/ui/resolve/hidden_glob_reexports.stderr b/tests/ui/resolve/hidden_glob_reexports.stderr
new file mode 100644
index 0000000..ddf7bcd
--- /dev/null
+++ b/tests/ui/resolve/hidden_glob_reexports.stderr
@@ -0,0 +1,31 @@
+warning: private item shadows public glob re-export
+  --> $DIR/hidden_glob_reexports.rs:11:5
+   |
+LL |     pub use self::inner::*;
+   |             -------------- the name `Foo` in the type namespace is supposed to be publicly re-exported here
+LL |
+LL |     struct Foo;
+   |     ^^^^^^^^^^^ but the private item here shadows it
+   |
+   = note: `#[warn(hidden_glob_reexports)]` on by default
+
+warning: private item shadows public glob re-export
+  --> $DIR/hidden_glob_reexports.rs:27:9
+   |
+LL |     pub use self::inner::*;
+   |             -------------- the name `Foo` in the type namespace is supposed to be publicly re-exported here
+LL |
+LL |     use self::other::Foo;
+   |         ^^^^^^^^^^^^^^^^ but the private item here shadows it
+
+warning: private item shadows public glob re-export
+  --> $DIR/hidden_glob_reexports.rs:40:9
+   |
+LL |     pub use self::no_def_id::*;
+   |             ------------------ the name `u8` in the type namespace is supposed to be publicly re-exported here
+LL |
+LL |     use std::primitive::u8;
+   |         ^^^^^^^^^^^^^^^^^^ but the private item here shadows it
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
index a6c8631..e7f7fdc 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
@@ -2,7 +2,7 @@
 
 trait One<A> { fn foo(&self) -> A; }
 
-fn foo(_: &dyn One()) //~ ERROR associated type `Output` not found for `One<()>`
+fn foo(_: &dyn One()) //~ ERROR associated type `Output` not found for `One`
 {}
 
 fn main() { }
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr
index 59e7bc8..e477247 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr
@@ -1,4 +1,4 @@
-error[E0220]: associated type `Output` not found for `One<()>`
+error[E0220]: associated type `Output` not found for `One`
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs:5:16
    |
 LL | fn foo(_: &dyn One())
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
index 5d7fe3f..eb18b12 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
@@ -12,7 +12,7 @@
 LL | trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); }
    |       ^^^^^ - - -
 
-error[E0220]: associated type `Output` not found for `Three<(), [type error], [type error]>`
+error[E0220]: associated type `Output` not found for `Three`
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16
    |
 LL | fn foo(_: &dyn Three())
diff --git a/triagebot.toml b/triagebot.toml
index d7cd3ea..c160c83 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -190,6 +190,7 @@
     "src/stage0.json",
     "src/tools/compiletest",
     "src/tools/tidy",
+    "src/tools/rustdoc-gui-test",
 ]
 
 [autolabel."T-infra"]
@@ -640,3 +641,4 @@
 "/src/tools/rustdoc-themes" =                ["rustdoc"]
 "/src/tools/tidy" =                          ["bootstrap"]
 "/src/tools/x" =                             ["bootstrap"]
+"/src/tools/rustdoc-gui-test" =              ["bootstrap", "@ozkanonur"]