about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_abi/src/lib.rs9
-rw-r--r--compiler/rustc_ast/src/ast.rs6
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs2
-rw-r--r--compiler/rustc_ast/src/util/literal.rs12
-rw-r--r--compiler/rustc_ast/src/visit.rs2
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl4
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs39
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs370
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs5
-rw-r--r--compiler/rustc_borrowck/src/nll.rs5
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs104
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs5
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs9
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0708.md6
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/base.rs56
-rw-r--r--compiler/rustc_expand/src/errors.rs7
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs1
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs7
-rw-r--r--compiler/rustc_hir/src/intravisit.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs64
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs79
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs48
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs39
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs46
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs134
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs32
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/test.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs13
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs82
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs160
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs33
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs10
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs11
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs21
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs26
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs15
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs90
-rw-r--r--compiler/rustc_interface/src/interface.rs4
-rw-r--r--compiler/rustc_interface/src/tests.rs9
-rw-r--r--compiler/rustc_lexer/src/unescape.rs17
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs11
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs4
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs29
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs58
-rw-r--r--compiler/rustc_middle/src/query/erase.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs27
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs12
-rw-r--r--compiler/rustc_middle/src/traits/query.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs156
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs81
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs181
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs5
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs3
-rw-r--r--compiler/rustc_passes/src/dead.rs5
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs6
-rw-r--r--compiler/rustc_pattern_analysis/Cargo.toml1
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs11
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs42
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs6
-rw-r--r--compiler/rustc_session/messages.ftl2
-rw-r--r--compiler/rustc_session/src/config.rs32
-rw-r--r--compiler/rustc_session/src/errors.rs15
-rw-r--r--compiler/rustc_session/src/options.rs19
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs122
-rw-r--r--compiler/rustc_span/src/hygiene.rs19
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/spec/base/freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs210
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs82
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs18
-rw-r--r--library/alloc/src/vec/in_place_collect.rs2
-rw-r--r--library/unwind/src/lib.rs8
-rw-r--r--src/bootstrap/bootstrap.py13
-rw-r--r--src/bootstrap/src/core/builder.rs19
-rw-r--r--src/doc/rustc/src/target-tier-policy.md2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/check-cfg.md25
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/librustdoc/clean/utils.rs4
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs3
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs98
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs9
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout6
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/validation.rs3
-rw-r--r--src/tools/rustfmt/src/patterns.rs9
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs1
-rw-r--r--src/tools/tidy/src/target_policy.rs52
-rw-r--r--tests/assembly/targets/targets-elf.rs633
-rw-r--r--tests/assembly/targets/targets-nvptx.rs21
-rw-r--r--tests/assembly/targets/targets-pe.rs93
-rw-r--r--tests/debuginfo/collapse-debuginfo-external-attr.rs31
-rw-r--r--tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs34
-rw-r--r--tests/debuginfo/collapse-debuginfo-external-flag.rs26
-rw-r--r--tests/debuginfo/collapse-debuginfo-no-attr.rs2
-rw-r--r--tests/debuginfo/collapse-debuginfo-with-yes-flag.rs57
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/const_prop/boolean_identities.rs7
-rw-r--r--tests/mir-opt/const_prop/boolean_identities.test.GVN.diff12
-rw-r--r--tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff9
-rw-r--r--tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff9
-rw-r--r--tests/mir-opt/const_prop/boxes.rs2
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/const_prop/mult_by_zero.rs3
-rw-r--r--tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff2
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff7
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff7
-rw-r--r--tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff357
-rw-r--r--tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff357
-rw-r--r--tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff101
-rw-r--r--tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff101
-rw-r--r--tests/mir-opt/gvn.comparison.GVN.panic-abort.diff10
-rw-r--r--tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff10
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff18
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff18
-rw-r--r--tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff13
-rw-r--r--tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff13
-rw-r--r--tests/mir-opt/gvn.rs128
-rw-r--r--tests/mir-opt/gvn.unary.GVN.panic-abort.diff153
-rw-r--r--tests/mir-opt/gvn.unary.GVN.panic-unwind.diff153
-rw-r--r--tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff386
-rw-r--r--tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff386
-rw-r--r--tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff17
-rw-r--r--tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff17
-rw-r--r--tests/rustdoc-ui/error-in-impl-trait/README.md2
-rw-r--r--tests/ui-fulldeps/stable-mir/check_abi.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/check_allocation.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/check_defs.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/check_instance.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/check_item_kind.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/check_trait_queries.rs4
-rw-r--r--tests/ui-fulldeps/stable-mir/check_ty_fold.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/compilation-result.rs20
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/projections.rs6
-rw-r--r--tests/ui-fulldeps/stable-mir/smir_internal.rs4
-rw-r--r--tests/ui-fulldeps/stable-mir/smir_visitor.rs6
-rw-r--r--tests/ui/associated-inherent-types/issue-111404-1.rs1
-rw-r--r--tests/ui/associated-inherent-types/issue-111404-1.stderr10
-rw-r--r--tests/ui/async-await/async-borrowck-escaping-closure-error.rs3
-rw-r--r--tests/ui/async-await/async-borrowck-escaping-closure-error.stderr21
-rw-r--r--tests/ui/async-await/inference_var_self_argument.rs12
-rw-r--r--tests/ui/async-await/inference_var_self_argument.stderr28
-rw-r--r--tests/ui/async-await/no-params-non-move-async-closure.rs2
-rw-r--r--tests/ui/async-await/no-params-non-move-async-closure.stderr11
-rw-r--r--tests/ui/check-cfg/cargo-feature.none.stderr20
-rw-r--r--tests/ui/check-cfg/cargo-feature.rs9
-rw-r--r--tests/ui/check-cfg/cargo-feature.some.stderr7
-rw-r--r--tests/ui/check-cfg/concat-values.rs4
-rw-r--r--tests/ui/check-cfg/concat-values.stderr4
-rw-r--r--tests/ui/check-cfg/empty-values.rs14
-rw-r--r--tests/ui/check-cfg/empty-values.stderr23
-rw-r--r--tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr2
-rw-r--r--tests/ui/closures/print/closure-print-generic-verbose-2.stderr2
-rw-r--r--tests/ui/closures/print/closure-print-verbose.stderr2
-rw-r--r--tests/ui/consts/const-eval/infinite_loop.rs10
-rw-r--r--tests/ui/consts/const-eval/infinite_loop.stderr6
-rw-r--r--tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr26
-rw-r--r--tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs21
-rw-r--r--tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr78
-rw-r--r--tests/ui/implied-bounds/auxiliary/bevy_ecs.rs18
-rw-r--r--tests/ui/implied-bounds/bevy_world_query.rs23
-rw-r--r--tests/ui/implied-bounds/from-trait-impl.rs5
-rw-r--r--tests/ui/implied-bounds/from-trait-impl.stderr26
-rw-r--r--tests/ui/implied-bounds/gluon_salsa.rs5
-rw-r--r--tests/ui/implied-bounds/normalization-nested.lifetime.stderr33
-rw-r--r--tests/ui/implied-bounds/normalization-nested.rs5
-rw-r--r--tests/ui/implied-bounds/sod_service_chain.rs6
-rw-r--r--tests/ui/implied-bounds/sod_service_chain.stderr31
-rw-r--r--tests/ui/inference/issue-80409.rs10
-rw-r--r--tests/ui/inference/issue-80409.stderr6
-rw-r--r--tests/ui/object-safety/erroneous_signature.rs17
-rw-r--r--tests/ui/object-safety/erroneous_signature.stderr15
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr14
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rsbin738 -> 1906 bytes
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderrbin674 -> 2028 bytes
-rw-r--r--tests/ui/type-alias-impl-trait/closure_infer.rs35
-rw-r--r--tests/ui/type-alias-impl-trait/issue-77179.rs5
-rw-r--r--tests/ui/type-alias-impl-trait/issue-77179.stderr11
-rw-r--r--triagebot.toml2
237 files changed, 5335 insertions, 1841 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 92dd45cf520..f5ce875ccd4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4355,6 +4355,7 @@ name = "rustc_pattern_analysis"
 version = "0.0.0"
 dependencies = [
  "derivative",
+ "rustc-hash",
  "rustc_apfloat",
  "rustc_arena",
  "rustc_data_structures",
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index ea194e10def..c45a4a410f9 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -49,7 +49,14 @@ bitflags! {
                                  | ReprFlags::IS_LINEAR.bits();
     }
 }
-rustc_data_structures::external_bitflags_debug! { ReprFlags }
+
+// This is the same as `rustc_data_structures::external_bitflags_debug` but without the
+// `rustc_data_structures` to make it build on stable.
+impl std::fmt::Debug for ReprFlags {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        bitflags::parser::to_writer(self, f)
+    }
+}
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 #[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 21077c312bd..d0d98eb3d62 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -625,7 +625,8 @@ impl Pat {
             | PatKind::Range(..)
             | PatKind::Ident(..)
             | PatKind::Path(..)
-            | PatKind::MacCall(_) => {}
+            | PatKind::MacCall(_)
+            | PatKind::Err(_) => {}
         }
     }
 
@@ -809,6 +810,9 @@ pub enum PatKind {
 
     /// A macro pattern; pre-expansion.
     MacCall(P<MacCall>),
+
+    /// Placeholder for a pattern that wasn't syntactically well formed in some way.
+    Err(ErrorGuaranteed),
 }
 
 /// Whether the `..` is present in a struct fields pattern.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 450555d0cb5..90677151d25 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1267,7 +1267,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
     let Pat { id, kind, span, tokens } = pat.deref_mut();
     vis.visit_id(id);
     match kind {
-        PatKind::Wild | PatKind::Rest | PatKind::Never => {}
+        PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
         PatKind::Ident(_binding_mode, ident, sub) => {
             vis.visit_ident(ident);
             visit_opt(sub, |sub| vis.visit_pat(sub));
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 92b9adf1db7..fbae4964588 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -8,7 +8,6 @@ use rustc_lexer::unescape::{
 };
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
-use std::ops::Range;
 use std::{ascii, fmt, str};
 
 // Escapes a string, represented as a symbol. Reuses the original symbol,
@@ -39,7 +38,6 @@ pub enum LitError {
     InvalidFloatSuffix,
     NonDecimalFloat(u32),
     IntTooLarge(u32),
-    NulInCStr(Range<usize>),
 }
 
 impl LitKind {
@@ -156,10 +154,7 @@ impl LitKind {
                 let s = symbol.as_str();
                 let mut buf = Vec::with_capacity(s.len());
                 let mut error = Ok(());
-                unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
-                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
-                        error = Err(LitError::NulInCStr(span));
-                    }
+                unescape_c_string(s, Mode::CStr, &mut |_span, c| match c {
                     Ok(CStrUnit::Byte(b)) => buf.push(b),
                     Ok(CStrUnit::Char(c)) => {
                         buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
@@ -179,10 +174,7 @@ impl LitKind {
                 // can convert the symbol directly to a `Lrc<u8>` on success.
                 let s = symbol.as_str();
                 let mut error = Ok(());
-                unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
-                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
-                        error = Err(LitError::NulInCStr(span));
-                    }
+                unescape_c_string(s, Mode::RawCStr, &mut |_, c| match c {
                     Ok(_) => {}
                     Err(err) => {
                         if err.is_fatal() {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 3617df931e2..89f50d3a0a7 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -568,7 +568,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
             walk_list!(visitor, visit_expr, lower_bound);
             walk_list!(visitor, visit_expr, upper_bound);
         }
-        PatKind::Wild | PatKind::Rest | PatKind::Never => {}
+        PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
         PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
             walk_list!(visitor, visit_pat, elems);
         }
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index e7177402db1..8615016cda5 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -14,10 +14,6 @@ ast_lowering_assoc_ty_parentheses =
 ast_lowering_async_coroutines_not_supported =
     `async` coroutines 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
 
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 2811fe104cd..4843d36372d 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -146,14 +146,6 @@ pub struct ClosureCannotBeStatic {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[help]
-#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")]
-pub struct AsyncNonMoveClosureNotSupported {
-    #[primary_span]
-    pub fn_decl_span: Span,
-}
-
-#[derive(Diagnostic, Clone, Copy)]
 #[diag(ast_lowering_functional_record_update_destructuring_assignment)]
 pub struct FunctionalRecordUpdateDestructuringAssignment {
     #[primary_span]
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index e0b1a10c82e..0920de48eb8 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1,6 +1,6 @@
 use super::errors::{
-    AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
-    BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
+    AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
+    ClosureCannotBeStatic, CoroutineTooManyParameters,
     FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
     NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
     UnderscoreExprLhsAssign,
@@ -13,7 +13,6 @@ use rustc_ast::*;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_middle::span_bug;
 use rustc_session::errors::report_lit_error;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1028,28 +1027,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         fn_decl_span: Span,
         fn_arg_span: Span,
     ) -> hir::ExprKind<'hir> {
-        let CoroutineKind::Async { closure_id: inner_closure_id, .. } = coroutine_kind else {
-            span_bug!(fn_decl_span, "`async gen` and `gen` closures are not supported, yet");
-        };
-
         if let &ClosureBinder::For { span, .. } = binder {
             self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
         }
 
         let (binder_clause, generic_params) = self.lower_closure_binder(binder);
 
-        let outer_decl =
-            FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
-
         let body = self.with_new_scopes(fn_decl_span, |this| {
-            // FIXME(cramertj): allow `async` non-`move` closures with arguments.
-            if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
-                this.dcx().emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
-            }
-
             // Transform `async |x: u8| -> X { ... }` into
             // `|x: u8| || -> X { ... }`.
-            let body_id = this.lower_fn_body(&outer_decl, |this| {
+            let body_id = this.lower_body(|this| {
                 let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
                     let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
                     Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
@@ -1057,22 +1044,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     None
                 };
 
-                let async_body = this.make_desugared_coroutine_expr(
-                    capture_clause,
-                    inner_closure_id,
-                    async_ret_ty,
+                let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
+                    decl,
+                    |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
                     body.span,
-                    hir::CoroutineDesugaring::Async,
+                    coroutine_kind,
                     hir::CoroutineSource::Closure,
-                    |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
+                    async_ret_ty,
                 );
-                let hir_id = this.lower_node_id(inner_closure_id);
+
+                let hir_id = this.lower_node_id(coroutine_kind.closure_id());
                 this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
-                hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) }
+
+                (parameters, expr)
             });
             body_id
         });
 
+        let outer_decl =
+            FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
+
         let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
         // We need to lower the declaration outside the new scope, because we
         // have to conserve the state of being inside a loop condition for the
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a3ff02f5f69..dd3f7289a60 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1082,194 +1082,224 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
             return self.lower_fn_body_block(span, decl, body);
         };
-        let closure_id = coroutine_kind.closure_id();
-
         self.lower_body(|this| {
-            let mut parameters: Vec<hir::Param<'_>> = Vec::new();
-            let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
-
-            // Async function parameters are lowered into the closure body so that they are
-            // captured and so that the drop order matches the equivalent non-async functions.
-            //
-            // from:
-            //
-            //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
-            //         <body>
-            //     }
-            //
-            // into:
-            //
-            //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
-            //       async move {
-            //         let __arg2 = __arg2;
-            //         let <pattern> = __arg2;
-            //         let __arg1 = __arg1;
-            //         let <pattern> = __arg1;
-            //         let __arg0 = __arg0;
-            //         let <pattern> = __arg0;
-            //         drop-temps { <body> } // see comments later in fn for details
-            //       }
-            //     }
-            //
-            // If `<pattern>` is a simple ident, then it is lowered to a single
-            // `let <pattern> = <pattern>;` statement as an optimization.
-            //
-            // Note that the body is embedded in `drop-temps`; an
-            // equivalent desugaring would be `return { <body>
-            // };`. The key point is that we wish to drop all the
-            // let-bound variables and temporaries created in the body
-            // (and its tail expression!) before we drop the
-            // parameters (c.f. rust-lang/rust#64512).
-            for (index, parameter) in decl.inputs.iter().enumerate() {
-                let parameter = this.lower_param(parameter);
-                let span = parameter.pat.span;
-
-                // Check if this is a binding pattern, if so, we can optimize and avoid adding a
-                // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
-                let (ident, is_simple_parameter) = match parameter.pat.kind {
-                    hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
-                        (ident, true)
-                    }
-                    // For `ref mut` or wildcard arguments, we can't reuse the binding, but
-                    // we can keep the same name for the parameter.
-                    // This lets rustdoc render it correctly in documentation.
-                    hir::PatKind::Binding(_, _, ident, _) => (ident, false),
-                    hir::PatKind::Wild => {
-                        (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
-                    }
-                    _ => {
-                        // Replace the ident for bindings that aren't simple.
-                        let name = format!("__arg{index}");
-                        let ident = Ident::from_str(&name);
-
-                        (ident, false)
-                    }
-                };
-
-                let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None);
-
-                // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
-                // async function.
-                //
-                // If this is the simple case, this parameter will end up being the same as the
-                // original parameter, but with a different pattern id.
-                let stmt_attrs = this.attrs.get(&parameter.hir_id.local_id).copied();
-                let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
-                let new_parameter = hir::Param {
-                    hir_id: parameter.hir_id,
-                    pat: new_parameter_pat,
-                    ty_span: this.lower_span(parameter.ty_span),
-                    span: this.lower_span(parameter.span),
-                };
+            let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
+                decl,
+                |this| this.lower_block_expr(body),
+                body.span,
+                coroutine_kind,
+                hir::CoroutineSource::Fn,
+                None,
+            );
 
-                if is_simple_parameter {
-                    // If this is the simple case, then we only insert one statement that is
-                    // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
-                    // `HirId`s are densely assigned.
-                    let expr = this.expr_ident(desugared_span, ident, new_parameter_id);
-                    let stmt = this.stmt_let_pat(
-                        stmt_attrs,
-                        desugared_span,
-                        Some(expr),
-                        parameter.pat,
-                        hir::LocalSource::AsyncFn,
-                    );
-                    statements.push(stmt);
-                } else {
-                    // If this is not the simple case, then we construct two statements:
-                    //
-                    // ```
-                    // let __argN = __argN;
-                    // let <pat> = __argN;
-                    // ```
-                    //
-                    // The first statement moves the parameter into the closure and thus ensures
-                    // that the drop order is correct.
-                    //
-                    // The second statement creates the bindings that the user wrote.
-
-                    // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
-                    // because the user may have specified a `ref mut` binding in the next
-                    // statement.
-                    let (move_pat, move_id) = this.pat_ident_binding_mode(
-                        desugared_span,
-                        ident,
-                        hir::BindingAnnotation::MUT,
-                    );
-                    let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
-                    let move_stmt = this.stmt_let_pat(
-                        None,
-                        desugared_span,
-                        Some(move_expr),
-                        move_pat,
-                        hir::LocalSource::AsyncFn,
-                    );
+            // FIXME(async_fn_track_caller): Can this be moved above?
+            let hir_id = this.lower_node_id(coroutine_kind.closure_id());
+            this.maybe_forward_track_caller(body.span, fn_id, hir_id);
 
-                    // Construct the `let <pat> = __argN;` statement. We re-use the original
-                    // parameter's pattern so that `HirId`s are densely assigned.
-                    let pattern_expr = this.expr_ident(desugared_span, ident, move_id);
-                    let pattern_stmt = this.stmt_let_pat(
-                        stmt_attrs,
-                        desugared_span,
-                        Some(pattern_expr),
-                        parameter.pat,
-                        hir::LocalSource::AsyncFn,
-                    );
+            (parameters, expr)
+        })
+    }
 
-                    statements.push(move_stmt);
-                    statements.push(pattern_stmt);
-                };
+    /// Lowers a desugared coroutine body after moving all of the arguments
+    /// into the body. This is to make sure that the future actually owns the
+    /// arguments that are passed to the function, and to ensure things like
+    /// drop order are stable.
+    pub fn lower_coroutine_body_with_moved_arguments(
+        &mut self,
+        decl: &FnDecl,
+        lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
+        body_span: Span,
+        coroutine_kind: CoroutineKind,
+        coroutine_source: hir::CoroutineSource,
+        return_type_hint: Option<hir::FnRetTy<'hir>>,
+    ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
+        let mut parameters: Vec<hir::Param<'_>> = Vec::new();
+        let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
+
+        // Async function parameters are lowered into the closure body so that they are
+        // captured and so that the drop order matches the equivalent non-async functions.
+        //
+        // from:
+        //
+        //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
+        //         <body>
+        //     }
+        //
+        // into:
+        //
+        //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
+        //       async move {
+        //         let __arg2 = __arg2;
+        //         let <pattern> = __arg2;
+        //         let __arg1 = __arg1;
+        //         let <pattern> = __arg1;
+        //         let __arg0 = __arg0;
+        //         let <pattern> = __arg0;
+        //         drop-temps { <body> } // see comments later in fn for details
+        //       }
+        //     }
+        //
+        // If `<pattern>` is a simple ident, then it is lowered to a single
+        // `let <pattern> = <pattern>;` statement as an optimization.
+        //
+        // Note that the body is embedded in `drop-temps`; an
+        // equivalent desugaring would be `return { <body>
+        // };`. The key point is that we wish to drop all the
+        // let-bound variables and temporaries created in the body
+        // (and its tail expression!) before we drop the
+        // parameters (c.f. rust-lang/rust#64512).
+        for (index, parameter) in decl.inputs.iter().enumerate() {
+            let parameter = self.lower_param(parameter);
+            let span = parameter.pat.span;
+
+            // Check if this is a binding pattern, if so, we can optimize and avoid adding a
+            // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
+            let (ident, is_simple_parameter) = match parameter.pat.kind {
+                hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
+                    (ident, true)
+                }
+                // For `ref mut` or wildcard arguments, we can't reuse the binding, but
+                // we can keep the same name for the parameter.
+                // This lets rustdoc render it correctly in documentation.
+                hir::PatKind::Binding(_, _, ident, _) => (ident, false),
+                hir::PatKind::Wild => {
+                    (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
+                }
+                _ => {
+                    // Replace the ident for bindings that aren't simple.
+                    let name = format!("__arg{index}");
+                    let ident = Ident::from_str(&name);
 
-                parameters.push(new_parameter);
-            }
+                    (ident, false)
+                }
+            };
 
-            let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
-                // Create a block from the user's function body:
-                let user_body = this.lower_block_expr(body);
+            let desugared_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-                // Transform into `drop-temps { <user-body> }`, an expression:
-                let desugared_span =
-                    this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
-                let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
+            // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
+            // async function.
+            //
+            // If this is the simple case, this parameter will end up being the same as the
+            // original parameter, but with a different pattern id.
+            let stmt_attrs = self.attrs.get(&parameter.hir_id.local_id).copied();
+            let (new_parameter_pat, new_parameter_id) = self.pat_ident(desugared_span, ident);
+            let new_parameter = hir::Param {
+                hir_id: parameter.hir_id,
+                pat: new_parameter_pat,
+                ty_span: self.lower_span(parameter.ty_span),
+                span: self.lower_span(parameter.span),
+            };
 
-                // As noted above, create the final block like
+            if is_simple_parameter {
+                // If this is the simple case, then we only insert one statement that is
+                // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
+                // `HirId`s are densely assigned.
+                let expr = self.expr_ident(desugared_span, ident, new_parameter_id);
+                let stmt = self.stmt_let_pat(
+                    stmt_attrs,
+                    desugared_span,
+                    Some(expr),
+                    parameter.pat,
+                    hir::LocalSource::AsyncFn,
+                );
+                statements.push(stmt);
+            } else {
+                // If this is not the simple case, then we construct two statements:
                 //
                 // ```
-                // {
-                //   let $param_pattern = $raw_param;
-                //   ...
-                //   drop-temps { <user-body> }
-                // }
+                // let __argN = __argN;
+                // let <pat> = __argN;
                 // ```
-                let body = this.block_all(
+                //
+                // The first statement moves the parameter into the closure and thus ensures
+                // that the drop order is correct.
+                //
+                // The second statement creates the bindings that the user wrote.
+
+                // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
+                // because the user may have specified a `ref mut` binding in the next
+                // statement.
+                let (move_pat, move_id) =
+                    self.pat_ident_binding_mode(desugared_span, ident, hir::BindingAnnotation::MUT);
+                let move_expr = self.expr_ident(desugared_span, ident, new_parameter_id);
+                let move_stmt = self.stmt_let_pat(
+                    None,
                     desugared_span,
-                    this.arena.alloc_from_iter(statements),
-                    Some(user_body),
+                    Some(move_expr),
+                    move_pat,
+                    hir::LocalSource::AsyncFn,
                 );
 
-                this.expr_block(body)
-            };
-            let desugaring_kind = match coroutine_kind {
-                CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
-                CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
-                CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
+                // Construct the `let <pat> = __argN;` statement. We re-use the original
+                // parameter's pattern so that `HirId`s are densely assigned.
+                let pattern_expr = self.expr_ident(desugared_span, ident, move_id);
+                let pattern_stmt = self.stmt_let_pat(
+                    stmt_attrs,
+                    desugared_span,
+                    Some(pattern_expr),
+                    parameter.pat,
+                    hir::LocalSource::AsyncFn,
+                );
+
+                statements.push(move_stmt);
+                statements.push(pattern_stmt);
             };
-            let coroutine_expr = this.make_desugared_coroutine_expr(
-                CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
-                closure_id,
-                None,
-                body.span,
-                desugaring_kind,
-                hir::CoroutineSource::Fn,
-                mkbody,
+
+            parameters.push(new_parameter);
+        }
+
+        let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
+            // Create a block from the user's function body:
+            let user_body = lower_body(this);
+
+            // Transform into `drop-temps { <user-body> }`, an expression:
+            let desugared_span =
+                this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
+            let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
+
+            // As noted above, create the final block like
+            //
+            // ```
+            // {
+            //   let $param_pattern = $raw_param;
+            //   ...
+            //   drop-temps { <user-body> }
+            // }
+            // ```
+            let body = this.block_all(
+                desugared_span,
+                this.arena.alloc_from_iter(statements),
+                Some(user_body),
             );
 
-            let hir_id = this.lower_node_id(closure_id);
-            this.maybe_forward_track_caller(body.span, fn_id, hir_id);
-            let expr = hir::Expr { hir_id, kind: coroutine_expr, span: this.lower_span(body.span) };
+            this.expr_block(body)
+        };
+        let desugaring_kind = match coroutine_kind {
+            CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
+            CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
+            CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
+        };
+        let closure_id = coroutine_kind.closure_id();
+        let coroutine_expr = self.make_desugared_coroutine_expr(
+            // FIXME(async_closures): This should only move locals,
+            // and not upvars. Capturing closure upvars by ref doesn't
+            // work right now anyways, so whatever.
+            CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
+            closure_id,
+            return_type_hint,
+            body_span,
+            desugaring_kind,
+            coroutine_source,
+            mkbody,
+        );
 
-            (this.arena.alloc_from_iter(parameters), expr)
-        })
+        let expr = hir::Expr {
+            hir_id: self.lower_node_id(closure_id),
+            kind: coroutine_expr,
+            span: self.lower_span(body_span),
+        };
+
+        (self.arena.alloc_from_iter(parameters), expr)
     }
 
     fn lower_method_sig(
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 1c405fac7e4..0af141ff99a 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -109,6 +109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // return inner to be processed in next loop
                     PatKind::Paren(inner) => pattern = inner,
                     PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
+                    PatKind::Err(guar) => break hir::PatKind::Err(*guar),
                 }
             };
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index f4b424259de..c2fd4558fd7 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1519,6 +1519,11 @@ impl<'a> State<'a> {
                 self.pclose();
             }
             PatKind::MacCall(m) => self.print_mac(m),
+            PatKind::Err(_) => {
+                self.popen();
+                self.word("/*ERROR*/");
+                self.pclose();
+            }
         }
         self.ann.post(self, AnnNode::Pat(pat))
     }
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 5b764495922..cc8208e9dc3 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
+use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_mir_dataflow::ResultsCursor;
 use rustc_span::symbol::sym;
 use std::env;
@@ -27,7 +28,7 @@ use crate::{
     facts::{AllFacts, AllFactsExt, RustcFacts},
     location::LocationTable,
     polonius,
-    region_infer::{values::RegionValueElements, RegionInferenceContext},
+    region_infer::RegionInferenceContext,
     renumber,
     type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
     universal_regions::UniversalRegions,
@@ -98,7 +99,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
 
     let universal_regions = Rc::new(universal_regions);
 
-    let elements = &Rc::new(RegionValueElements::new(body));
+    let elements = &Rc::new(DenseLocationMap::new(body));
 
     // Run the MIR type-checker.
     let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 948221e9407..cbf01feae06 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -19,6 +19,7 @@ use rustc_middle::mir::{
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
+use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_span::Span;
 
 use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
@@ -30,8 +31,7 @@ use crate::{
     nll::PoloniusOutput,
     region_infer::reverse_sccs::ReverseSccGraph,
     region_infer::values::{
-        LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
-        ToElementIndex,
+        LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
     },
     type_check::{free_region_relations::UniversalRegionRelations, Locations},
     universal_regions::UniversalRegions,
@@ -330,7 +330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
         liveness_constraints: LivenessValues,
-        elements: &Rc<RegionValueElements>,
+        elements: &Rc<DenseLocationMap>,
     ) -> Self {
         debug!("universal_regions: {:#?}", universal_regions);
         debug!("outlives constraints: {:#?}", outlives_constraints);
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index dc3ee849d00..01f7bfcadb6 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -5,97 +5,13 @@ use rustc_index::bit_set::SparseBitMatrix;
 use rustc_index::interval::IntervalSet;
 use rustc_index::interval::SparseIntervalMatrix;
 use rustc_index::Idx;
-use rustc_index::IndexVec;
-use rustc_middle::mir::{BasicBlock, Body, Location};
+use rustc_middle::mir::{BasicBlock, Location};
 use rustc_middle::ty::{self, RegionVid};
+use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
 use std::fmt::Debug;
 use std::rc::Rc;
 
-use crate::dataflow::BorrowIndex;
-
-/// Maps between a `Location` and a `PointIndex` (and vice versa).
-pub(crate) struct RegionValueElements {
-    /// For each basic block, how many points are contained within?
-    statements_before_block: IndexVec<BasicBlock, usize>,
-
-    /// Map backward from each point to the basic block that it
-    /// belongs to.
-    basic_blocks: IndexVec<PointIndex, BasicBlock>,
-
-    num_points: usize,
-}
-
-impl RegionValueElements {
-    pub(crate) fn new(body: &Body<'_>) -> Self {
-        let mut num_points = 0;
-        let statements_before_block: IndexVec<BasicBlock, usize> = body
-            .basic_blocks
-            .iter()
-            .map(|block_data| {
-                let v = num_points;
-                num_points += block_data.statements.len() + 1;
-                v
-            })
-            .collect();
-        debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block);
-        debug!("RegionValueElements: num_points={:#?}", num_points);
-
-        let mut basic_blocks = IndexVec::with_capacity(num_points);
-        for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
-            basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
-        }
-
-        Self { statements_before_block, basic_blocks, num_points }
-    }
-
-    /// Total number of point indices
-    pub(crate) fn num_points(&self) -> usize {
-        self.num_points
-    }
-
-    /// Converts a `Location` into a `PointIndex`. O(1).
-    pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
-        let Location { block, statement_index } = location;
-        let start_index = self.statements_before_block[block];
-        PointIndex::new(start_index + statement_index)
-    }
-
-    /// Converts a `Location` into a `PointIndex`. O(1).
-    pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex {
-        let start_index = self.statements_before_block[block];
-        PointIndex::new(start_index)
-    }
-
-    /// Return the PointIndex for the block start of this index.
-    pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex {
-        PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
-    }
-
-    /// Converts a `PointIndex` back to a location. O(1).
-    pub(crate) fn to_location(&self, index: PointIndex) -> Location {
-        assert!(index.index() < self.num_points);
-        let block = self.basic_blocks[index];
-        let start_index = self.statements_before_block[block];
-        let statement_index = index.index() - start_index;
-        Location { block, statement_index }
-    }
-
-    /// Sometimes we get point-indices back from bitsets that may be
-    /// out of range (because they round up to the nearest 2^N number
-    /// of bits). Use this function to filter such points out if you
-    /// like.
-    pub(crate) fn point_in_range(&self, index: PointIndex) -> bool {
-        index.index() < self.num_points
-    }
-}
-
-rustc_index::newtype_index! {
-    /// A single integer representing a `Location` in the MIR control-flow
-    /// graph. Constructed efficiently from `RegionValueElements`.
-    #[orderable]
-    #[debug_format = "PointIndex({})"]
-    pub struct PointIndex {}
-}
+use crate::BorrowIndex;
 
 rustc_index::newtype_index! {
     /// A single integer representing a `ty::Placeholder`.
@@ -123,7 +39,7 @@ pub(crate) enum RegionElement {
 /// an interval matrix storing liveness ranges for each region-vid.
 pub(crate) struct LivenessValues {
     /// The map from locations to points.
-    elements: Rc<RegionValueElements>,
+    elements: Rc<DenseLocationMap>,
 
     /// For each region: the points where it is live.
     points: SparseIntervalMatrix<RegionVid, PointIndex>,
@@ -155,9 +71,9 @@ impl LiveLoans {
 
 impl LivenessValues {
     /// Create an empty map of regions to locations where they're live.
-    pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
+    pub(crate) fn new(elements: Rc<DenseLocationMap>) -> Self {
         LivenessValues {
-            points: SparseIntervalMatrix::new(elements.num_points),
+            points: SparseIntervalMatrix::new(elements.num_points()),
             elements,
             loans: None,
         }
@@ -298,7 +214,7 @@ impl PlaceholderIndices {
 /// it would also contain various points from within the function.
 #[derive(Clone)]
 pub(crate) struct RegionValues<N: Idx> {
-    elements: Rc<RegionValueElements>,
+    elements: Rc<DenseLocationMap>,
     placeholder_indices: Rc<PlaceholderIndices>,
     points: SparseIntervalMatrix<N, PointIndex>,
     free_regions: SparseBitMatrix<N, RegionVid>,
@@ -313,14 +229,14 @@ impl<N: Idx> RegionValues<N> {
     /// Each of the regions in num_region_variables will be initialized with an
     /// empty set of points and no causal information.
     pub(crate) fn new(
-        elements: &Rc<RegionValueElements>,
+        elements: &Rc<DenseLocationMap>,
         num_universal_regions: usize,
         placeholder_indices: &Rc<PlaceholderIndices>,
     ) -> Self {
         let num_placeholders = placeholder_indices.len();
         Self {
             elements: elements.clone(),
-            points: SparseIntervalMatrix::new(elements.num_points),
+            points: SparseIntervalMatrix::new(elements.num_points()),
             placeholder_indices: placeholder_indices.clone(),
             free_regions: SparseBitMatrix::new(num_universal_regions),
             placeholders: SparseBitMatrix::new(num_placeholders),
@@ -486,7 +402,7 @@ impl ToElementIndex for ty::PlaceholderRegion {
 
 /// For debugging purposes, returns a pretty-printed string of the given points.
 pub(crate) fn pretty_print_points(
-    elements: &RegionValueElements,
+    elements: &DenseLocationMap,
     points: impl IntoIterator<Item = PointIndex>,
 ) -> String {
     pretty_print_region_elements(
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index 7433c94a0bc..da5456692ab 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -2,9 +2,9 @@ use rustc_data_structures::vec_linked_list as vll;
 use rustc_index::IndexVec;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location};
+use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
 
 use crate::def_use::{self, DefUse};
-use crate::region_infer::values::{PointIndex, RegionValueElements};
 
 /// A map that cross references each local with the locations where it
 /// is defined (assigned), used, or dropped. Used during liveness
@@ -60,7 +60,7 @@ impl vll::LinkElem for Appearance {
 impl LocalUseMap {
     pub(crate) fn build(
         live_locals: &[Local],
-        elements: &RegionValueElements,
+        elements: &DenseLocationMap,
         body: &Body<'_>,
     ) -> Self {
         let nones = IndexVec::from_elem(None, &body.local_decls);
@@ -103,7 +103,7 @@ impl LocalUseMap {
 
 struct LocalUseMapBuild<'me> {
     local_use_map: &'me mut LocalUseMap,
-    elements: &'me RegionValueElements,
+    elements: &'me DenseLocationMap,
 
     // Vector used in `visit_local` to signal which `Local`s do we need
     // def/use/drop information on, constructed from `live_locals` (that
@@ -144,7 +144,7 @@ impl LocalUseMapBuild<'_> {
     }
 
     fn insert(
-        elements: &RegionValueElements,
+        elements: &DenseLocationMap,
         first_appearance: &mut Option<AppearanceIndex>,
         appearances: &mut IndexVec<AppearanceIndex, Appearance>,
         location: Location,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index e137bc1be0a..51ae7d14e43 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -6,6 +6,7 @@ use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
+use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_mir_dataflow::ResultsCursor;
 use std::rc::Rc;
 
@@ -13,7 +14,7 @@ use crate::{
     constraints::OutlivesConstraintSet,
     facts::{AllFacts, AllFactsExt},
     location::LocationTable,
-    region_infer::values::{LivenessValues, RegionValueElements},
+    region_infer::values::LivenessValues,
     universal_regions::UniversalRegions,
 };
 
@@ -34,7 +35,7 @@ mod trace;
 pub(super) fn generate<'mir, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     body: &Body<'tcx>,
-    elements: &Rc<RegionValueElements>,
+    elements: &Rc<DenseLocationMap>,
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
     location_table: &LocationTable,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index c718d57bec3..eec128b5f1d 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -7,6 +7,7 @@ use rustc_infer::infer::outlives::for_liveness;
 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_mir_dataflow::points::{DenseLocationMap, PointIndex};
 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};
@@ -17,7 +18,7 @@ use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
 use rustc_mir_dataflow::ResultsCursor;
 
 use crate::{
-    region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements},
+    region_infer::values::{self, LiveLoans},
     type_check::liveness::local_use_map::LocalUseMap,
     type_check::liveness::polonius,
     type_check::NormalizeLocation,
@@ -41,7 +42,7 @@ use crate::{
 pub(super) fn trace<'mir, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     body: &Body<'tcx>,
-    elements: &Rc<RegionValueElements>,
+    elements: &Rc<DenseLocationMap>,
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
     relevant_live_locals: Vec<Local>,
@@ -105,7 +106,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
     typeck: &'me mut TypeChecker<'typeck, 'tcx>,
 
     /// Defines the `PointIndex` mapping
-    elements: &'me RegionValueElements,
+    elements: &'me DenseLocationMap,
 
     /// MIR we are analyzing.
     body: &'me Body<'tcx>,
@@ -570,7 +571,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     }
 
     fn make_all_regions_live(
-        elements: &RegionValueElements,
+        elements: &DenseLocationMap,
         typeck: &mut TypeChecker<'_, 'tcx>,
         value: impl TypeVisitable<TyCtxt<'tcx>>,
         live_at: &IntervalSet<PointIndex>,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index aa951a6ce55..48444a6b6f7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -35,6 +35,7 @@ use rustc_middle::ty::{
     OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
 };
 use rustc_middle::ty::{GenericArgsRef, UserArgs};
+use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
@@ -59,9 +60,7 @@ use crate::{
     location::LocationTable,
     member_constraints::MemberConstraintSet,
     path_utils,
-    region_infer::values::{
-        LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
-    },
+    region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices},
     region_infer::TypeTest,
     type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
     universal_regions::{DefiningTy, UniversalRegions},
@@ -134,7 +133,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
     all_facts: &mut Option<AllFacts>,
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
-    elements: &Rc<RegionValueElements>,
+    elements: &Rc<DenseLocationMap>,
     upvars: &[&ty::CapturedPlace<'tcx>],
     use_polonius: bool,
 ) -> MirTypeckResults<'tcx> {
@@ -556,7 +555,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         let all_facts = &mut None;
         let mut constraints = Default::default();
         let mut liveness_constraints =
-            LivenessValues::new(Rc::new(RegionValueElements::new(promoted_body)));
+            LivenessValues::new(Rc::new(DenseLocationMap::new(promoted_body)));
         // Don't try to add borrow_region facts for the promoted MIR
 
         let mut swap_constraints = |this: &mut Self| {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0708.md b/compiler/rustc_error_codes/src/error_codes/E0708.md
index 9287fc803d1..61a853ac446 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0708.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0708.md
@@ -1,12 +1,14 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 `async` non-`move` closures with parameters are currently not supported.
 
 Erroneous code example:
 
-```compile_fail,edition2018,E0708
+```edition2018
 #![feature(async_closure)]
 
 fn main() {
-    let add_one = async |num: u8| { // error!
+    let add_one = async |num: u8| {
         num + 1
     };
 }
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 475dd348e7b..3e3b4814300 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -16,6 +16,9 @@ expand_attributes_wrong_form =
 expand_cannot_be_name_of_macro =
     `{$trait_ident}` cannot be a name of {$macro_type} macro
 
+expand_collapse_debuginfo_illegal =
+    illegal value for attribute #[collapse_debuginfo(no|external|yes)]
+
 expand_count_repetition_misplaced =
     `count` can not be placed inside the inner-most repetition
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 0a1c4430397..edc9c5a9130 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,5 +1,6 @@
 #![deny(rustc::untranslatable_diagnostic)]
 
+use crate::base::ast::NestedMetaItem;
 use crate::errors;
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirOwnership;
@@ -19,6 +20,7 @@ use rustc_feature::Features;
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools};
 use rustc_parse::{parser, MACRO_ARGUMENTS};
+use rustc_session::config::CollapseMacroDebuginfo;
 use rustc_session::errors::report_lit_error;
 use rustc_session::{parse::ParseSess, Limit, Session};
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
@@ -761,6 +763,55 @@ impl SyntaxExtension {
         }
     }
 
+    fn collapse_debuginfo_by_name(sess: &Session, attr: &Attribute) -> CollapseMacroDebuginfo {
+        use crate::errors::CollapseMacroDebuginfoIllegal;
+        // #[collapse_debuginfo] without enum value (#[collapse_debuginfo(no/external/yes)])
+        // considered as `yes`
+        attr.meta_item_list().map_or(CollapseMacroDebuginfo::Yes, |l| {
+            let [NestedMetaItem::MetaItem(item)] = &l[..] else {
+                sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: attr.span });
+                return CollapseMacroDebuginfo::Unspecified;
+            };
+            if !item.is_word() {
+                sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span });
+                CollapseMacroDebuginfo::Unspecified
+            } else {
+                match item.name_or_empty() {
+                    sym::no => CollapseMacroDebuginfo::No,
+                    sym::external => CollapseMacroDebuginfo::External,
+                    sym::yes => CollapseMacroDebuginfo::Yes,
+                    _ => {
+                        sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span });
+                        CollapseMacroDebuginfo::Unspecified
+                    }
+                }
+            }
+        })
+    }
+
+    /// if-ext - if macro from different crate (related to callsite code)
+    /// | cmd \ attr    | no  | (unspecified) | external | yes |
+    /// | no            | no  | no            | no       | no  |
+    /// | (unspecified) | no  | no            | if-ext   | yes |
+    /// | external      | no  | if-ext        | if-ext   | yes |
+    /// | yes           | yes | yes           | yes      | yes |
+    fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], is_local: bool) -> bool {
+        let collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo)
+            .map(|v| Self::collapse_debuginfo_by_name(sess, v))
+            .unwrap_or(CollapseMacroDebuginfo::Unspecified);
+        let flag = sess.opts.unstable_opts.collapse_macro_debuginfo;
+        let attr = collapse_debuginfo_attr;
+        let ext = !is_local;
+        #[rustfmt::skip]
+        let collapse_table = [
+            [false, false, false, false],
+            [false, false, ext,   true],
+            [false, ext,   ext,   true],
+            [true,  true,  true,  true],
+        ];
+        collapse_table[flag as usize][attr as usize]
+    }
+
     /// Constructs a syntax extension with the given properties
     /// and other properties converted from attributes.
     pub fn new(
@@ -772,6 +823,7 @@ impl SyntaxExtension {
         edition: Edition,
         name: Symbol,
         attrs: &[ast::Attribute],
+        is_local: bool,
     ) -> SyntaxExtension {
         let allow_internal_unstable =
             attr::allow_internal_unstable(sess, attrs).collect::<Vec<Symbol>>();
@@ -780,8 +832,8 @@ impl SyntaxExtension {
         let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
             .and_then(|macro_export| macro_export.meta_item_list())
             .is_some_and(|l| attr::list_contains_name(&l, sym::local_inner_macros));
-        let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo);
-        tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
+        let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, is_local);
+        tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
 
         let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro)
             .map(|attr| {
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 2b43fae6852..4a1c00f0104 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -59,6 +59,13 @@ pub(crate) struct ResolveRelativePath {
 }
 
 #[derive(Diagnostic)]
+#[diag(expand_collapse_debuginfo_illegal)]
+pub(crate) struct CollapseMacroDebuginfoIllegal {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(expand_macro_const_stability)]
 pub(crate) struct MacroConstStability {
     #[primary_span]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 363b52aef8a..1a39708ed8e 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -367,6 +367,7 @@ pub fn compile_declarative_macro(
             edition,
             def.ident.name,
             &def.attrs,
+            def.id != DUMMY_NODE_ID,
         )
     };
     let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new());
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 4442b67df6e..68b6f69854d 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -469,7 +469,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // `#[collapse_debuginfo]`
     gated!(
-        collapse_debuginfo, Normal, template!(Word), WarnFollowing,
+        collapse_debuginfo, Normal, template!(Word, List: "no|external|yes"), ErrorFollowing,
         experimental!(collapse_debuginfo)
     ),
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6b347f7035a..6d5917c7b99 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1015,7 +1015,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
+            Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
             Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
             Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
@@ -1042,7 +1042,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {}
+            Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
             Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
             Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
@@ -1205,6 +1205,9 @@ pub enum PatKind<'hir> {
     /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)])
     /// ```
     Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]),
+
+    /// A placeholder for a pattern that wasn't well formed in some way.
+    Err(ErrorGuaranteed),
 }
 
 /// A statement.
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index adc09025809..116de6fb04d 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -655,7 +655,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
             walk_list!(visitor, visit_expr, lower_bound);
             walk_list!(visitor, visit_expr, upper_bound);
         }
-        PatKind::Never | PatKind::Wild => (),
+        PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
         PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
             walk_list!(visitor, visit_pat, prepatterns);
             walk_list!(visitor, visit_pat, slice_pattern);
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 9f4f1413650..b9e72a3b1ea 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1446,7 +1446,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         }
 
         let candidates: Vec<_> = tcx
-            .inherent_impls(adt_did)
+            .inherent_impls(adt_did)?
             .iter()
             .filter_map(|&impl_| Some((impl_, self.lookup_assoc_ty_unchecked(name, block, impl_)?)))
             .collect();
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 77914802bf7..03e2b0e0022 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -368,7 +368,7 @@ fn check_opaque_meets_bounds<'tcx>(
         // Can have different predicates to their defining use
         hir::OpaqueTyOrigin::TyAlias { .. } => {
             let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
-            let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
+            let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys);
             let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
             ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
         }
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 774feb94f7d..5b264f6f034 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -378,7 +378,7 @@ fn compare_method_predicate_entailment<'tcx>(
     // lifetime parameters.
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
-        infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
+        infcx.implied_bounds_tys(param_env, impl_m_def_id, &wf_tys),
     );
     let errors = infcx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
@@ -702,7 +702,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     // lifetime parameters.
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
-        infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
+        infcx.implied_bounds_tys(param_env, impl_m_def_id, &wf_tys),
     );
     ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?;
 
@@ -2070,7 +2070,7 @@ pub(super) fn check_type_bounds<'tcx>(
 
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, &assumed_wf_types);
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
     ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
 }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index f7fc0c81b95..0d8de0cabd1 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -158,7 +158,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     }
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
-        infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types),
+        infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), &implied_wf_types),
     );
     let errors = infcx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 5d5a4789734..1c0a1a69513 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -681,7 +681,8 @@ fn resolve_local<'tcx>(
             | PatKind::Never
             | PatKind::Path(_)
             | PatKind::Lit(_)
-            | PatKind::Range(_, _, _) => false,
+            | PatKind::Range(_, _, _)
+            | PatKind::Err(_) => false,
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 4772bae58c4..58046173fb1 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -15,6 +15,7 @@ use rustc_infer::infer::outlives::obligations::TypeOutlives;
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::query::Providers;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
     self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
@@ -112,8 +113,6 @@ where
 
     let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
 
-    let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
-
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
         let err = infcx.err_ctxt().report_fulfillment_errors(errors);
@@ -128,10 +127,65 @@ where
         }
     }
 
+    debug!(?assumed_wf_types);
+
+    let infcx_compat = infcx.fork();
+
+    // We specifically want to call the non-compat version of `implied_bounds_tys`; we do this always.
+    let implied_bounds =
+        infcx.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, false);
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
 
-    wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?;
-    infcx.tainted_by_errors().error_reported()
+    let errors = infcx.resolve_regions(&outlives_env);
+    if errors.is_empty() {
+        return Ok(());
+    }
+
+    let is_bevy = 'is_bevy: {
+        // We don't want to emit this for dependents of Bevy, for now.
+        // See #119956
+        let is_bevy_paramset = |def: ty::AdtDef<'_>| {
+            let adt_did = with_no_trimmed_paths!(infcx.tcx.def_path_str(def.0.did));
+            adt_did.contains("ParamSet")
+        };
+        for ty in assumed_wf_types.iter() {
+            match ty.kind() {
+                ty::Adt(def, _) => {
+                    if is_bevy_paramset(*def) {
+                        break 'is_bevy true;
+                    }
+                }
+                ty::Ref(_, ty, _) => match ty.kind() {
+                    ty::Adt(def, _) => {
+                        if is_bevy_paramset(*def) {
+                            break 'is_bevy true;
+                        }
+                    }
+                    _ => {}
+                },
+                _ => {}
+            }
+        }
+        false
+    };
+
+    // If we have set `no_implied_bounds_compat`, then do not attempt compatibility.
+    // We could also just always enter if `is_bevy`, and call `implied_bounds_tys`,
+    // but that does result in slightly more work when this option is set and
+    // just obscures what we mean here anyways. Let's just be explicit.
+    if is_bevy && !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
+        let implied_bounds =
+            infcx_compat.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, true);
+        let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
+        let errors_compat = infcx_compat.resolve_regions(&outlives_env);
+        if errors_compat.is_empty() {
+            Ok(())
+        } else {
+            Err(infcx_compat.err_ctxt().report_region_errors(body_def_id, &errors_compat))
+        }
+    } else {
+        Err(infcx.err_ctxt().report_region_errors(body_def_id, &errors))
+    }
 }
 
 fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
@@ -723,7 +777,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
     let infcx = tcx.infer_ctxt().build();
     let outlives_environment = OutlivesEnvironment::with_bounds(
         param_env,
-        infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
+        infcx.implied_bounds_tys(param_env, id, wf_tys),
     );
     let region_bound_pairs = outlives_environment.region_bound_pairs();
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 3162004a634..abef365c3ca 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -13,32 +13,41 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use rustc_span::symbol::sym;
+use rustc_span::ErrorGuaranteed;
 
 use crate::errors;
 
 /// On-demand query: yields a map containing all types mapped to their inherent impls.
-pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
+pub fn crate_inherent_impls(
+    tcx: TyCtxt<'_>,
+    (): (),
+) -> Result<&'_ CrateInherentImpls, ErrorGuaranteed> {
     let mut collect = InherentCollect { tcx, impls_map: Default::default() };
+    let mut res = Ok(());
     for id in tcx.hir().items() {
-        collect.check_item(id);
+        res = res.and(collect.check_item(id));
     }
-    collect.impls_map
+    res?;
+    Ok(tcx.arena.alloc(collect.impls_map))
 }
 
-pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
-    let crate_map = tcx.crate_inherent_impls(());
-    tcx.arena.alloc_from_iter(
+pub fn crate_incoherent_impls(
+    tcx: TyCtxt<'_>,
+    simp: SimplifiedType,
+) -> Result<&[DefId], ErrorGuaranteed> {
+    let crate_map = tcx.crate_inherent_impls(())?;
+    Ok(tcx.arena.alloc_from_iter(
         crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()),
-    )
+    ))
 }
 
 /// On-demand query: yields a vector of the inherent impls for a specific type.
-pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] {
-    let crate_map = tcx.crate_inherent_impls(());
-    match crate_map.inherent_impls.get(&ty_def_id) {
+pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> Result<&[DefId], ErrorGuaranteed> {
+    let crate_map = tcx.crate_inherent_impls(())?;
+    Ok(match crate_map.inherent_impls.get(&ty_def_id) {
         Some(v) => &v[..],
         None => &[],
-    }
+    })
 }
 
 struct InherentCollect<'tcx> {
@@ -47,14 +56,19 @@ struct InherentCollect<'tcx> {
 }
 
 impl<'tcx> InherentCollect<'tcx> {
-    fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
+    fn check_def_id(
+        &mut self,
+        impl_def_id: LocalDefId,
+        self_ty: Ty<'tcx>,
+        ty_def_id: DefId,
+    ) -> Result<(), ErrorGuaranteed> {
         if let Some(ty_def_id) = ty_def_id.as_local() {
             // Add the implementation to the mapping from implementation to base
             // type def ID, if there is a base type for this implementation and
             // the implementation does not have any associated traits.
             let vec = self.impls_map.inherent_impls.entry(ty_def_id).or_default();
             vec.push(impl_def_id.to_def_id());
-            return;
+            return Ok(());
         }
 
         if self.tcx.features().rustc_attrs {
@@ -62,18 +76,16 @@ impl<'tcx> InherentCollect<'tcx> {
 
             if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
                 let impl_span = self.tcx.def_span(impl_def_id);
-                self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span });
-                return;
+                return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span }));
             }
 
             for &impl_item in items {
                 if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
                     let impl_span = self.tcx.def_span(impl_def_id);
-                    self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant {
+                    return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant {
                         span: impl_span,
                         help_span: self.tcx.def_span(impl_item),
-                    });
-                    return;
+                    }));
                 }
             }
 
@@ -82,24 +94,28 @@ impl<'tcx> InherentCollect<'tcx> {
             } else {
                 bug!("unexpected self type: {:?}", self_ty);
             }
+            Ok(())
         } else {
             let impl_span = self.tcx.def_span(impl_def_id);
-            self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span });
+            Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span }))
         }
     }
 
-    fn check_primitive_impl(&mut self, impl_def_id: LocalDefId, ty: Ty<'tcx>) {
+    fn check_primitive_impl(
+        &mut self,
+        impl_def_id: LocalDefId,
+        ty: Ty<'tcx>,
+    ) -> Result<(), ErrorGuaranteed> {
         let items = self.tcx.associated_item_def_ids(impl_def_id);
         if !self.tcx.hir().rustc_coherence_is_core() {
             if self.tcx.features().rustc_attrs {
                 for &impl_item in items {
                     if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
                         let span = self.tcx.def_span(impl_def_id);
-                        self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive {
+                        return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive {
                             span,
                             help_span: self.tcx.def_span(impl_item),
-                        });
-                        return;
+                        }));
                     }
                 }
             } else {
@@ -108,8 +124,7 @@ impl<'tcx> InherentCollect<'tcx> {
                 if let ty::Ref(_, subty, _) = ty.kind() {
                     note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
                 }
-                self.tcx.dcx().emit_err(errors::InherentPrimitiveTy { span, note });
-                return;
+                return Err(self.tcx.dcx().emit_err(errors::InherentPrimitiveTy { span, note }));
             }
         }
 
@@ -118,11 +133,12 @@ impl<'tcx> InherentCollect<'tcx> {
         } else {
             bug!("unexpected primitive type: {:?}", ty);
         }
+        Ok(())
     }
 
-    fn check_item(&mut self, id: hir::ItemId) {
+    fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
         if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: false }) {
-            return;
+            return Ok(());
         }
 
         let id = id.owner_id.def_id;
@@ -132,10 +148,10 @@ impl<'tcx> InherentCollect<'tcx> {
             ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
             ty::Foreign(did) => self.check_def_id(id, self_ty, did),
             ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
-                self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
+                self.check_def_id(id, self_ty, data.principal_def_id().unwrap())
             }
             ty::Dynamic(..) => {
-                self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span });
+                Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }))
             }
             ty::Bool
             | ty::Char
@@ -151,7 +167,7 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::FnPtr(_)
             | ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
             ty::Alias(..) | ty::Param(_) => {
-                self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span });
+                Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }))
             }
             ty::FnDef(..)
             | ty::Closure(..)
@@ -162,7 +178,8 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Infer(_) => {
                 bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty);
             }
-            ty::Error(_) => {}
+            // We could bail out here, but that will silence other useful errors.
+            ty::Error(_) => Ok(()),
         }
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 4c3455c7240..63ea0272014 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -6,16 +6,18 @@ use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::Symbol;
+use rustc_span::{ErrorGuaranteed, Symbol};
 use rustc_trait_selection::traits::{self, SkipLeakCheck};
 use smallvec::SmallVec;
 use std::collections::hash_map::Entry;
 
-pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) {
+pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> {
     let mut inherent_overlap_checker = InherentOverlapChecker { tcx };
+    let mut res = Ok(());
     for id in tcx.hir().items() {
-        inherent_overlap_checker.check_item(id);
+        res = res.and(inherent_overlap_checker.check_item(id));
     }
+    res
 }
 
 struct InherentOverlapChecker<'tcx> {
@@ -58,10 +60,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
                 == item2.ident(self.tcx).normalize_to_macros_2_0()
     }
 
-    fn check_for_duplicate_items_in_impl(&self, impl_: DefId) {
+    fn check_for_duplicate_items_in_impl(&self, impl_: DefId) -> Result<(), ErrorGuaranteed> {
         let impl_items = self.tcx.associated_items(impl_);
 
         let mut seen_items = FxHashMap::default();
+        let mut res = Ok(());
         for impl_item in impl_items.in_definition_order() {
             let span = self.tcx.def_span(impl_item.def_id);
             let ident = impl_item.ident(self.tcx);
@@ -70,7 +73,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
             match seen_items.entry(norm_ident) {
                 Entry::Occupied(entry) => {
                     let former = entry.get();
-                    struct_span_code_err!(
+                    res = Err(struct_span_code_err!(
                         self.tcx.dcx(),
                         span,
                         E0592,
@@ -79,13 +82,14 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
                     )
                     .with_span_label(span, format!("duplicate definitions for `{ident}`"))
                     .with_span_label(*former, format!("other definition for `{ident}`"))
-                    .emit();
+                    .emit());
                 }
                 Entry::Vacant(entry) => {
                     entry.insert(span);
                 }
             }
         }
+        res
     }
 
     fn check_for_common_items_in_impls(
@@ -93,10 +97,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
         impl1: DefId,
         impl2: DefId,
         overlap: traits::OverlapResult<'_>,
-    ) {
+    ) -> Result<(), ErrorGuaranteed> {
         let impl_items1 = self.tcx.associated_items(impl1);
         let impl_items2 = self.tcx.associated_items(impl2);
 
+        let mut res = Ok(());
         for &item1 in impl_items1.in_definition_order() {
             let collision = impl_items2
                 .filter_by_name_unhygienic(item1.name)
@@ -128,9 +133,10 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
                     traits::add_placeholder_note(&mut err);
                 }
 
-                err.emit();
+                res = Err(err.emit());
             }
         }
+        res
     }
 
     fn check_for_overlapping_inherent_impls(
@@ -138,7 +144,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
         overlap_mode: OverlapMode,
         impl1_def_id: DefId,
         impl2_def_id: DefId,
-    ) {
+    ) -> Result<(), ErrorGuaranteed> {
         let maybe_overlap = traits::overlapping_impls(
             self.tcx,
             impl1_def_id,
@@ -150,17 +156,19 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
         );
 
         if let Some(overlap) = maybe_overlap {
-            self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
+            self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap)
+        } else {
+            Ok(())
         }
     }
 
-    fn check_item(&mut self, id: hir::ItemId) {
+    fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
         let def_kind = self.tcx.def_kind(id.owner_id);
         if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) {
-            return;
+            return Ok(());
         }
 
-        let impls = self.tcx.inherent_impls(id.owner_id);
+        let impls = self.tcx.inherent_impls(id.owner_id)?;
 
         let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id());
 
@@ -173,17 +181,18 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
         // otherwise switch to an allocating algorithm with
         // faster asymptotic runtime.
         const ALLOCATING_ALGO_THRESHOLD: usize = 500;
+        let mut res = Ok(());
         if impls.len() < ALLOCATING_ALGO_THRESHOLD {
             for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
-                self.check_for_duplicate_items_in_impl(impl1_def_id);
+                res = res.and(self.check_for_duplicate_items_in_impl(impl1_def_id));
 
                 for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
                     if self.impls_have_common_items(impl_items1, impl_items2) {
-                        self.check_for_overlapping_inherent_impls(
+                        res = res.and(self.check_for_overlapping_inherent_impls(
                             overlap_mode,
                             impl1_def_id,
                             impl2_def_id,
-                        );
+                        ));
                     }
                 }
             }
@@ -315,20 +324,21 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
                 impl_blocks.sort_unstable();
                 for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() {
                     let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx];
-                    self.check_for_duplicate_items_in_impl(impl1_def_id);
+                    res = res.and(self.check_for_duplicate_items_in_impl(impl1_def_id));
 
                     for &impl2_items_idx in impl_blocks[(i + 1)..].iter() {
                         let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx];
                         if self.impls_have_common_items(impl_items1, impl_items2) {
-                            self.check_for_overlapping_inherent_impls(
+                            res = res.and(self.check_for_overlapping_inherent_impls(
                                 overlap_mode,
                                 impl1_def_id,
                                 impl2_def_id,
-                            );
+                            ));
                         }
                     }
                 }
             }
         }
+        res
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 1f7ca48234a..85093bc12b3 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -5,20 +5,22 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::{sym, DUMMY_SP};
+use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
 
 use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
 
-pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) {
+pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
+    let mut res = Ok(());
     if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
         for id in tcx.hir().items() {
             if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
                 let type_of = tcx.type_of(id.owner_id).instantiate_identity();
 
-                tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of });
+                res = Err(tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of }));
             }
         }
     }
+    res
 }
 
 /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
@@ -135,18 +137,25 @@ impl TaitConstraintLocator<'_> {
             return;
         }
 
-        if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() {
-            if hir_sig.output.get_infer_ret_ty().is_some() {
-                let guar = self.tcx.dcx().span_delayed_bug(
-                    hir_sig.output.span(),
-                    "inferring return types and opaque types do not mix well",
-                );
-                self.found = Some(ty::OpaqueHiddenType {
-                    span: DUMMY_SP,
-                    ty: Ty::new_error(self.tcx, guar),
-                });
-                return;
-            }
+        // Function items with `_` in their return type already emit an error, skip any
+        // "non-defining use" errors for them.
+        // Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
+        // excludes closures, which are allowed to have `_` in their return type.
+        let hir_node = self.tcx.hir_node_by_def_id(item_def_id);
+        debug_assert!(
+            !matches!(hir_node, Node::ForeignItem(..)),
+            "foreign items cannot constrain opaque types",
+        );
+        if let Some(hir_sig) = hir_node.fn_sig()
+            && hir_sig.decl.output.get_infer_ret_ty().is_some()
+        {
+            let guar = self.tcx.dcx().span_delayed_bug(
+                hir_sig.decl.output.span(),
+                "inferring return types and opaque types do not mix well",
+            );
+            self.found =
+                Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
+            return;
         }
 
         // Calling `mir_borrowck` can lead to cycle errors through
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 3f9b1f384d7..2fe08ead72b 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -17,7 +17,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
-use rustc_span::{Span, Symbol};
+use rustc_span::{ErrorGuaranteed, Span, Symbol};
 
 mod min_specialization;
 
@@ -51,24 +51,29 @@ mod min_specialization;
 /// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
 /// //   ^ 'a is unused and appears in assoc type, error
 /// ```
-fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
+fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) -> Result<(), ErrorGuaranteed> {
     let min_specialization = tcx.features().min_specialization;
     let module = tcx.hir_module_items(module_def_id);
+    let mut res = Ok(());
     for id in module.items() {
         if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) {
-            enforce_impl_params_are_constrained(tcx, id.owner_id.def_id);
+            res = res.and(enforce_impl_params_are_constrained(tcx, id.owner_id.def_id));
             if min_specialization {
-                check_min_specialization(tcx, id.owner_id.def_id);
+                res = res.and(check_min_specialization(tcx, id.owner_id.def_id));
             }
         }
     }
+    res
 }
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_impl_wf, ..*providers };
 }
 
-fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
+fn enforce_impl_params_are_constrained(
+    tcx: TyCtxt<'_>,
+    impl_def_id: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     // Every lifetime used in an associated type must be constrained.
     let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
     if impl_self_ty.references_error() {
@@ -80,7 +85,10 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
                 "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}",
             ),
         );
-        return;
+        // This is super fishy, but our current `rustc_hir_analysis::check_crate` pipeline depends on
+        // `type_of` having been called much earlier, and thus this value being read from cache.
+        // Compilation must continue in order for other important diagnostics to keep showing up.
+        return Ok(());
     }
     let impl_generics = tcx.generics_of(impl_def_id);
     let impl_predicates = tcx.predicates_of(impl_def_id);
@@ -113,13 +121,19 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
         })
         .collect();
 
+    let mut res = Ok(());
     for param in &impl_generics.params {
         match param.kind {
             // Disallow ANY unconstrained type parameters.
             ty::GenericParamDefKind::Type { .. } => {
                 let param_ty = ty::ParamTy::for_def(param);
                 if !input_parameters.contains(&cgp::Parameter::from(param_ty)) {
-                    report_unused_parameter(tcx, tcx.def_span(param.def_id), "type", param_ty.name);
+                    res = Err(report_unused_parameter(
+                        tcx,
+                        tcx.def_span(param.def_id),
+                        "type",
+                        param_ty.name,
+                    ));
                 }
             }
             ty::GenericParamDefKind::Lifetime => {
@@ -127,27 +141,28 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
                 if lifetimes_in_associated_types.contains(&param_lt) && // (*)
                     !input_parameters.contains(&param_lt)
                 {
-                    report_unused_parameter(
+                    res = Err(report_unused_parameter(
                         tcx,
                         tcx.def_span(param.def_id),
                         "lifetime",
                         param.name,
-                    );
+                    ));
                 }
             }
             ty::GenericParamDefKind::Const { .. } => {
                 let param_ct = ty::ParamConst::for_def(param);
                 if !input_parameters.contains(&cgp::Parameter::from(param_ct)) {
-                    report_unused_parameter(
+                    res = Err(report_unused_parameter(
                         tcx,
                         tcx.def_span(param.def_id),
                         "const",
                         param_ct.name,
-                    );
+                    ));
                 }
             }
         }
     }
+    res
 
     // (*) This is a horrible concession to reality. I think it'd be
     // better to just ban unconstrained lifetimes outright, but in
@@ -169,7 +184,12 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
     // used elsewhere are not projected back out.
 }
 
-fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) {
+fn report_unused_parameter(
+    tcx: TyCtxt<'_>,
+    span: Span,
+    kind: &str,
+    name: Symbol,
+) -> ErrorGuaranteed {
     let mut err = struct_span_code_err!(
         tcx.dcx(),
         span,
@@ -188,5 +208,5 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol
             "proving the result of expressions other than the parameter are unique is not supported",
         );
     }
-    err.emit();
+    err.emit()
 }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 93dd2342a4d..1b6a39d8162 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -82,10 +82,14 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt};
 
-pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
+pub(super) fn check_min_specialization(
+    tcx: TyCtxt<'_>,
+    impl_def_id: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
-        check_always_applicable(tcx, impl_def_id, node);
+        check_always_applicable(tcx, impl_def_id, node)?;
     }
+    Ok(())
 }
 
 fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
@@ -109,42 +113,58 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
 
 /// Check that `impl1` is a sound specialization
 #[instrument(level = "debug", skip(tcx))]
-fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) {
+fn check_always_applicable(
+    tcx: TyCtxt<'_>,
+    impl1_def_id: LocalDefId,
+    impl2_node: Node,
+) -> Result<(), ErrorGuaranteed> {
     let span = tcx.def_span(impl1_def_id);
-    check_has_items(tcx, impl1_def_id, impl2_node, span);
-
-    if let Ok((impl1_args, impl2_args)) = get_impl_args(tcx, impl1_def_id, impl2_node) {
-        let impl2_def_id = impl2_node.def_id();
-        debug!(?impl2_def_id, ?impl2_args);
-
-        let parent_args = if impl2_node.is_from_trait() {
-            impl2_args.to_vec()
-        } else {
-            unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args)
-        };
-
-        check_constness(tcx, impl1_def_id, impl2_node, span);
-        check_static_lifetimes(tcx, &parent_args, span);
-        check_duplicate_params(tcx, impl1_args, &parent_args, span);
-        check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span);
-    }
+    let mut res = check_has_items(tcx, impl1_def_id, impl2_node, span);
+
+    let (impl1_args, impl2_args) = get_impl_args(tcx, impl1_def_id, impl2_node)?;
+    let impl2_def_id = impl2_node.def_id();
+    debug!(?impl2_def_id, ?impl2_args);
+
+    let parent_args = if impl2_node.is_from_trait() {
+        impl2_args.to_vec()
+    } else {
+        unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args)
+    };
+
+    res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span));
+    res = res.and(check_static_lifetimes(tcx, &parent_args, span));
+    res = res.and(check_duplicate_params(tcx, impl1_args, &parent_args, span));
+    res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span));
+
+    res
 }
 
-fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
+fn check_has_items(
+    tcx: TyCtxt<'_>,
+    impl1_def_id: LocalDefId,
+    impl2_node: Node,
+    span: Span,
+) -> Result<(), ErrorGuaranteed> {
     if let Node::Impl(impl2_id) = impl2_node
         && tcx.associated_item_def_ids(impl1_def_id).is_empty()
     {
         let base_impl_span = tcx.def_span(impl2_id);
-        tcx.dcx().emit_err(errors::EmptySpecialization { span, base_impl_span });
+        return Err(tcx.dcx().emit_err(errors::EmptySpecialization { span, base_impl_span }));
     }
+    Ok(())
 }
 
 /// Check that the specializing impl `impl1` is at least as const as the base
 /// impl `impl2`
-fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
+fn check_constness(
+    tcx: TyCtxt<'_>,
+    impl1_def_id: LocalDefId,
+    impl2_node: Node,
+    span: Span,
+) -> Result<(), ErrorGuaranteed> {
     if impl2_node.is_from_trait() {
         // This isn't a specialization
-        return;
+        return Ok(());
     }
 
     let impl1_constness = tcx.constness(impl1_def_id.to_def_id());
@@ -152,9 +172,10 @@ fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node,
 
     if let hir::Constness::Const = impl2_constness {
         if let hir::Constness::NotConst = impl1_constness {
-            tcx.dcx().emit_err(errors::ConstSpecialize { span });
+            return Err(tcx.dcx().emit_err(errors::ConstSpecialize { span }));
         }
     }
+    Ok(())
 }
 
 /// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
@@ -202,7 +223,7 @@ fn get_impl_args(
         return Err(guar);
     }
 
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, &assumed_wf_types);
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
     let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
@@ -290,15 +311,17 @@ fn check_duplicate_params<'tcx>(
     impl1_args: GenericArgsRef<'tcx>,
     parent_args: &Vec<GenericArg<'tcx>>,
     span: Span,
-) {
+) -> Result<(), ErrorGuaranteed> {
     let mut base_params = cgp::parameters_for(parent_args, true);
     base_params.sort_by_key(|param| param.0);
     if let (_, [duplicate, ..]) = base_params.partition_dedup() {
         let param = impl1_args[duplicate.0 as usize];
-        tcx.dcx()
+        return Err(tcx
+            .dcx()
             .struct_span_err(span, format!("specializing impl repeats parameter `{param}`"))
-            .emit();
+            .emit());
     }
+    Ok(())
 }
 
 /// Check that `'static` lifetimes are not introduced by the specializing impl.
@@ -313,10 +336,11 @@ fn check_static_lifetimes<'tcx>(
     tcx: TyCtxt<'tcx>,
     parent_args: &Vec<GenericArg<'tcx>>,
     span: Span,
-) {
+) -> Result<(), ErrorGuaranteed> {
     if tcx.any_free_region_meets(parent_args, |r| r.is_static()) {
-        tcx.dcx().emit_err(errors::StaticSpecialize { span });
+        return Err(tcx.dcx().emit_err(errors::StaticSpecialize { span }));
     }
+    Ok(())
 }
 
 /// Check whether predicates on the specializing impl (`impl1`) are allowed.
@@ -337,7 +361,7 @@ fn check_predicates<'tcx>(
     impl2_node: Node,
     impl2_args: GenericArgsRef<'tcx>,
     span: Span,
-) {
+) -> Result<(), ErrorGuaranteed> {
     let impl1_predicates: Vec<_> = traits::elaborate(
         tcx,
         tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_args).into_iter(),
@@ -399,14 +423,16 @@ fn check_predicates<'tcx>(
     }
     impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits));
 
+    let mut res = Ok(());
     for (clause, span) in impl1_predicates {
         if !impl2_predicates
             .iter()
             .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span))
         {
-            check_specialization_on(tcx, clause, span)
+            res = res.and(check_specialization_on(tcx, clause, span))
         }
     }
+    res
 }
 
 /// Checks if some predicate on the specializing impl (`predicate1`) is the same
@@ -443,19 +469,26 @@ fn trait_predicates_eq<'tcx>(
 }
 
 #[instrument(level = "debug", skip(tcx))]
-fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, span: Span) {
+fn check_specialization_on<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    clause: ty::Clause<'tcx>,
+    span: Span,
+) -> Result<(), ErrorGuaranteed> {
     match clause.kind().skip_binder() {
         // Global predicates are either always true or always false, so we
         // are fine to specialize on.
-        _ if clause.is_global() => (),
+        _ if clause.is_global() => Ok(()),
         // We allow specializing on explicitly marked traits with no associated
         // items.
         ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
-            if !matches!(
+            if matches!(
                 trait_specialization_kind(tcx, clause),
                 Some(TraitSpecializationKind::Marker)
             ) {
-                tcx.dcx()
+                Ok(())
+            } else {
+                Err(tcx
+                    .dcx()
                     .struct_span_err(
                         span,
                         format!(
@@ -463,17 +496,16 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp
                             tcx.def_path_str(trait_ref.def_id),
                         ),
                     )
-                    .emit();
+                    .emit())
             }
         }
-        ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
-            tcx.dcx()
-                .struct_span_err(
-                    span,
-                    format!("cannot specialize on associated type `{projection_ty} == {term}`",),
-                )
-                .emit();
-        }
+        ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => Err(tcx
+            .dcx()
+            .struct_span_err(
+                span,
+                format!("cannot specialize on associated type `{projection_ty} == {term}`",),
+            )
+            .emit()),
         ty::ClauseKind::ConstArgHasType(..) => {
             // FIXME(min_specialization), FIXME(const_generics):
             // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure
@@ -483,12 +515,12 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp
             // While we do not support constructs like `<T, const N: T>` there is probably no risk of
             // soundness bugs, but when we support generic const parameter types this will need to be
             // revisited.
+            Ok(())
         }
-        _ => {
-            tcx.dcx()
-                .struct_span_err(span, format!("cannot specialize on predicate `{clause}`"))
-                .emit();
-        }
+        _ => Err(tcx
+            .dcx()
+            .struct_span_err(span, format!("cannot specialize on predicate `{clause}`"))
+            .emit()),
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index f5abb7261c0..08956d222d2 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -166,33 +166,29 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
         tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module))
     });
 
-    // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function
-    // or the compiler in general.
     if tcx.features().rustc_attrs {
-        tcx.sess.track_errors(|| {
-            tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
-        })?;
+        tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?;
     }
 
-    tcx.sess.track_errors(|| {
-        tcx.sess.time("coherence_checking", || {
-            // Check impls constrain their parameters
-            tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module));
+    tcx.sess.time("coherence_checking", || {
+        // Check impls constrain their parameters
+        let res =
+            tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_impl_wf(module));
 
+        // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function
+        // or the compiler in general.
+        res.and(tcx.sess.track_errors(|| {
             for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
                 tcx.ensure().coherent_trait(trait_def_id);
             }
-
-            // these queries are executed for side-effects (error reporting):
-            tcx.ensure().crate_inherent_impls(());
-            tcx.ensure().crate_inherent_impls_overlap_check(());
-        });
+        }))
+        // these queries are executed for side-effects (error reporting):
+        .and(tcx.ensure().crate_inherent_impls(()))
+        .and(tcx.ensure().crate_inherent_impls_overlap_check(()))
     })?;
 
     if tcx.features().rustc_attrs {
-        tcx.sess.track_errors(|| {
-            tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
-        })?;
+        tcx.sess.time("variance_testing", || variance::test::test_variance(tcx))?;
     }
 
     tcx.sess.time("wf_checking", || {
@@ -200,7 +196,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
     })?;
 
     if tcx.features().rustc_attrs {
-        tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?;
+        collect::test_opaque_hidden_types(tcx)?;
     }
 
     // Freeze definitions as we don't add new ones at this point. This improves performance by
diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
index dea3f1a9930..60cd8c39fa0 100644
--- a/compiler/rustc_hir_analysis/src/outlives/test.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/test.rs
@@ -1,7 +1,8 @@
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::symbol::sym;
+use rustc_span::{symbol::sym, ErrorGuaranteed};
 
-pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
+pub fn test_inferred_outlives(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
+    let mut res = Ok(());
     for id in tcx.hir().items() {
         // For unit testing: check for a special "rustc_outlives"
         // attribute and report an error with various results if found.
@@ -22,7 +23,8 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
             for p in pred {
                 err.note(p);
             }
-            err.emit();
+            res = Err(err.emit());
         }
     }
+    res
 }
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index 5264d5aa26f..c211e1af046 100644
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -2,19 +2,21 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
+use rustc_span::ErrorGuaranteed;
 
 use crate::errors;
 
-pub fn test_variance(tcx: TyCtxt<'_>) {
+pub fn test_variance(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
+    let mut res = Ok(());
     if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
         for id in tcx.hir().items() {
             if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
                 let variances_of = tcx.variances_of(id.owner_id);
 
-                tcx.dcx().emit_err(errors::VariancesOf {
+                res = Err(tcx.dcx().emit_err(errors::VariancesOf {
                     span: tcx.def_span(id.owner_id),
                     variances_of: format!("{variances_of:?}"),
-                });
+                }));
             }
         }
     }
@@ -25,10 +27,11 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
         if tcx.has_attr(id.owner_id, sym::rustc_variance) {
             let variances_of = tcx.variances_of(id.owner_id);
 
-            tcx.dcx().emit_err(errors::VariancesOf {
+            res = Err(tcx.dcx().emit_err(errors::VariancesOf {
                 span: tcx.def_span(id.owner_id),
                 variances_of: format!("{variances_of:?}"),
-            });
+            }));
         }
     }
+    res
 }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index d36e0892d19..e76303bc6df 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1838,6 +1838,11 @@ impl<'a> State<'a> {
                 self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
                 self.word("]");
             }
+            PatKind::Err(_) => {
+                self.popen();
+                self.word("/*ERROR*/");
+                self.pclose();
+            }
         }
         self.ann.post(self, AnnNode::Pat(pat))
     }
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 1a4e03d50ca..d486f069989 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -293,49 +293,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         callee_node: &hir::ExprKind<'_>,
         callee_span: Span,
     ) {
+        let hir::ExprKind::Block(..) = callee_node else {
+            // Only calls on blocks suggested here.
+            return;
+        };
+
         let hir = self.tcx.hir();
-        let parent_hir_id = hir.parent_id(hir_id);
-        let parent_node = self.tcx.hir_node(parent_hir_id);
-        if let (
-            hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, kind, .. }),
+        let fn_decl_span = if let hir::Node::Expr(hir::Expr {
+            kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
+            ..
+        }) = hir.get_parent(hir_id)
+        {
+            fn_decl_span
+        } else if let Some((
+            _,
+            hir::Node::Expr(&hir::Expr {
+                hir_id: parent_hir_id,
+                kind:
+                    hir::ExprKind::Closure(&hir::Closure {
+                        kind:
+                            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                                hir::CoroutineDesugaring::Async,
+                                hir::CoroutineSource::Closure,
+                            )),
+                        ..
+                    }),
                 ..
             }),
-            hir::ExprKind::Block(..),
-        ) = (parent_node, callee_node)
+        )) = hir.parent_iter(hir_id).nth(3)
         {
-            let fn_decl_span = if matches!(
-                kind,
-                hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::Async,
-                    hir::CoroutineSource::Closure
-                ),)
-            ) {
-                // Actually need to unwrap one more layer of HIR to get to
-                // the _real_ closure...
-                let async_closure = hir.parent_id(parent_hir_id);
-                if let hir::Node::Expr(hir::Expr {
-                    kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
-                    ..
-                }) = self.tcx.hir_node(async_closure)
-                {
-                    fn_decl_span
-                } else {
-                    return;
-                }
-            } else {
+            // Actually need to unwrap one more layer of HIR to get to
+            // the _real_ closure...
+            let async_closure = hir.parent_id(parent_hir_id);
+            if let hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
+                ..
+            }) = self.tcx.hir_node(async_closure)
+            {
                 fn_decl_span
-            };
+            } else {
+                return;
+            }
+        } else {
+            return;
+        };
 
-            let start = fn_decl_span.shrink_to_lo();
-            let end = callee_span.shrink_to_hi();
-            err.multipart_suggestion(
-                "if you meant to create this closure and immediately call it, surround the \
+        let start = fn_decl_span.shrink_to_lo();
+        let end = callee_span.shrink_to_hi();
+        err.multipart_suggestion(
+            "if you meant to create this closure and immediately call it, surround the \
                 closure with parentheses",
-                vec![(start, "(".to_string()), (end, ")".to_string())],
-                Applicability::MaybeIncorrect,
-            );
-        }
+            vec![(start, "(".to_string()), (end, ")".to_string())],
+            Applicability::MaybeIncorrect,
+        );
     }
 
     /// Give appropriate suggestion when encountering `[("a", 0) ("b", 1)]`, where the
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 57fdfa4ecb6..8a035d0577f 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -68,12 +68,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         debug!(?bound_sig, ?liberated_sig);
 
+        let parent_args =
+            GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
+
+        let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::ClosureSynthetic,
+            span: expr_span,
+        });
+
         // FIXME: We could probably actually just unify this further --
         // instead of having a `FnSig` and a `Option<CoroutineTypes>`,
         // we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`,
         // similar to how `ty::GenSig` is a distinct data structure.
-        let coroutine_types = match closure.kind {
-            hir::ClosureKind::Closure => None,
+        let (closure_ty, coroutine_types) = match closure.kind {
+            hir::ClosureKind::Closure => {
+                // Tuple up the arguments and insert the resulting function type into
+                // the `closures` table.
+                let sig = bound_sig.map_bound(|sig| {
+                    tcx.mk_fn_sig(
+                        [Ty::new_tup(tcx, sig.inputs())],
+                        sig.output(),
+                        sig.c_variadic,
+                        sig.unsafety,
+                        sig.abi,
+                    )
+                });
+
+                debug!(?sig, ?expected_kind);
+
+                let closure_kind_ty = match expected_kind {
+                    Some(kind) => Ty::from_closure_kind(tcx, kind),
+
+                    // Create a type variable (for now) to represent the closure kind.
+                    // It will be unified during the upvar inference phase (`upvar.rs`)
+                    None => self.next_ty_var(TypeVariableOrigin {
+                        // FIXME(eddyb) distinguish closure kind inference variables from the rest.
+                        kind: TypeVariableOriginKind::ClosureSynthetic,
+                        span: expr_span,
+                    }),
+                };
+
+                let closure_args = ty::ClosureArgs::new(
+                    tcx,
+                    ty::ClosureArgsParts {
+                        parent_args,
+                        closure_kind_ty,
+                        closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
+                        tupled_upvars_ty,
+                    },
+                );
+
+                (Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None)
+            }
             hir::ClosureKind::Coroutine(kind) => {
                 let yield_ty = match kind {
                     hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
@@ -119,74 +165,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Resume type defaults to `()` if the coroutine has no argument.
                 let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
 
-                Some(CoroutineTypes { resume_ty, yield_ty })
-            }
-        };
-
-        check_fn(
-            &mut FnCtxt::new(self, self.param_env, closure.def_id),
-            liberated_sig,
-            coroutine_types,
-            closure.fn_decl,
-            expr_def_id,
-            body,
-            // Closure "rust-call" ABI doesn't support unsized params
-            false,
-        );
-
-        let parent_args =
-            GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
-
-        let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::ClosureSynthetic,
-            span: expr_span,
-        });
-
-        match closure.kind {
-            hir::ClosureKind::Closure => {
-                assert_eq!(coroutine_types, None);
-                // Tuple up the arguments and insert the resulting function type into
-                // the `closures` table.
-                let sig = bound_sig.map_bound(|sig| {
-                    tcx.mk_fn_sig(
-                        [Ty::new_tup(tcx, sig.inputs())],
-                        sig.output(),
-                        sig.c_variadic,
-                        sig.unsafety,
-                        sig.abi,
-                    )
-                });
-
-                debug!(?sig, ?expected_kind);
-
-                let closure_kind_ty = match expected_kind {
-                    Some(kind) => Ty::from_closure_kind(tcx, kind),
-
-                    // Create a type variable (for now) to represent the closure kind.
-                    // It will be unified during the upvar inference phase (`upvar.rs`)
-                    None => self.next_root_ty_var(TypeVariableOrigin {
-                        // FIXME(eddyb) distinguish closure kind inference variables from the rest.
-                        kind: TypeVariableOriginKind::ClosureSynthetic,
-                        span: expr_span,
-                    }),
-                };
-
-                let closure_args = ty::ClosureArgs::new(
-                    tcx,
-                    ty::ClosureArgsParts {
-                        parent_args,
-                        closure_kind_ty,
-                        closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
-                        tupled_upvars_ty,
-                    },
-                );
-
-                Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args)
-            }
-            hir::ClosureKind::Coroutine(_) => {
-                let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else {
-                    bug!("expected coroutine to have yield/resume types");
-                };
                 let interior = self.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: body.value.span,
@@ -209,9 +187,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     },
                 );
 
-                Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args)
+                (
+                    Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args),
+                    Some(CoroutineTypes { resume_ty, yield_ty }),
+                )
             }
-        }
+        };
+
+        check_fn(
+            &mut FnCtxt::new(self, self.param_env, closure.def_id),
+            liberated_sig,
+            coroutine_types,
+            closure.fn_decl,
+            expr_def_id,
+            body,
+            // Closure "rust-call" ABI doesn't support unsized params
+            false,
+        );
+
+        closure_ty
     }
 
     /// Given the expected type, figures out what it can about this closure we
@@ -683,10 +677,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     })
                 }
                 // All `gen {}` and `async gen {}` must return unit.
-                hir::ClosureKind::Coroutine(
-                    hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
-                    | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
-                ) => self.tcx.types.unit,
+                hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                    hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen,
+                    _,
+                )) => self.tcx.types.unit,
 
                 // For async blocks, we just fall back to `_` here.
                 // For closures/coroutines, we know nothing about the return
@@ -760,16 +754,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     get_future_output(obligation.predicate, obligation.cause.span)
                 })?
             }
+            ty::Alias(ty::Projection, _) => {
+                return Some(Ty::new_error_with_message(
+                    self.tcx,
+                    closure_span,
+                    "this projection should have been projected to an opaque type",
+                ));
+            }
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
                 .tcx
                 .explicit_item_bounds(def_id)
                 .iter_instantiated_copied(self.tcx, args)
                 .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             ty::Error(_) => return Some(ret_ty),
-            _ => span_bug!(
-                closure_span,
-                "async fn coroutine return type not an inference variable: {ret_ty}"
-            ),
+            _ => {
+                span_bug!(closure_span, "invalid async fn coroutine return type: {ret_ty:?}")
+            }
         };
 
         let output_ty = self.normalize(closure_span, output_ty);
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index ac8701a33d4..4b1ad28f094 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1526,13 +1526,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.check_repeat_element_needs_copy_bound(element, count, element_ty);
 
-        self.register_wf_obligation(
-            Ty::new_array_with_const_len(tcx, t, count).into(),
-            expr.span,
-            traits::WellFormed(None),
-        );
+        let ty = Ty::new_array_with_const_len(tcx, t, count);
+
+        self.register_wf_obligation(ty.into(), expr.span, traits::WellFormed(None));
 
-        Ty::new_array_with_const_len(tcx, t, count)
+        ty
     }
 
     fn check_repeat_element_needs_copy_bound(
@@ -2104,7 +2102,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut items = self
                 .tcx
                 .inherent_impls(def_id)
-                .iter()
+                .into_iter()
+                .flatten()
                 .flat_map(|i| self.tcx.associated_items(i).in_definition_order())
                 // Only assoc fn with no receivers.
                 .filter(|item| {
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index ed3dd1e39df..3ecf6c5e428 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -458,11 +458,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                             needs_to_be_read = true;
                         }
                     }
-                    PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => {
+                    PatKind::Or(_)
+                    | PatKind::Box(_)
+                    | PatKind::Ref(..)
+                    | PatKind::Wild
+                    | PatKind::Err(_) => {
                         // If the PatKind is Or, Box, or Ref, the decision is made later
                         // as these patterns contains subpatterns
-                        // If the PatKind is Wild, the decision is made based on the other patterns being
-                        // examined
+                        // If the PatKind is Wild or Err, the decision is made based on the other patterns
+                        // being examined
                     }
                 }
             })?
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index fde3d41faec..f3d70867e37 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -190,10 +190,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn errors_reported_since_creation(&self) -> bool {
         self.dcx().err_count() > self.err_count_on_creation
     }
-
-    pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        Ty::new_var(self.tcx, self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT))
-    }
 }
 
 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index ce3a4b4c80c..1ce0240f7b8 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -767,7 +767,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             | PatKind::Lit(..)
             | PatKind::Range(..)
             | PatKind::Never
-            | PatKind::Wild => {
+            | PatKind::Wild
+            | PatKind::Err(_) => {
                 // always ok
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 10c31d8c641..4dc802008d0 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -711,14 +711,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else {
             bug!("unexpected incoherent type: {:?}", self_ty)
         };
-        for &impl_def_id in self.tcx.incoherent_impls(simp) {
+        for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter().flatten() {
             self.assemble_inherent_impl_probe(impl_def_id);
         }
     }
 
     fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
-        let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id);
-        for &impl_def_id in impl_def_ids.iter() {
+        let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id).into_iter().flatten();
+        for &impl_def_id in impl_def_ids {
             self.assemble_inherent_impl_probe(impl_def_id);
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 3bf1e1312b3..0b8a25eedaf 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -359,7 +359,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     if let ty::Adt(adt_def, _) = ty.kind() {
                         self.tcx
                             .inherent_impls(adt_def.did())
-                            .iter()
+                            .into_iter()
+                            .flatten()
                             .any(|def_id| self.associated_value(*def_id, item_name).is_some())
                     } else {
                         false
@@ -1048,7 +1049,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let mut inherent_impls_candidate = self
                         .tcx
                         .inherent_impls(adt.did())
-                        .iter()
+                        .into_iter()
+                        .flatten()
                         .copied()
                         .filter(|def_id| {
                             if let Some(assoc) = self.associated_value(*def_id, item_name) {
@@ -1103,7 +1105,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             "the {item_kind} was found for\n{type_candidates}{additional_types}"
                         ));
                     } else {
-                        'outer: for inherent_impl_did in self.tcx.inherent_impls(adt.did()) {
+                        'outer: for inherent_impl_did in
+                            self.tcx.inherent_impls(adt.did()).into_iter().flatten()
+                        {
                             for inherent_method in
                                 self.tcx.associated_items(inherent_impl_did).in_definition_order()
                             {
@@ -1457,9 +1461,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
             return;
         };
-        let mut items = self
-            .tcx
-            .inherent_impls(adt_def.did())
+        // FIXME(oli-obk): try out bubbling this error up one level and cancelling the other error in that case.
+        let Ok(impls) = self.tcx.inherent_impls(adt_def.did()) else { return };
+        let mut items = impls
             .iter()
             .flat_map(|i| self.tcx.associated_items(i).in_definition_order())
             // Only assoc fn with no receivers.
@@ -1823,7 +1827,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             simplify_type(tcx, ty, TreatParams::AsCandidateKey)
                 .and_then(|simp| {
                     tcx.incoherent_impls(simp)
-                        .iter()
+                        .into_iter()
+                        .flatten()
                         .find_map(|&id| self.associated_value(id, item_name))
                 })
                 .is_some()
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 95813cb68a6..fe8c36dbe06 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -177,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin };
 
         let ty = match pat.kind {
-            PatKind::Wild => expected,
+            PatKind::Wild | PatKind::Err(_) => expected,
             // FIXME(never_patterns): check the type is uninhabited. If that is not possible within
             // typeck, do that in a later phase.
             PatKind::Never => expected,
@@ -325,6 +325,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatKind::Ref(..) => AdjustMode::Reset,
             // A `_` pattern works with any expected type, so there's no need to do anything.
             PatKind::Wild
+            // A malformed pattern doesn't have an expected type, so let's just accept any type.
+            | PatKind::Err(_)
             // Bindings also work with whatever the expected type is,
             // and moreover if we peel references off, that will give us the wrong binding type.
             // Also, we can have a subpattern `binding @ pat`.
@@ -754,7 +756,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         | PatKind::Box(..)
                         | PatKind::Ref(..)
                         | PatKind::Lit(..)
-                        | PatKind::Range(..) => break 'block None,
+                        | PatKind::Range(..)
+                        | PatKind::Err(_) => break 'block None,
                     },
 
                     // Don't provide suggestions in other cases
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index e85c940f1b5..03c8e08aa01 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -13,7 +13,9 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::infer::unify_key::{
+    ConstVariableOrigin, ConstVariableOriginKind, ConstVariableValue,
+};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::{self, InferConst};
@@ -178,17 +180,23 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
         }
     };
     printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
-    let const_getter = move |ct_vid| {
-        if infcx.probe_const_var(ct_vid).is_ok() {
+    let const_getter = move |ct_vid| match infcx
+        .inner
+        .borrow_mut()
+        .const_unification_table()
+        .probe_value(ct_vid)
+    {
+        ConstVariableValue::Known { value: _ } => {
             warn!("resolved const var in error message");
-        }
-        if let ConstVariableOriginKind::ConstParameterDefinition(name, _) =
-            infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind
-        {
-            return Some(name);
-        } else {
             None
         }
+        ConstVariableValue::Unknown { origin, universe: _ } => {
+            if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = origin.kind {
+                return Some(name);
+            } else {
+                None
+            }
+        }
     };
     printer.const_infer_name_resolver = Some(Box::new(const_getter));
     printer
@@ -303,7 +311,12 @@ impl<'tcx> InferCtxt<'tcx> {
             GenericArgKind::Const(ct) => {
                 if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
                     let origin =
-                        self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+                        match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
+                            ConstVariableValue::Known { value } => {
+                                bug!("resolved infer var: {vid:?} {value}")
+                            }
+                            ConstVariableValue::Unknown { origin, universe: _ } => origin,
+                        };
                     if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
                         origin.kind
                     {
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index c7cab048db1..d256994d8d1 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -146,14 +146,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         match ct.kind() {
             ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
-                let opt_ct = self
-                    .infcx
-                    .inner
-                    .borrow_mut()
-                    .const_unification_table()
-                    .probe_value(v)
-                    .val
-                    .known();
+                let opt_ct =
+                    self.infcx.inner.borrow_mut().const_unification_table().probe_value(v).known();
                 self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
             }
             ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 8ca97ae1b8e..99033922bdf 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -1,4 +1,4 @@
-use rustc_middle::infer::unify_key::ConstVidKey;
+use rustc_middle::infer::unify_key::{ConstVariableOriginKind, ConstVariableValue, ConstVidKey};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
 
@@ -28,10 +28,17 @@ fn const_vars_since_snapshot<'tcx>(
     snapshot_var_len: usize,
 ) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
     let range = vars_since_snapshot(table, snapshot_var_len);
+
     (
         range.start.vid..range.end.vid,
         (range.start.index()..range.end.index())
-            .map(|index| table.probe_value(ConstVid::from_u32(index)).origin)
+            .map(|index| match table.probe_value(ConstVid::from_u32(index)) {
+                ConstVariableValue::Known { value: _ } => ConstVariableOrigin {
+                    kind: ConstVariableOriginKind::MiscVariable,
+                    span: rustc_span::DUMMY_SP,
+                },
+                ConstVariableValue::Unknown { origin, universe: _ } => origin,
+            })
             .collect(),
     )
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index e164041c599..002aad19c49 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -23,8 +23,8 @@ use rustc_data_structures::unify as ut;
 use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
+use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::{select, DefiningAnchor};
@@ -1086,7 +1086,7 @@ impl<'tcx> InferCtxt<'tcx> {
             .inner
             .borrow_mut()
             .const_unification_table()
-            .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } })
+            .new_key(ConstVariableValue::Unknown { origin, universe })
             .vid;
         ty::Const::new_var(self.tcx, vid, ty)
     }
@@ -1095,10 +1095,7 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner
             .borrow_mut()
             .const_unification_table()
-            .new_key(ConstVarValue {
-                origin,
-                val: ConstVariableValue::Unknown { universe: self.universe() },
-            })
+            .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
             .vid
     }
 
@@ -1217,10 +1214,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     .inner
                     .borrow_mut()
                     .const_unification_table()
-                    .new_key(ConstVarValue {
-                        origin,
-                        val: ConstVariableValue::Unknown { universe: self.universe() },
-                    })
+                    .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
                     .vid;
                 ty::Const::new_var(
                     self.tcx,
@@ -1410,9 +1404,9 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
-        match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
+        match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
             ConstVariableValue::Known { value } => Ok(value),
-            ConstVariableValue::Unknown { universe } => Err(universe),
+            ConstVariableValue::Unknown { origin: _, universe } => Err(universe),
         }
     }
 
@@ -1709,7 +1703,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 // `ty::ConstKind::Infer(ty::InferConst::Var(v))`.
                 //
                 // Not `inlined_probe_value(v)` because this call site is colder.
-                match self.inner.borrow_mut().const_unification_table().probe_value(v).val {
+                match self.inner.borrow_mut().const_unification_table().probe_value(v) {
                     ConstVariableValue::Unknown { .. } => false,
                     ConstVariableValue::Known { .. } => true,
                 }
@@ -1876,7 +1870,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
                 .borrow_mut()
                 .const_unification_table()
                 .probe_value(vid)
-                .val
                 .known()
                 .unwrap_or(ct),
             ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 4b254fc7df5..9e1dab12b4d 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -30,14 +30,12 @@ use super::sub::Sub;
 use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
 use crate::traits::{Obligation, PredicateObligations};
 use rustc_middle::infer::canonical::OriginalQueryValues;
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{RelateResult, TypeRelation};
 use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{AliasRelationDirection, TyVar};
 use rustc_middle::ty::{IntType, UintType};
-use rustc_span::DUMMY_SP;
 
 #[derive(Clone)]
 pub struct CombineFields<'infcx, 'tcx> {
@@ -328,8 +326,12 @@ impl<'tcx> InferCtxt<'tcx> {
         ct: ty::Const<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        let span =
-            self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span;
+        let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) {
+            ConstVariableValue::Known { value } => {
+                bug!("instantiating a known const var: {target_vid:?} {value} {ct}")
+            }
+            ConstVariableValue::Unknown { origin, universe: _ } => origin.span,
+        };
         // FIXME(generic_const_exprs): Occurs check failures for unevaluated
         // constants and generic expressions are not yet handled correctly.
         let Generalization { value_may_be_infer: value, needs_wf: _ } = generalize::generalize(
@@ -340,16 +342,10 @@ impl<'tcx> InferCtxt<'tcx> {
             ty::Variance::Invariant,
         )?;
 
-        self.inner.borrow_mut().const_unification_table().union_value(
-            target_vid,
-            ConstVarValue {
-                origin: ConstVariableOrigin {
-                    kind: ConstVariableOriginKind::ConstInference,
-                    span: DUMMY_SP,
-                },
-                val: ConstVariableValue::Known { value },
-            },
-        );
+        self.inner
+            .borrow_mut()
+            .const_unification_table()
+            .union_value(target_vid, ConstVariableValue::Known { value });
         Ok(value)
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 27d37fd9369..417c8695e24 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -3,7 +3,7 @@ use std::mem;
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
+use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::visit::MaxUniverse;
@@ -431,22 +431,19 @@ where
 
                 let mut inner = self.infcx.inner.borrow_mut();
                 let variable_table = &mut inner.const_unification_table();
-                let var_value = variable_table.probe_value(vid);
-                match var_value.val {
+                match variable_table.probe_value(vid) {
                     ConstVariableValue::Known { value: u } => {
                         drop(inner);
                         self.relate(u, u)
                     }
-                    ConstVariableValue::Unknown { universe } => {
+                    ConstVariableValue::Unknown { origin, universe } => {
                         if self.for_universe.can_name(universe) {
                             Ok(c)
                         } else {
                             let new_var_id = variable_table
-                                .new_key(ConstVarValue {
-                                    origin: var_value.origin,
-                                    val: ConstVariableValue::Unknown {
-                                        universe: self.for_universe,
-                                    },
+                                .new_key(ConstVariableValue::Unknown {
+                                    origin,
+                                    universe: self.for_universe,
                                 })
                                 .vid;
                             Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index f317ccee691..959b0903127 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,12 +1,8 @@
-use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use super::{FixupError, FixupResult, InferCtxt, Span};
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use super::{FixupError, FixupResult, InferCtxt};
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitableExt, TypeVisitor};
+use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
 
-use std::ops::ControlFlow;
-
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC VAR RESOLVER
 
@@ -105,88 +101,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// UNRESOLVED TYPE FINDER
-
-/// The unresolved type **finder** walks a type searching for
-/// type variables that don't yet have a value. The first unresolved type is stored.
-/// It does not construct the fully resolved type (which might
-/// involve some hashing and so forth).
-pub struct UnresolvedTypeOrConstFinder<'a, 'tcx> {
-    infcx: &'a InferCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> UnresolvedTypeOrConstFinder<'a, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
-        UnresolvedTypeOrConstFinder { infcx }
-    }
-}
-
-impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
-    type BreakTy = (ty::Term<'tcx>, Option<Span>);
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let t = self.infcx.shallow_resolve(t);
-        if let ty::Infer(infer_ty) = *t.kind() {
-            // Since we called `shallow_resolve` above, this must
-            // be an (as yet...) unresolved inference variable.
-            let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty {
-                let mut inner = self.infcx.inner.borrow_mut();
-                let ty_vars = &inner.type_variables();
-                if let TypeVariableOrigin {
-                    kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
-                    span,
-                } = ty_vars.var_origin(ty_vid)
-                {
-                    Some(span)
-                } else {
-                    None
-                }
-            } else {
-                None
-            };
-            ControlFlow::Break((t.into(), ty_var_span))
-        } else if !t.has_non_region_infer() {
-            // All const/type variables in inference types must already be resolved,
-            // no need to visit the contents.
-            ControlFlow::Continue(())
-        } else {
-            // Otherwise, keep visiting.
-            t.super_visit_with(self)
-        }
-    }
-
-    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let ct = self.infcx.shallow_resolve(ct);
-        if let ty::ConstKind::Infer(i) = ct.kind() {
-            // Since we called `shallow_resolve` above, this must
-            // be an (as yet...) unresolved inference variable.
-            let ct_var_span = if let ty::InferConst::Var(vid) = i {
-                let mut inner = self.infcx.inner.borrow_mut();
-                let ct_vars = &mut inner.const_unification_table();
-                if let ConstVariableOrigin {
-                    span,
-                    kind: ConstVariableOriginKind::ConstParameterDefinition(_, _),
-                } = ct_vars.probe_value(vid).origin
-                {
-                    Some(span)
-                } else {
-                    None
-                }
-            } else {
-                None
-            };
-            ControlFlow::Break((ct.into(), ct_var_span))
-        } else if !ct.has_non_region_infer() {
-            // All const/type variables in inference types must already be resolved,
-            // no need to visit the contents.
-            ControlFlow::Continue(())
-        } else {
-            // Otherwise, keep visiting.
-            ct.super_visit_with(self)
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
 // FULL TYPE RESOLUTION
 
 /// Full type resolution replaces all type and region variables with
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 32fba6ade88..5ca88090996 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -218,7 +218,9 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
             }
         }
 
-        if values.is_empty() && !values_any_specified && !any_specified {
+        if !values_specified && !any_specified {
+            // `cfg(name)` is equivalent to `cfg(name, values(none()))` so add
+            // an implicit `none()`
             values.insert(None);
         } else if !values.is_empty() && values_any_specified {
             error!(
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 588139a303c..555c822ad6d 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -4,10 +4,10 @@ use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
 use rustc_session::config::{
     build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
-    DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
-    FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
-    LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy,
-    Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
+    CollapseMacroDebuginfo, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry,
+    ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage,
+    InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig,
+    OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
     ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
 };
 use rustc_session::lint::Level;
@@ -742,6 +742,7 @@ fn test_unstable_options_tracking_hash() {
         })
     );
     tracked!(codegen_backend, Some("abc".to_string()));
+    tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes);
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
     tracked!(debug_info_for_profiling, true);
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index abec12f52a6..0a632c4d12a 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -59,6 +59,9 @@ pub enum EscapeError {
     /// Non-ascii character in byte literal, byte string literal, or raw byte string literal.
     NonAsciiCharInByte,
 
+    // `\0` in a C string literal.
+    NulInCStr,
+
     /// After a line ending with '\', the next line contains whitespace
     /// characters that are not skipped.
     UnskippedWhitespaceWarning,
@@ -122,10 +125,20 @@ where
 {
     match mode {
         CStr => {
-            unescape_non_raw_common(src, mode, callback);
+            unescape_non_raw_common(src, mode, &mut |r, mut result| {
+                if let Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) = result {
+                    result = Err(EscapeError::NulInCStr);
+                }
+                callback(r, result)
+            });
         }
         RawCStr => {
-            check_raw_common(src, mode, &mut |r, result| callback(r, result.map(CStrUnit::Char)));
+            check_raw_common(src, mode, &mut |r, mut result| {
+                if let Ok('\0') = result {
+                    result = Err(EscapeError::NulInCStr);
+                }
+                callback(r, result.map(CStrUnit::Char))
+            });
         }
         Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(),
     }
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 9e6a6f70eac..312874db3f5 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -354,6 +354,15 @@ pub(super) fn builtin(
                         Applicability::MaybeIncorrect,
                     );
                 }
+            } else {
+                db.note(format!("no expected values for `{name}`"));
+
+                let sp = if let Some((_value, value_span)) = value {
+                    name_span.to(value_span)
+                } else {
+                    name_span
+                };
+                db.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect);
             }
 
             // We don't want to suggest adding values to well known names
@@ -373,6 +382,8 @@ pub(super) fn builtin(
                 if name == sym::feature {
                     if let Some((value, _value_span)) = value {
                         db.help(format!("consider adding `{value}` as a feature in `Cargo.toml`"));
+                    } else {
+                        db.help("consider defining some features in `Cargo.toml`");
                     }
                 } else if !is_cfg_a_well_know_name {
                     db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 0f4528d1d5c..39decf1faab 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1166,7 +1166,7 @@ impl EarlyLintPass for UnusedParens {
             // Do not lint on `(..)` as that will result in the other arms being useless.
             Paren(_)
             // The other cases do not contain sub-patterns.
-            | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
+            | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
             // These are list-like patterns; parens can always be removed.
             TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
                 self.check_unused_parens_pat(cx, p, false, false, keep_space);
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 49e849964be..20e3ae3ba94 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1027,6 +1027,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             self.root.edition,
             Symbol::intern(name),
             &attrs,
+            false,
         )
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 912c2f36eb3..c3d6c21c402 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -283,7 +283,7 @@ provide! { tcx, def_id, other, cdata,
         tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index))
     }
     associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
-    inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
+    inherent_impls => { Ok(cdata.get_inherent_implementations_for_type(tcx, def_id.index)) }
     item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
     is_mir_available => { cdata.is_item_mir_available(def_id.index) }
     is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
@@ -328,7 +328,7 @@ provide! { tcx, def_id, other, cdata,
     traits => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
     trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) }
     implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
-    crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) }
+    crate_incoherent_impls => { Ok(cdata.get_incoherent_impls(tcx, other)) }
 
     dep_kind => { cdata.dep_kind }
     module_children => {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index a458b528a97..2d4e49e27d9 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1485,7 +1485,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
 
         let inherent_impls = tcx.with_stable_hashing_context(|hcx| {
-            tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true)
+            tcx.crate_inherent_impls(()).unwrap().inherent_impls.to_sorted(&hcx, true)
         });
         for (def_id, impls) in inherent_impls {
             record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| {
@@ -2028,7 +2028,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let all_impls = tcx.with_stable_hashing_context(|hcx| {
-            tcx.crate_inherent_impls(()).incoherent_impls.to_sorted(&hcx, true)
+            tcx.crate_inherent_impls(()).unwrap().incoherent_impls.to_sorted(&hcx, true)
         });
 
         let all_impls: Vec<_> = all_impls
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 8a4fd01437f..e745913fabc 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -114,6 +114,7 @@ macro_rules! arena_types {
             [] mod_child: rustc_middle::metadata::ModChild,
             [] features: rustc_feature::Features,
             [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph,
+            [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls,
         ]);
     )
 }
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 6e50e894046..c35799ef47f 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -120,7 +120,7 @@ pub enum ConstVariableOriginKind {
 #[derive(Copy, Clone, Debug)]
 pub enum ConstVariableValue<'tcx> {
     Known { value: ty::Const<'tcx> },
-    Unknown { universe: ty::UniverseIndex },
+    Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
 }
 
 impl<'tcx> ConstVariableValue<'tcx> {
@@ -134,12 +134,6 @@ impl<'tcx> ConstVariableValue<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct ConstVarValue<'tcx> {
-    pub origin: ConstVariableOrigin,
-    pub val: ConstVariableValue<'tcx>,
-}
-
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub struct ConstVidKey<'tcx> {
     pub vid: ty::ConstVid,
@@ -153,7 +147,7 @@ impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> {
 }
 
 impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
-    type Value = ConstVarValue<'tcx>;
+    type Value = ConstVariableValue<'tcx>;
     #[inline]
     fn index(&self) -> u32 {
         self.vid.as_u32()
@@ -167,23 +161,23 @@ impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
     }
 }
 
-impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
+impl<'tcx> UnifyValue for ConstVariableValue<'tcx> {
     type Error = NoError;
 
     fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
-        Ok(match (value1.val, value2.val) {
+        match (value1, value2) {
             (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
                 bug!("equating two const variables, both of which have known values")
             }
 
             // If one side is known, prefer that one.
-            (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => value1,
-            (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2,
+            (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(value1),
+            (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(value2),
 
             // If both sides are *unknown*, it hardly matters, does it?
             (
-                ConstVariableValue::Unknown { universe: universe1 },
-                ConstVariableValue::Unknown { universe: universe2 },
+                ConstVariableValue::Unknown { origin, universe: universe1 },
+                ConstVariableValue::Unknown { origin: _, universe: universe2 },
             ) => {
                 // If we unify two unbound variables, ?T and ?U, then whatever
                 // value they wind up taking (which must be the same value) must
@@ -191,12 +185,9 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
                 // universe is the minimum of the two universes, because that is
                 // the one which contains the fewest names in scope.
                 let universe = cmp::min(universe1, universe2);
-                ConstVarValue {
-                    val: ConstVariableValue::Unknown { universe },
-                    origin: value1.origin,
-                }
+                Ok(ConstVariableValue::Unknown { origin, universe })
             }
-        })
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 239929a2c0e..2cf6410990e 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -142,15 +142,17 @@ fn dump_matched_mir_node<'tcx, F>(
     }
 }
 
-/// Returns the file basename portion (without extension) of a filename path
-/// where we should dump a MIR representation output files.
-fn dump_file_basename<'tcx>(
+/// Returns the path to the filename where we should dump a given MIR.
+/// Also used by other bits of code (e.g., NLL inference) that dump
+/// graphviz data or other things.
+fn dump_path<'tcx>(
     tcx: TyCtxt<'tcx>,
+    extension: &str,
     pass_num: bool,
     pass_name: &str,
     disambiguator: &dyn Display,
     body: &Body<'tcx>,
-) -> String {
+) -> PathBuf {
     let source = body.source;
     let promotion_id = match source.promoted {
         Some(id) => format!("-{id:?}"),
@@ -186,32 +188,31 @@ fn dump_file_basename<'tcx>(
         _ => String::new(),
     };
 
-    format!(
-        "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}",
-    )
-}
-
-/// Returns the path to the filename where we should dump a given MIR.
-/// Also used by other bits of code (e.g., NLL inference) that dump
-/// graphviz data or other things.
-fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf {
     let mut file_path = PathBuf::new();
     file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir));
 
-    let file_name = format!("{basename}.{extension}",);
+    let file_name = format!(
+        "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}",
+    );
 
     file_path.push(&file_name);
 
     file_path
 }
 
-/// Attempts to open the MIR dump file with the given name and extension.
-fn create_dump_file_with_basename(
-    tcx: TyCtxt<'_>,
-    file_basename: &str,
+/// Attempts to open a file where we should dump a given MIR or other
+/// bit of MIR-related data. Used by `mir-dump`, but also by other
+/// bits of code (e.g., NLL inference) that dump graphviz data or
+/// other things, and hence takes the extension as an argument.
+pub fn create_dump_file<'tcx>(
+    tcx: TyCtxt<'tcx>,
     extension: &str,
+    pass_num: bool,
+    pass_name: &str,
+    disambiguator: &dyn Display,
+    body: &Body<'tcx>,
 ) -> io::Result<io::BufWriter<fs::File>> {
-    let file_path = dump_path(tcx, file_basename, extension);
+    let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body);
     if let Some(parent) = file_path.parent() {
         fs::create_dir_all(parent).map_err(|e| {
             io::Error::new(
@@ -225,25 +226,6 @@ fn create_dump_file_with_basename(
     })?))
 }
 
-/// Attempts to open a file where we should dump a given MIR or other
-/// bit of MIR-related data. Used by `mir-dump`, but also by other
-/// bits of code (e.g., NLL inference) that dump graphviz data or
-/// other things, and hence takes the extension as an argument.
-pub fn create_dump_file<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    extension: &str,
-    pass_num: bool,
-    pass_name: &str,
-    disambiguator: &dyn Display,
-    body: &Body<'tcx>,
-) -> io::Result<io::BufWriter<fs::File>> {
-    create_dump_file_with_basename(
-        tcx,
-        &dump_file_basename(tcx, pass_num, pass_name, disambiguator, body),
-        extension,
-    )
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Whole MIR bodies
 
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index b9200f1abf1..52c180f94bb 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -74,10 +74,18 @@ impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> {
     type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()];
 }
 
+impl<T> EraseType for Result<&'_ [T], traits::query::NoSolution> {
+    type Result = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()];
+}
+
 impl<T> EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> {
     type Result = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()];
 }
 
+impl<T> EraseType for Result<&'_ [T], rustc_errors::ErrorGuaranteed> {
+    type Result = [u8; size_of::<Result<&'static [()], rustc_errors::ErrorGuaranteed>>()];
+}
+
 impl<T> EraseType for Result<&'_ T, traits::CodegenObligationError> {
     type Result = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()];
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 1dc77220881..9c7eeb72b79 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -859,13 +859,13 @@ rustc_queries! {
     /// Maps a `DefId` of a type to a list of its inherent impls.
     /// Contains implementations of methods that are inherent to a type.
     /// Methods in these implementations don't need to be exported.
-    query inherent_impls(key: DefId) -> &'tcx [DefId] {
+    query inherent_impls(key: DefId) -> Result<&'tcx [DefId], ErrorGuaranteed> {
         desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
-    query incoherent_impls(key: SimplifiedType) -> &'tcx [DefId] {
+    query incoherent_impls(key: SimplifiedType) -> Result<&'tcx [DefId], ErrorGuaranteed> {
         desc { |tcx| "collecting all inherent impls for `{:?}`", key }
     }
 
@@ -961,8 +961,9 @@ rustc_queries! {
         desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) }
     }
 
-    query check_mod_impl_wf(key: LocalModDefId) -> () {
+    query check_mod_impl_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
+        ensure_forwards_result_if_red
     }
 
     query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> {
@@ -1011,15 +1012,16 @@ rustc_queries! {
 
     /// Gets a complete map from all types to their inherent impls.
     /// Not meant to be used directly outside of coherence.
-    query crate_inherent_impls(k: ()) -> &'tcx CrateInherentImpls {
-        arena_cache
+    query crate_inherent_impls(k: ()) -> Result<&'tcx CrateInherentImpls, ErrorGuaranteed> {
         desc { "finding all inherent impls defined in crate" }
+        ensure_forwards_result_if_red
     }
 
     /// Checks all types in the crate for overlap in their inherent impls. Reports errors.
     /// Not meant to be used directly outside of coherence.
-    query crate_inherent_impls_overlap_check(_: ()) -> () {
+    query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> {
         desc { "check for overlap between inherent impls defined in this crate" }
+        ensure_forwards_result_if_red
     }
 
     /// Checks whether all impls in the crate pass the overlap check, returning
@@ -1645,7 +1647,7 @@ rustc_queries! {
     ///
     /// Do not call this directly, but instead use the `incoherent_impls` query.
     /// This query is only used to get the data necessary for that query.
-    query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> &'tcx [DefId] {
+    query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> Result<&'tcx [DefId], ErrorGuaranteed> {
         desc { |tcx| "collecting all impls for a type in a crate" }
         separate_provide_extern
     }
@@ -1949,7 +1951,7 @@ rustc_queries! {
         desc { "normalizing `{}`", goal.value }
     }
 
-    query implied_outlives_bounds(
+    query implied_outlives_bounds_compat(
         goal: CanonicalTyGoal<'tcx>
     ) -> Result<
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
@@ -1958,6 +1960,15 @@ rustc_queries! {
         desc { "computing implied outlives bounds for `{}`", goal.value.value }
     }
 
+    query implied_outlives_bounds(
+        goal: CanonicalTyGoal<'tcx>
+    ) -> Result<
+        &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
+        NoSolution,
+    > {
+        desc { "computing implied outlives bounds v2 for `{}`", goal.value.value }
+    }
+
     /// Do not call this query directly:
     /// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead.
     query dropck_outlives(
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index a41d4f1ad58..8d88488e167 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -174,7 +174,7 @@ pub fn query_ensure<'tcx, Cache>(
 }
 
 #[inline]
-pub fn query_ensure_error_guaranteed<'tcx, Cache>(
+pub fn query_ensure_error_guaranteed<'tcx, Cache, T>(
     tcx: TyCtxt<'tcx>,
     execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
     query_cache: &Cache,
@@ -182,14 +182,16 @@ pub fn query_ensure_error_guaranteed<'tcx, Cache>(
     check_cache: bool,
 ) -> Result<(), ErrorGuaranteed>
 where
-    Cache: QueryCache<Value = super::erase::Erase<Result<(), ErrorGuaranteed>>>,
+    Cache: QueryCache<Value = super::erase::Erase<Result<T, ErrorGuaranteed>>>,
+    Result<T, ErrorGuaranteed>: EraseType,
 {
     let key = key.into_query_param();
     if let Some(res) = try_get_cached(tcx, query_cache, &key) {
-        super::erase::restore(res)
+        super::erase::restore(res).map(drop)
     } else {
         execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache })
             .map(super::erase::restore)
+            .map(|res| res.map(drop))
             // Either we actually executed the query, which means we got a full `Result`,
             // or we can just assume the query succeeded, because it was green in the
             // incremental cache. If it is green, that means that the previous compilation
@@ -205,7 +207,7 @@ macro_rules! query_ensure {
         query_ensure($($args)*)
     };
     ([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => {
-        query_ensure_error_guaranteed($($args)*)
+        query_ensure_error_guaranteed($($args)*).map(|_| ())
     };
     ([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
         query_ensure!([$($modifiers)*]$($args)*)
@@ -667,5 +669,7 @@ mod sealed {
 
 pub use sealed::IntoQueryParam;
 
+use super::erase::EraseType;
+
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct CyclePlaceholder(pub ErrorGuaranteed);
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 5f02dd22961..61d96cad57d 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -191,7 +191,7 @@ pub struct NormalizationResult<'tcx> {
 /// case they are called implied bounds). They are fed to the
 /// `OutlivesEnv` which in turn is supplied to the region checker and
 /// other parts of the inference system.
-#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
 pub enum OutlivesBound<'tcx> {
     RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
     RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ad9296a4cc8..a5d9e0fcf44 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2535,8 +2535,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() {
             return span;
         }
-        let collapse_debuginfo_enabled = self.features().collapse_debuginfo;
-        hygiene::walk_chain_collapsed(span, upto, collapse_debuginfo_enabled)
+        hygiene::walk_chain_collapsed(span, upto, self.features().collapse_debuginfo)
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 6c9000c45f6..4028de27cae 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1013,7 +1013,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                                 .extend(
                                     // Group the return ty with its def id, if we had one.
                                     entry.return_ty.map(|ty| {
-                                        (tcx.require_lang_item(LangItem::FnOnce, None), ty)
+                                        (tcx.require_lang_item(LangItem::FnOnceOutput, None), ty)
                                     }),
                                 );
                         }
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 227a0753d04..d85b541d363 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -254,16 +254,28 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
 }
 
 /// Query provider for `incoherent_impls`.
-pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
+pub(super) fn incoherent_impls_provider(
+    tcx: TyCtxt<'_>,
+    simp: SimplifiedType,
+) -> Result<&[DefId], ErrorGuaranteed> {
     let mut impls = Vec::new();
 
+    let mut res = Ok(());
     for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) {
-        for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) {
+        let incoherent_impls = match tcx.crate_incoherent_impls((cnum, simp)) {
+            Ok(impls) => impls,
+            Err(e) => {
+                res = Err(e);
+                continue;
+            }
+        };
+        for &impl_def_id in incoherent_impls {
             impls.push(impl_def_id)
         }
     }
 
     debug!(?impls);
+    res?;
 
-    tcx.arena.alloc_slice(&impls)
+    Ok(tcx.arena.alloc_slice(&impls))
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index c4987634b78..ff7e985bdfd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -345,6 +345,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
 
             hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
+
+            hir::PatKind::Err(guar) => PatKind::Error(guar),
         };
 
         Box::new(Pat { span, ty, kind })
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index f0b21fd4184..b805f8ca23e 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -34,6 +34,7 @@ mod errors;
 mod framework;
 pub mod impls;
 pub mod move_paths;
+pub mod points;
 pub mod rustc_peek;
 pub mod storage;
 pub mod un_derefer;
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
new file mode 100644
index 00000000000..ff17ce1fe07
--- /dev/null
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -0,0 +1,156 @@
+use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor};
+use rustc_index::bit_set::ChunkedBitSet;
+use rustc_index::interval::SparseIntervalMatrix;
+use rustc_index::Idx;
+use rustc_index::IndexVec;
+use rustc_middle::mir::{self, BasicBlock, Body, Location};
+
+/// Maps between a `Location` and a `PointIndex` (and vice versa).
+pub struct DenseLocationMap {
+    /// For each basic block, how many points are contained within?
+    statements_before_block: IndexVec<BasicBlock, usize>,
+
+    /// Map backward from each point to the basic block that it
+    /// belongs to.
+    basic_blocks: IndexVec<PointIndex, BasicBlock>,
+
+    num_points: usize,
+}
+
+impl DenseLocationMap {
+    #[inline]
+    pub fn new(body: &Body<'_>) -> Self {
+        let mut num_points = 0;
+        let statements_before_block: IndexVec<BasicBlock, usize> = body
+            .basic_blocks
+            .iter()
+            .map(|block_data| {
+                let v = num_points;
+                num_points += block_data.statements.len() + 1;
+                v
+            })
+            .collect();
+
+        let mut basic_blocks = IndexVec::with_capacity(num_points);
+        for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
+            basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
+        }
+
+        Self { statements_before_block, basic_blocks, num_points }
+    }
+
+    /// Total number of point indices
+    #[inline]
+    pub fn num_points(&self) -> usize {
+        self.num_points
+    }
+
+    /// Converts a `Location` into a `PointIndex`. O(1).
+    #[inline]
+    pub fn point_from_location(&self, location: Location) -> PointIndex {
+        let Location { block, statement_index } = location;
+        let start_index = self.statements_before_block[block];
+        PointIndex::new(start_index + statement_index)
+    }
+
+    /// Returns the `PointIndex` for the first statement in the given `BasicBlock`. O(1).
+    #[inline]
+    pub fn entry_point(&self, block: BasicBlock) -> PointIndex {
+        let start_index = self.statements_before_block[block];
+        PointIndex::new(start_index)
+    }
+
+    /// Return the PointIndex for the block start of this index.
+    #[inline]
+    pub fn to_block_start(&self, index: PointIndex) -> PointIndex {
+        PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
+    }
+
+    /// Converts a `PointIndex` back to a location. O(1).
+    #[inline]
+    pub fn to_location(&self, index: PointIndex) -> Location {
+        assert!(index.index() < self.num_points);
+        let block = self.basic_blocks[index];
+        let start_index = self.statements_before_block[block];
+        let statement_index = index.index() - start_index;
+        Location { block, statement_index }
+    }
+
+    /// Sometimes we get point-indices back from bitsets that may be
+    /// out of range (because they round up to the nearest 2^N number
+    /// of bits). Use this function to filter such points out if you
+    /// like.
+    #[inline]
+    pub fn point_in_range(&self, index: PointIndex) -> bool {
+        index.index() < self.num_points
+    }
+}
+
+rustc_index::newtype_index! {
+    /// A single integer representing a `Location` in the MIR control-flow
+    /// graph. Constructed efficiently from `DenseLocationMap`.
+    #[orderable]
+    #[debug_format = "PointIndex({})"]
+    pub struct PointIndex {}
+}
+
+/// Add points depending on the result of the given dataflow analysis.
+pub fn save_as_intervals<'tcx, N, R>(
+    elements: &DenseLocationMap,
+    body: &mir::Body<'tcx>,
+    mut results: R,
+) -> SparseIntervalMatrix<N, PointIndex>
+where
+    N: Idx,
+    R: ResultsVisitable<'tcx, FlowState = ChunkedBitSet<N>>,
+{
+    let values = SparseIntervalMatrix::new(elements.num_points());
+    let mut visitor = Visitor { elements, values };
+    visit_results(
+        body,
+        body.basic_blocks.reverse_postorder().iter().copied(),
+        &mut results,
+        &mut visitor,
+    );
+    visitor.values
+}
+
+struct Visitor<'a, N: Idx> {
+    elements: &'a DenseLocationMap,
+    values: SparseIntervalMatrix<N, PointIndex>,
+}
+
+impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
+where
+    N: Idx,
+{
+    type FlowState = ChunkedBitSet<N>;
+
+    fn visit_statement_after_primary_effect(
+        &mut self,
+        _results: &mut R,
+        state: &Self::FlowState,
+        _statement: &'mir mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        let point = self.elements.point_from_location(location);
+        // Use internal iterator manually as it is much more efficient.
+        state.iter().for_each(|node| {
+            self.values.insert(node, point);
+        });
+    }
+
+    fn visit_terminator_after_primary_effect(
+        &mut self,
+        _results: &mut R,
+        state: &Self::FlowState,
+        _terminator: &'mir mir::Terminator<'tcx>,
+        location: Location,
+    ) {
+        let point = self.elements.point_from_location(location);
+        // Use internal iterator manually as it is much more efficient.
+        state.iter().for_each(|node| {
+            self.values.insert(node, point);
+        });
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 2cc76f30fcf..0ac4ab61d40 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -134,6 +134,7 @@
 use crate::MirPass;
 use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry};
 use rustc_index::bit_set::BitSet;
+use rustc_index::interval::SparseIntervalMatrix;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::HasLocalDecls;
 use rustc_middle::mir::{dump_mir, PassWhere};
@@ -143,7 +144,8 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::MaybeLiveLocals;
-use rustc_mir_dataflow::{Analysis, ResultsCursor};
+use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex};
+use rustc_mir_dataflow::Analysis;
 
 pub struct DestinationPropagation;
 
@@ -167,6 +169,13 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
 
         let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
 
+        let live = MaybeLiveLocals
+            .into_engine(tcx, body)
+            .pass_name("MaybeLiveLocals-DestinationPropagation")
+            .iterate_to_fixpoint();
+        let points = DenseLocationMap::new(body);
+        let mut live = save_as_intervals(&points, body, live);
+
         // In order to avoid having to collect data for every single pair of locals in the body, we
         // do not allow doing more than one merge for places that are derived from the same local at
         // once. To avoid missed opportunities, we instead iterate to a fixed point - we'll refer to
@@ -190,22 +199,19 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
                 &mut allocations.candidates_reverse,
             );
             trace!(?candidates);
-            let mut live = MaybeLiveLocals
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint()
-                .into_results_cursor(body);
-            dest_prop_mir_dump(tcx, body, &mut live, round_count);
+            dest_prop_mir_dump(tcx, body, &points, &live, round_count);
 
             FilterInformation::filter_liveness(
                 &mut candidates,
-                &mut live,
+                &points,
+                &live,
                 &mut allocations.write_info,
                 body,
             );
 
-            // Because we do not update liveness information, it is unsound to use a local for more
-            // than one merge operation within a single round of optimizations. We store here which
-            // ones we have already used.
+            // Because we only filter once per round, it is unsound to use a local for more than
+            // one merge operation within a single round of optimizations. We store here which ones
+            // we have already used.
             let mut merged_locals: BitSet<Local> = BitSet::new_empty(body.local_decls.len());
 
             // This is the set of merges we will apply this round. It is a subset of the candidates.
@@ -224,9 +230,15 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
                 }) {
                     break;
                 }
+
+                // Replace `src` by `dest` everywhere.
                 merges.insert(*src, *dest);
                 merged_locals.insert(*src);
                 merged_locals.insert(*dest);
+
+                // Update liveness information based on the merge we just performed.
+                // Every location where `src` was live, `dest` will be live.
+                live.union_rows(*src, *dest);
             }
             trace!(merging = ?merges);
 
@@ -349,7 +361,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> {
 
 struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
     body: &'body Body<'tcx>,
-    live: &'a mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>,
+    points: &'a DenseLocationMap,
+    live: &'a SparseIntervalMatrix<Local, PointIndex>,
     candidates: &'a mut Candidates<'alloc>,
     write_info: &'alloc mut WriteInfo,
     at: Location,
@@ -452,12 +465,14 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
     /// locals as also being read from.
     fn filter_liveness<'b>(
         candidates: &mut Candidates<'alloc>,
-        live: &mut ResultsCursor<'b, 'tcx, MaybeLiveLocals>,
+        points: &DenseLocationMap,
+        live: &SparseIntervalMatrix<Local, PointIndex>,
         write_info_alloc: &'alloc mut WriteInfo,
         body: &'b Body<'tcx>,
     ) {
         let mut this = FilterInformation {
             body,
+            points,
             live,
             candidates,
             // We don't actually store anything at this scope, we just keep things here to be able
@@ -472,13 +487,11 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
     fn internal_filter_liveness(&mut self) {
         for (block, data) in traversal::preorder(self.body) {
             self.at = Location { block, statement_index: data.statements.len() };
-            self.live.seek_after_primary_effect(self.at);
             self.write_info.for_terminator(&data.terminator().kind);
             self.apply_conflicts();
 
             for (i, statement) in data.statements.iter().enumerate().rev() {
                 self.at = Location { block, statement_index: i };
-                self.live.seek_after_primary_effect(self.at);
                 self.write_info.for_statement(&statement.kind, self.body);
                 self.apply_conflicts();
             }
@@ -497,6 +510,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
                     None
                 }
             });
+            let at = self.points.point_from_location(self.at);
             self.candidates.filter_candidates_by(
                 *p,
                 |q| {
@@ -508,7 +522,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
                     // calls or inline asm. Because of this, we also mark locals as
                     // conflicting when both of them are written to in the same
                     // statement.
-                    if self.live.contains(q) || writes.contains(&q) {
+                    if self.live.contains(q, at) || writes.contains(&q) {
                         CandidateFilter::Remove
                     } else {
                         CandidateFilter::Keep
@@ -801,38 +815,17 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool {
 fn dest_prop_mir_dump<'body, 'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &'body Body<'tcx>,
-    live: &mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>,
+    points: &DenseLocationMap,
+    live: &SparseIntervalMatrix<Local, PointIndex>,
     round: usize,
 ) {
-    let mut reachable = None;
+    let locals_live_at = |location| {
+        let location = points.point_from_location(location);
+        live.rows().filter(|&r| live.contains(r, location)).collect::<Vec<_>>()
+    };
     dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| {
-        let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
-
-        match pass_where {
-            PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => {
-                live.seek_after_primary_effect(loc);
-                writeln!(w, "        // live: {:?}", live.get())?;
-            }
-            PassWhere::AfterTerminator(bb) if reachable.contains(bb) => {
-                let loc = body.terminator_loc(bb);
-                live.seek_before_primary_effect(loc);
-                writeln!(w, "        // live: {:?}", live.get())?;
-            }
-
-            PassWhere::BeforeBlock(bb) if reachable.contains(bb) => {
-                live.seek_to_block_start(bb);
-                writeln!(w, "    // live: {:?}", live.get())?;
-            }
-
-            PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {}
-
-            PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => {
-                writeln!(w, "        // live: <unreachable>")?;
-            }
-
-            PassWhere::BeforeBlock(_) => {
-                writeln!(w, "    // live: <unreachable>")?;
-            }
+        if let PassWhere::BeforeLocation(loc) = pass_where {
+            writeln!(w, "        // live: {:?}", locals_live_at(loc))?;
         }
 
         Ok(())
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index dc3af038d80..390ec3e1a36 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -345,11 +345,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         Some(self.insert(Value::Constant { value, disambiguator }))
     }
 
+    fn insert_bool(&mut self, flag: bool) -> VnIndex {
+        // Booleans are deterministic.
+        self.insert(Value::Constant { value: Const::from_bool(self.tcx, flag), disambiguator: 0 })
+    }
+
     fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex {
         self.insert_constant(Const::from_scalar(self.tcx, scalar, ty))
             .expect("scalars are deterministic")
     }
 
+    fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex {
+        self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::from_u32(0), values))
+    }
+
     #[instrument(level = "trace", skip(self), ret)]
     fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
         use Value::*;
@@ -767,10 +776,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
 
             // Operations.
-            Rvalue::Len(ref mut place) => {
-                let place = self.simplify_place_value(place, location)?;
-                Value::Len(place)
-            }
+            Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
             Rvalue::Cast(kind, ref mut value, to) => {
                 let from = value.ty(self.local_decls, self.tcx);
                 let value = self.simplify_operand(value, location)?;
@@ -785,17 +791,36 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 Value::Cast { kind, value, from, to }
             }
             Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
+                let ty = lhs.ty(self.local_decls, self.tcx);
                 let lhs = self.simplify_operand(lhs, location);
                 let rhs = self.simplify_operand(rhs, location);
-                Value::BinaryOp(op, lhs?, rhs?)
+                // Only short-circuit options after we called `simplify_operand`
+                // on both operands for side effect.
+                let lhs = lhs?;
+                let rhs = rhs?;
+                if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
+                    return Some(value);
+                }
+                Value::BinaryOp(op, lhs, rhs)
             }
             Rvalue::CheckedBinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
+                let ty = lhs.ty(self.local_decls, self.tcx);
                 let lhs = self.simplify_operand(lhs, location);
                 let rhs = self.simplify_operand(rhs, location);
-                Value::CheckedBinaryOp(op, lhs?, rhs?)
+                // Only short-circuit options after we called `simplify_operand`
+                // on both operands for side effect.
+                let lhs = lhs?;
+                let rhs = rhs?;
+                if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {
+                    return Some(value);
+                }
+                Value::CheckedBinaryOp(op, lhs, rhs)
             }
             Rvalue::UnaryOp(op, ref mut arg) => {
                 let arg = self.simplify_operand(arg, location)?;
+                if let Some(value) = self.simplify_unary(op, arg) {
+                    return Some(value);
+                }
                 Value::UnaryOp(op, arg)
             }
             Rvalue::Discriminant(ref mut place) => {
@@ -894,6 +919,150 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         Some(self.insert(Value::Aggregate(ty, variant_index, fields)))
     }
+
+    #[instrument(level = "trace", skip(self), ret)]
+    fn simplify_unary(&mut self, op: UnOp, value: VnIndex) -> Option<VnIndex> {
+        let value = match (op, self.get(value)) {
+            (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(*inner),
+            (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(*inner),
+            (UnOp::Not, Value::BinaryOp(BinOp::Eq, lhs, rhs)) => {
+                Value::BinaryOp(BinOp::Ne, *lhs, *rhs)
+            }
+            (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => {
+                Value::BinaryOp(BinOp::Eq, *lhs, *rhs)
+            }
+            _ => return None,
+        };
+
+        Some(self.insert(value))
+    }
+
+    #[instrument(level = "trace", skip(self), ret)]
+    fn simplify_binary(
+        &mut self,
+        op: BinOp,
+        checked: bool,
+        lhs_ty: Ty<'tcx>,
+        lhs: VnIndex,
+        rhs: VnIndex,
+    ) -> Option<VnIndex> {
+        // Floats are weird enough that none of the logic below applies.
+        let reasonable_ty =
+            lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char() || lhs_ty.is_any_ptr();
+        if !reasonable_ty {
+            return None;
+        }
+
+        let layout = self.ecx.layout_of(lhs_ty).ok()?;
+
+        let as_bits = |value| {
+            let constant = self.evaluated[value].as_ref()?;
+            if layout.abi.is_scalar() {
+                let scalar = self.ecx.read_scalar(constant).ok()?;
+                scalar.to_bits(constant.layout.size).ok()
+            } else {
+                // `constant` is a wide pointer. Do not evaluate to bits.
+                None
+            }
+        };
+
+        // Represent the values as `Left(bits)` or `Right(VnIndex)`.
+        use Either::{Left, Right};
+        let a = as_bits(lhs).map_or(Right(lhs), Left);
+        let b = as_bits(rhs).map_or(Right(rhs), Left);
+        let result = match (op, a, b) {
+            // Neutral elements.
+            (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p))
+            | (
+                BinOp::Add
+                | BinOp::BitOr
+                | BinOp::BitXor
+                | BinOp::Sub
+                | BinOp::Offset
+                | BinOp::Shl
+                | BinOp::Shr,
+                Right(p),
+                Left(0),
+            )
+            | (BinOp::Mul, Left(1), Right(p))
+            | (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p,
+            // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size.
+            (BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p))
+                if ones == layout.size.truncate(u128::MAX)
+                    || (layout.ty.is_bool() && ones == 1) =>
+            {
+                p
+            }
+            // Absorbing elements.
+            (BinOp::Mul | BinOp::BitAnd, _, Left(0))
+            | (BinOp::Rem, _, Left(1))
+            | (
+                BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr,
+                Left(0),
+                _,
+            ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
+            // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`.
+            (BinOp::BitOr, _, Left(ones)) | (BinOp::BitOr, Left(ones), _)
+                if ones == layout.size.truncate(u128::MAX)
+                    || (layout.ty.is_bool() && ones == 1) =>
+            {
+                self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty)
+            }
+            // Sub/Xor with itself.
+            (BinOp::Sub | BinOp::BitXor, a, b) if a == b => {
+                self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty)
+            }
+            // Comparison:
+            // - if both operands can be computed as bits, just compare the bits;
+            // - if we proved that both operands have the same value, we can insert true/false;
+            // - otherwise, do nothing, as we do not try to prove inequality.
+            (BinOp::Eq, Left(a), Left(b)) => self.insert_bool(a == b),
+            (BinOp::Eq, a, b) if a == b => self.insert_bool(true),
+            (BinOp::Ne, Left(a), Left(b)) => self.insert_bool(a != b),
+            (BinOp::Ne, a, b) if a == b => self.insert_bool(false),
+            _ => return None,
+        };
+
+        if checked {
+            let false_val = self.insert_bool(false);
+            Some(self.insert_tuple(vec![result, false_val]))
+        } else {
+            Some(result)
+        }
+    }
+
+    fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
+        // Trivial case: we are fetching a statically known length.
+        let place_ty = place.ty(self.local_decls, self.tcx).ty;
+        if let ty::Array(_, len) = place_ty.kind() {
+            return self.insert_constant(Const::from_ty_const(*len, self.tcx));
+        }
+
+        let mut inner = self.simplify_place_value(place, location)?;
+
+        // The length information is stored in the fat pointer.
+        // Reborrowing copies length information from one pointer to the other.
+        while let Value::Address { place: borrowed, .. } = self.get(inner)
+            && let [PlaceElem::Deref] = borrowed.projection[..]
+            && let Some(borrowed) = self.locals[borrowed.local]
+        {
+            inner = borrowed;
+        }
+
+        // We have an unsizing cast, which assigns the length to fat pointer metadata.
+        if let Value::Cast { kind, from, to, .. } = self.get(inner)
+            && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind
+            && let Some(from) = from.builtin_deref(true)
+            && let ty::Array(_, len) = from.ty.kind()
+            && let Some(to) = to.builtin_deref(true)
+            && let ty::Slice(..) = to.ty.kind()
+        {
+            return self.insert_constant(Const::from_ty_const(*len, self.tcx));
+        }
+
+        // Fallback: a symbolic `Len`.
+        Some(self.insert(Value::Len(inner)))
+    }
 }
 
 fn op_to_prop_const<'tcx>(
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 070580860c1..20e70f87b75 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1433,7 +1433,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
 }
 
 fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> {
-    for impl_def_id in tcx.inherent_impls(def_id) {
+    for impl_def_id in tcx.inherent_impls(def_id).ok()? {
         if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
             tcx,
             fn_ident,
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index d515e86a182..fb19bb996f9 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -616,6 +616,8 @@ parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable
 
 parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
 
+parse_nul_in_c_str = null characters in C string literals are 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
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 34b34a1bad6..7dc711d9610 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2163,6 +2163,11 @@ pub enum UnescapeError {
         #[subdiagnostic]
         suggestion: MoreThanOneCharSugg,
     },
+    #[diag(parse_nul_in_c_str)]
+    NulInCStr {
+        #[primary_span]
+        span: Span,
+    },
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index fbc77f28780..3238f8e23bb 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -262,6 +262,9 @@ pub(crate) fn emit_unescape_error(
         EscapeError::LoneSlash => {
             dcx.emit_err(UnescapeError::LoneSlash(err_span));
         }
+        EscapeError::NulInCStr => {
+            dcx.emit_err(UnescapeError::NulInCStr { span: err_span });
+        }
         EscapeError::UnskippedWhitespaceWarning => {
             let (c, char_span) = last_char();
             dcx.emit_warn(UnescapeError::UnskippedWhitespace {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index ac2ca23ad41..9422a594488 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -128,7 +128,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         if let Some(def_id) = self.typeck_results().type_dependent_def_id(id) {
             self.check_def_id(def_id);
         } else {
-            bug!("no type-dependent def for method");
+            assert!(
+                self.typeck_results().tainted_by_errors.is_some(),
+                "no type-dependent def for method"
+            );
         }
     }
 
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index ff29fc5929c..528a52f4225 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -303,7 +303,8 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
                 Ref,
                 Lit,
                 Range,
-                Slice
+                Slice,
+                Err
             ]
         );
         hir_visit::walk_pat(self, p)
@@ -576,7 +577,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
                 Rest,
                 Never,
                 Paren,
-                MacCall
+                MacCall,
+                Err
             ]
         );
         ast_visit::walk_pat(self, p)
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index 7cc585bea3a..1d0e1cb7e6a 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 derivative = "2.2.0"
+rustc-hash = "1.1.0"
 rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index c1042d5b66e..76098505b79 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -155,13 +155,13 @@ use std::iter::once;
 use smallvec::SmallVec;
 
 use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
-use rustc_index::bit_set::{BitSet, GrowableBitSet};
-use rustc_index::IndexVec;
+use rustc_index::bit_set::GrowableBitSet;
 
 use self::Constructor::*;
 use self::MaybeInfiniteInt::*;
 use self::SliceKind::*;
 
+use crate::index;
 use crate::usefulness::PlaceCtxt;
 use crate::TypeCx;
 
@@ -804,7 +804,10 @@ pub enum ConstructorSet<Cx: TypeCx> {
     Struct { empty: bool },
     /// This type has the following list of constructors. If `variants` is empty and
     /// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
-    Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool },
+    Variants {
+        variants: index::IdxContainer<Cx::VariantIdx, VariantVisibility>,
+        non_exhaustive: bool,
+    },
     /// The type is `&T`.
     Ref,
     /// The type is a union.
@@ -904,7 +907,7 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
                 }
             }
             ConstructorSet::Variants { variants, non_exhaustive } => {
-                let mut seen_set: BitSet<_> = BitSet::new_empty(variants.len());
+                let mut seen_set = index::IdxSet::new_empty(variants.len());
                 for idx in seen.iter().map(|c| c.as_variant().unwrap()) {
                     seen_set.insert(idx);
                 }
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 0bc432fa6f0..21fa8e68d82 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -21,7 +21,45 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 use std::fmt;
 
-use rustc_index::Idx;
+#[cfg(feature = "rustc")]
+pub mod index {
+    // Faster version when the indices of variants are `0..variants.len()`.
+    pub use rustc_index::bit_set::BitSet as IdxSet;
+    pub use rustc_index::Idx;
+    pub use rustc_index::IndexVec as IdxContainer;
+}
+#[cfg(not(feature = "rustc"))]
+pub mod index {
+    // Slower version when the indices of variants are something else.
+    pub trait Idx: Copy + PartialEq + Eq + std::hash::Hash {}
+    impl<T: Copy + PartialEq + Eq + std::hash::Hash> Idx for T {}
+
+    #[derive(Debug)]
+    pub struct IdxContainer<K, V>(pub rustc_hash::FxHashMap<K, V>);
+    impl<K: Idx, V> IdxContainer<K, V> {
+        pub fn len(&self) -> usize {
+            self.0.len()
+        }
+        pub fn iter_enumerated(&self) -> impl Iterator<Item = (K, &V)> {
+            self.0.iter().map(|(k, v)| (*k, v))
+        }
+    }
+
+    #[derive(Debug)]
+    pub struct IdxSet<T>(pub rustc_hash::FxHashSet<T>);
+    impl<T: Idx> IdxSet<T> {
+        pub fn new_empty(_len: usize) -> Self {
+            Self(Default::default())
+        }
+        pub fn contains(&self, elem: T) -> bool {
+            self.0.contains(&elem)
+        }
+        pub fn insert(&mut self, elem: T) {
+            self.0.insert(elem);
+        }
+    }
+}
+
 #[cfg(feature = "rustc")]
 use rustc_middle::ty::Ty;
 #[cfg(feature = "rustc")]
@@ -48,7 +86,7 @@ pub trait TypeCx: Sized + fmt::Debug {
     /// Errors that can abort analysis.
     type Error: fmt::Debug;
     /// The index of an enum variant.
-    type VariantIdx: Clone + Idx;
+    type VariantIdx: Clone + index::Idx + fmt::Debug;
     /// A string literal
     type StrLit: Clone + PartialEq + fmt::Debug;
     /// Extra data to store in a match arm.
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 58ff4d8c793..5a95f2083f6 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1745,12 +1745,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             // Doing analysis on local `DefId`s would cause infinite recursion.
             return;
         }
+        let Ok(impls) = self.r.tcx.inherent_impls(def_id) else { return };
         // Look at all the associated functions without receivers in the type's
         // inherent impls to look for builders that return `Self`
-        let mut items = self
-            .r
-            .tcx
-            .inherent_impls(def_id)
+        let mut items = impls
             .iter()
             .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
             // Only assoc fn with no receivers.
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 53bdef6dfa0..af8c962a2ed 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -75,8 +75,6 @@ session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be u
 
 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}
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index ac15c3b407b..e751ff13a34 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3190,12 +3190,12 @@ pub enum WasiExecModel {
 /// how the hash should be calculated when adding a new command-line argument.
 pub(crate) mod dep_tracking {
     use super::{
-        BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
-        ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay,
-        LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, OptLevel,
-        OutFileName, OutputType, OutputTypes, Polonius, RemapPathScopeComponents, ResolveDocLinks,
-        SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
-        WasiExecModel,
+        BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CrateType, DebugInfo,
+        DebugInfoCompression, ErrorOutputType, FunctionReturn, InliningThreshold,
+        InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli,
+        NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius,
+        RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
+        SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
     };
     use crate::lint;
     use crate::utils::NativeLib;
@@ -3274,6 +3274,7 @@ pub(crate) mod dep_tracking {
         LtoCli,
         DebugInfo,
         DebugInfoCompression,
+        CollapseMacroDebuginfo,
         UnstableFeatures,
         NativeLib,
         SanitizerSet,
@@ -3437,6 +3438,25 @@ pub enum ProcMacroExecutionStrategy {
     CrossThread,
 }
 
+/// How to perform collapse macros debug info
+/// if-ext - if macro from different crate (related to callsite code)
+/// | cmd \ attr    | no  | (unspecified) | external | yes |
+/// | no            | no  | no            | no       | no  |
+/// | (unspecified) | no  | no            | if-ext   | yes |
+/// | external      | no  | if-ext        | if-ext   | yes |
+/// | yes           | yes | yes           | yes      | yes |
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum CollapseMacroDebuginfo {
+    /// Don't collapse debuginfo for the macro
+    No = 0,
+    /// Unspecified value
+    Unspecified = 1,
+    /// Collapse debuginfo if the macro comes from a different crate
+    External = 2,
+    /// Collapse debuginfo for the macro
+    Yes = 3,
+}
+
 /// Which format to use for `-Z dump-mono-stats`
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum DumpMonoStatsFormat {
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 21a206798af..e19f0fd84de 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
     error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan,
 };
 use rustc_macros::Diagnostic;
-use rustc_span::{BytePos, Span, Symbol};
+use rustc_span::{Span, Symbol};
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 use crate::parse::ParseSess;
@@ -346,13 +346,6 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
     pub span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(session_nul_in_c_str)]
-pub(crate) struct NulInCStr {
-    #[primary_span]
-    pub span: Span,
-}
-
 pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
     // Checks if `s` looks like i32 or u1234 etc.
     fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -432,12 +425,6 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
             };
             dcx.emit_err(IntLiteralTooLarge { span, limit });
         }
-        LitError::NulInCStr(range) => {
-            let lo = BytePos(span.lo().0 + range.start as u32 + 2);
-            let hi = BytePos(span.lo().0 + range.end as u32 + 2);
-            let span = span.with_lo(lo).with_hi(hi);
-            dcx.emit_err(NulInCStr { span });
-        }
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f4bf79f93f2..1337ade62c0 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -388,6 +388,7 @@ mod desc {
     pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
     pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
     pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
+    pub const parse_collapse_macro_debuginfo: &str = "one of `no`, `external`, or `yes`";
     pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
     pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
     pub const parse_optimization_fuel: &str = "crate=integer";
@@ -1302,6 +1303,19 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_collapse_macro_debuginfo(
+        slot: &mut CollapseMacroDebuginfo,
+        v: Option<&str>,
+    ) -> bool {
+        *slot = match v {
+            Some("no") => CollapseMacroDebuginfo::No,
+            Some("external") => CollapseMacroDebuginfo::External,
+            Some("yes") => CollapseMacroDebuginfo::Yes,
+            _ => return false,
+        };
+        true
+    }
+
     pub(crate) fn parse_proc_macro_execution_strategy(
         slot: &mut ProcMacroExecutionStrategy,
         v: Option<&str>,
@@ -1534,6 +1548,9 @@ options! {
         "instrument control-flow architecture protection"),
     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
         "the backend to use"),
+    collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified,
+        parse_collapse_macro_debuginfo, [TRACKED],
+        "set option to collapse debuginfo for macros"),
     combine_cgu: bool = (false, parse_bool, [TRACKED],
         "combine CGUs into a single one"),
     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
@@ -1724,6 +1741,8 @@ options! {
         "run all passes except codegen; no output"),
     no_generate_arange_section: bool = (false, parse_no_flag, [TRACKED],
         "omit DWARF address ranges that give faster lookups"),
+    no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED],
+        "disable the compatibility version of the `implied_bounds_ty` query"),
     no_jump_tables: bool = (false, parse_no_flag, [TRACKED],
         "disable the jump tables and lookup tables that can be generated from a switch case lowering"),
     no_leak_check: bool = (false, parse_no_flag, [UNTRACKED],
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 4bac98909ad..b99640d2f2d 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -190,35 +190,120 @@ where
     stable_mir::compiler_interface::run(&tables, || init(&tables, f))
 }
 
+/// Instantiate and run the compiler with the provided arguments and callback.
+///
+/// The callback will be invoked after the compiler ran all its analyses, but before code generation.
+/// Note that this macro accepts two different formats for the callback:
+/// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow<B, C>`
+/// ```ignore(needs-extern-crate)
+/// # extern crate rustc_driver;
+/// # extern crate rustc_interface;
+/// # #[macro_use]
+/// # extern crate rustc_smir;
+/// # extern crate stable_mir;
+/// #
+/// # fn main() {
+/// #   use std::ops::ControlFlow;
+/// #   use stable_mir::CompilerError;
+///     fn analyze_code() -> ControlFlow<(), ()> {
+///         // Your code goes in here.
+/// #       ControlFlow::Continue(())
+///     }
+/// #   let args = vec!["--verbose".to_string()];
+///     let result = run!(args, analyze_code);
+/// #   assert_eq!(result, Err(CompilerError::Skipped))
+/// # }
+/// ```
+/// 2. A closure expression:
+/// ```ignore(needs-extern-crate)
+/// # extern crate rustc_driver;
+/// # extern crate rustc_interface;
+/// # #[macro_use]
+/// # extern crate rustc_smir;
+/// # extern crate stable_mir;
+/// #
+/// # fn main() {
+/// #   use std::ops::ControlFlow;
+/// #   use stable_mir::CompilerError;
+///     fn analyze_code(extra_args: Vec<String>) -> ControlFlow<(), ()> {
+/// #       let _ = extra_args;
+///         // Your code goes in here.
+/// #       ControlFlow::Continue(())
+///     }
+/// #   let args = vec!["--verbose".to_string()];
+/// #   let extra_args = vec![];
+///     let result = run!(args, || analyze_code(extra_args));
+/// #   assert_eq!(result, Err(CompilerError::Skipped))
+/// # }
+/// ```
 #[macro_export]
 macro_rules! run {
+    ($args:expr, $callback_fn:ident) => {
+        run_driver!($args, || $callback_fn())
+    };
+    ($args:expr, $callback:expr) => {
+        run_driver!($args, $callback)
+    };
+}
+
+/// Instantiate and run the compiler with the provided arguments and callback.
+///
+/// This is similar to `run` but it invokes the callback with the compiler's `TyCtxt`,
+/// which can be used to invoke internal APIs.
+#[macro_export]
+macro_rules! run_with_tcx {
+    ($args:expr, $callback_fn:ident) => {
+        run_driver!($args, |tcx| $callback_fn(tcx), with_tcx)
+    };
     ($args:expr, $callback:expr) => {
-        run!($args, tcx, $callback)
+        run_driver!($args, $callback, with_tcx)
+    };
+}
+
+/// Optionally include an ident. This is needed due to macro hygiene.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! optional {
+    (with_tcx $ident:ident) => {
+        $ident
     };
-    ($args:expr, $tcx:ident, $callback:expr) => {{
+}
+
+/// Prefer using [run!] and [run_with_tcx] instead.
+///
+/// This macro implements the instantiation of a StableMIR driver, and it will invoke
+/// the given callback after the compiler analyses.
+///
+/// The third argument determines whether the callback requires `tcx` as an argument.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! run_driver {
+    ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{
         use rustc_driver::{Callbacks, Compilation, RunCompiler};
         use rustc_interface::{interface, Queries};
         use stable_mir::CompilerError;
         use std::ops::ControlFlow;
 
-        pub struct StableMir<B = (), C = ()>
+        pub struct StableMir<B = (), C = (), F = fn($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C>>
         where
             B: Send,
             C: Send,
+            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             args: Vec<String>,
-            callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>,
+            callback: Option<F>,
             result: Option<ControlFlow<B, C>>,
         }
 
-        impl<B, C> StableMir<B, C>
+        impl<B, C, F> StableMir<B, C, F>
         where
             B: Send,
             C: Send,
+            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             /// Creates a new `StableMir` instance, with given test_function and arguments.
-            pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>) -> Self {
-                StableMir { args, callback, result: None }
+            pub fn new(args: Vec<String>, callback: F) -> Self {
+                StableMir { args, callback: Some(callback), result: None }
             }
 
             /// Runs the compiler against given target and tests it with `test_function`
@@ -238,10 +323,11 @@ macro_rules! run {
             }
         }
 
-        impl<B, C> Callbacks for StableMir<B, C>
+        impl<B, C, F> Callbacks for StableMir<B, C, F>
         where
             B: Send,
             C: Send,
+            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             /// Called after analysis. Return value instructs the compiler whether to
             /// continue the compilation afterwards (defaults to `Compilation::Continue`)
@@ -251,20 +337,24 @@ macro_rules! run {
                 queries: &'tcx Queries<'tcx>,
             ) -> Compilation {
                 queries.global_ctxt().unwrap().enter(|tcx| {
-                    rustc_internal::run(tcx, || {
-                        self.result = Some((self.callback)(tcx));
-                    })
-                    .unwrap();
-                    if self.result.as_ref().is_some_and(|val| val.is_continue()) {
-                        Compilation::Continue
+                    if let Some(callback) = self.callback.take() {
+                        rustc_internal::run(tcx, || {
+                            self.result = Some(callback($(optional!($with_tcx tcx))?));
+                        })
+                        .unwrap();
+                        if self.result.as_ref().is_some_and(|val| val.is_continue()) {
+                            Compilation::Continue
+                        } else {
+                            Compilation::Stop
+                        }
                     } else {
-                        Compilation::Stop
+                        Compilation::Continue
                     }
                 })
             }
         }
 
-        StableMir::new($args, |$tcx| $callback).run()
+        StableMir::new($args, $callback).run()
     }};
 }
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index d03965b539c..21623fdc1d2 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -464,12 +464,15 @@ impl HygieneData {
         &self,
         mut span: Span,
         to: Span,
-        collapse_debuginfo_enabled: bool,
+        collapse_debuginfo_feature_enabled: bool,
     ) -> Span {
         let orig_span = span;
         let mut ret_span = span;
 
-        debug!("walk_chain_collapsed({:?}, {:?})", span, to);
+        debug!(
+            "walk_chain_collapsed({:?}, {:?}), feature_enable={}",
+            span, to, collapse_debuginfo_feature_enabled,
+        );
         debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
         while !span.eq_ctxt(to) && span.from_expansion() {
             let outer_expn = self.outer_expn(span.ctxt());
@@ -477,7 +480,7 @@ impl HygieneData {
             let expn_data = self.expn_data(outer_expn);
             debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
             span = expn_data.call_site;
-            if !collapse_debuginfo_enabled || expn_data.collapse_debuginfo {
+            if !collapse_debuginfo_feature_enabled || expn_data.collapse_debuginfo {
                 ret_span = span;
             }
         }
@@ -601,8 +604,14 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
     HygieneData::with(|data| data.walk_chain(span, to))
 }
 
-pub fn walk_chain_collapsed(span: Span, to: Span, collapse_debuginfo_enabled: bool) -> Span {
-    HygieneData::with(|hdata| hdata.walk_chain_collapsed(span, to, collapse_debuginfo_enabled))
+pub fn walk_chain_collapsed(
+    span: Span,
+    to: Span,
+    collapse_debuginfo_feature_enabled: bool,
+) -> Span {
+    HygieneData::with(|hdata| {
+        hdata.walk_chain_collapsed(span, to, collapse_debuginfo_feature_enabled)
+    })
 }
 
 pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 72b62a795fc..44795022cba 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -749,6 +749,7 @@ symbols! {
         extern_in_paths,
         extern_prelude,
         extern_types,
+        external,
         external_doc,
         f,
         f16c_target_feature,
@@ -1811,6 +1812,7 @@ symbols! {
         xmm_reg,
         yeet_desugar_details,
         yeet_expr,
+        yes,
         yield_expr,
         ymm_reg,
         zmm_reg,
diff --git a/compiler/rustc_target/src/spec/base/freebsd.rs b/compiler/rustc_target/src/spec/base/freebsd.rs
index 8c141aaaec3..80b3da8a752 100644
--- a/compiler/rustc_target/src/spec/base/freebsd.rs
+++ b/compiler/rustc_target/src/spec/base/freebsd.rs
@@ -6,6 +6,7 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         families: cvs!["unix"],
         has_rpath: true,
+        crt_static_respected: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         abi_return_struct_as_int: true,
diff --git a/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs
deleted file mode 100644
index e4768c67af5..00000000000
--- a/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-use crate::spec::{targets::wasm32_unknown_emscripten, LinkerFlavor, Target};
-
-pub fn target() -> Target {
-    let mut target = wasm32_unknown_emscripten::target();
-    target.add_post_link_args(LinkerFlavor::EmCc, &["-sWASM=0", "--memory-init-file", "0"]);
-    target
-}
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
index e2e707f4a1a..90df3c69684 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".into(),
         pointer_width: 64,
-        data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 073174127d6..0cd376fcbbd 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -194,7 +194,7 @@ pub fn all_fields_implement_trait<'tcx>(
                 infcx.implied_bounds_tys(
                     param_env,
                     parent_cause.body_id,
-                    FxIndexSet::from_iter([self_type]),
+                    &FxIndexSet::from_iter([self_type]),
                 ),
             );
             let errors = infcx.resolve_regions(&outlives_env);
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 5b349d576b6..52631d4353b 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -9,123 +9,153 @@ use rustc_span::def_id::LocalDefId;
 
 pub use rustc_middle::traits::query::OutlivesBound;
 
+pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
 pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
 pub trait InferCtxtExt<'a, 'tcx> {
-    fn implied_outlives_bounds(
-        &self,
+    /// Do *NOT* call this directly.
+    fn implied_bounds_tys_compat(
+        &'a self,
         param_env: ty::ParamEnv<'tcx>,
         body_id: LocalDefId,
-        ty: Ty<'tcx>,
-    ) -> Vec<OutlivesBound<'tcx>>;
+        tys: &'a FxIndexSet<Ty<'tcx>>,
+        compat: bool,
+    ) -> BoundsCompat<'a, 'tcx>;
 
+    /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat`
+    /// with `compat` set to `true`, otherwise `false`.
     fn implied_bounds_tys(
         &'a self,
         param_env: ty::ParamEnv<'tcx>,
         body_id: LocalDefId,
-        tys: FxIndexSet<Ty<'tcx>>,
+        tys: &'a FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx>;
 }
 
-impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
-    /// Implied bounds are region relationships that we deduce
-    /// automatically. The idea is that (e.g.) a caller must check that a
-    /// function's argument types are well-formed immediately before
-    /// calling that fn, and hence the *callee* can assume that its
-    /// argument types are well-formed. This may imply certain relationships
-    /// between generic parameters. For example:
-    /// ```
-    /// fn foo<T>(x: &T) {}
-    /// ```
-    /// can only be called with a `'a` and `T` such that `&'a T` is WF.
-    /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
-    ///
-    /// # Parameters
-    ///
-    /// - `param_env`, the where-clauses in scope
-    /// - `body_id`, the body-id to use when normalizing assoc types.
-    ///   Note that this may cause outlives obligations to be injected
-    ///   into the inference context with this body-id.
-    /// - `ty`, the type that we are supposed to assume is WF.
-    #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
-    fn implied_outlives_bounds(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: LocalDefId,
-        ty: Ty<'tcx>,
-    ) -> Vec<OutlivesBound<'tcx>> {
-        let ty = self.resolve_vars_if_possible(ty);
-        let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
+/// Implied bounds are region relationships that we deduce
+/// automatically. The idea is that (e.g.) a caller must check that a
+/// function's argument types are well-formed immediately before
+/// calling that fn, and hence the *callee* can assume that its
+/// argument types are well-formed. This may imply certain relationships
+/// between generic parameters. For example:
+/// ```
+/// fn foo<T>(x: &T) {}
+/// ```
+/// can only be called with a `'a` and `T` such that `&'a T` is WF.
+/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
+///
+/// # Parameters
+///
+/// - `param_env`, the where-clauses in scope
+/// - `body_id`, the body-id to use when normalizing assoc types.
+///   Note that this may cause outlives obligations to be injected
+///   into the inference context with this body-id.
+/// - `ty`, the type that we are supposed to assume is WF.
+#[instrument(level = "debug", skip(infcx, param_env, body_id), ret)]
+fn implied_outlives_bounds<'a, 'tcx>(
+    infcx: &'a InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: LocalDefId,
+    ty: Ty<'tcx>,
+    compat: bool,
+) -> Vec<OutlivesBound<'tcx>> {
+    let ty = infcx.resolve_vars_if_possible(ty);
+    let ty = OpportunisticRegionResolver::new(infcx).fold_ty(ty);
 
-        // We do not expect existential variables in implied bounds.
-        // We may however encounter unconstrained lifetime variables
-        // in very rare cases.
-        //
-        // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
-        // an example.
-        assert!(!ty.has_non_region_infer());
+    // We do not expect existential variables in implied bounds.
+    // We may however encounter unconstrained lifetime variables
+    // in very rare cases.
+    //
+    // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
+    // an example.
+    assert!(!ty.has_non_region_infer());
 
-        let mut canonical_var_values = OriginalQueryValues::default();
-        let canonical_ty = self.canonicalize_query(param_env.and(ty), &mut canonical_var_values);
-        let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else {
-            return vec![];
-        };
+    let mut canonical_var_values = OriginalQueryValues::default();
+    let canonical_ty = infcx.canonicalize_query(param_env.and(ty), &mut canonical_var_values);
+    let implied_bounds_result = if compat {
+        infcx.tcx.implied_outlives_bounds_compat(canonical_ty)
+    } else {
+        infcx.tcx.implied_outlives_bounds(canonical_ty)
+    };
+    let Ok(canonical_result) = implied_bounds_result else {
+        return vec![];
+    };
 
-        let mut constraints = QueryRegionConstraints::default();
-        let Ok(InferOk { value: mut bounds, 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, &[]);
+    let mut constraints = QueryRegionConstraints::default();
+    let Ok(InferOk { value: mut bounds, obligations }) = infcx
+        .instantiate_nll_query_response_and_region_obligations(
+            &ObligationCause::dummy(),
+            param_env,
+            &canonical_var_values,
+            canonical_result,
+            &mut constraints,
+        )
+    else {
+        return vec![];
+    };
+    assert_eq!(&obligations, &[]);
 
-        // Because of #109628, we may have unexpected placeholders. Ignore them!
-        // FIXME(#109628): panic in this case once the issue is fixed.
-        bounds.retain(|bound| !bound.has_placeholders());
+    // Because of #109628, we may have unexpected placeholders. Ignore them!
+    // FIXME(#109628): panic in this case once the issue is fixed.
+    bounds.retain(|bound| !bound.has_placeholders());
 
-        if !constraints.is_empty() {
-            let span = self.tcx.def_span(body_id);
+    if !constraints.is_empty() {
+        let span = infcx.tcx.def_span(body_id);
 
-            debug!(?constraints);
-            if !constraints.member_constraints.is_empty() {
-                span_bug!(span, "{:#?}", constraints.member_constraints);
-            }
+        debug!(?constraints);
+        if !constraints.member_constraints.is_empty() {
+            span_bug!(span, "{:#?}", constraints.member_constraints);
+        }
 
-            // Instantiation may have produced new inference variables and constraints on those
-            // variables. Process these constraints.
-            let ocx = ObligationCtxt::new(self);
-            let cause = ObligationCause::misc(span, body_id);
-            for &constraint in &constraints.outlives {
-                ocx.register_obligation(self.query_outlives_constraint_to_obligation(
-                    constraint,
-                    cause.clone(),
-                    param_env,
-                ));
-            }
+        // Instantiation may have produced new inference variables and constraints on those
+        // variables. Process these constraints.
+        let ocx = ObligationCtxt::new(infcx);
+        let cause = ObligationCause::misc(span, body_id);
+        for &constraint in &constraints.outlives {
+            ocx.register_obligation(infcx.query_outlives_constraint_to_obligation(
+                constraint,
+                cause.clone(),
+                param_env,
+            ));
+        }
 
-            let errors = ocx.select_all_or_error();
-            if !errors.is_empty() {
-                self.dcx().span_delayed_bug(
-                    span,
-                    "implied_outlives_bounds failed to solve obligations from instantiation",
-                );
-            }
-        };
+        let errors = ocx.select_all_or_error();
+        if !errors.is_empty() {
+            infcx.dcx().span_delayed_bug(
+                span,
+                "implied_outlives_bounds failed to solve obligations from instantiation",
+            );
+        }
+    };
 
-        bounds
+    bounds
+}
+
+impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
+    fn implied_bounds_tys_compat(
+        &'a self,
+        param_env: ParamEnv<'tcx>,
+        body_id: LocalDefId,
+        tys: &'a FxIndexSet<Ty<'tcx>>,
+        compat: bool,
+    ) -> BoundsCompat<'a, 'tcx> {
+        tys.iter()
+            .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, compat))
     }
 
     fn implied_bounds_tys(
         &'a self,
         param_env: ParamEnv<'tcx>,
         body_id: LocalDefId,
-        tys: FxIndexSet<Ty<'tcx>>,
+        tys: &'a FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx> {
-        tys.into_iter().flat_map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
+        tys.iter().flat_map(move |ty| {
+            implied_outlives_bounds(
+                self,
+                param_env,
+                body_id,
+                *ty,
+                !self.tcx.sess.opts.unstable_opts.no_implied_bounds_compat,
+            )
+        })
     }
 }
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 ba6ed298774..2fdb63d7dee 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
@@ -5,10 +5,11 @@ use crate::traits::ObligationCtxt;
 
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
+use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::infer::canonical::CanonicalQueryResponse;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::DUMMY_SP;
 use smallvec::{smallvec, SmallVec};
@@ -63,6 +64,85 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
+    let normalize_op = |ty| {
+        let ty = ocx.normalize(&ObligationCause::dummy(), param_env, ty);
+        if !ocx.select_all_or_error().is_empty() {
+            return Err(NoSolution);
+        }
+        let ty = ocx.infcx.resolve_vars_if_possible(ty);
+        let ty = OpportunisticRegionResolver::new(&ocx.infcx).fold_ty(ty);
+        Ok(ty)
+    };
+
+    // 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(), normalize_op(ty)?.into()];
+
+    let mut outlives_bounds: Vec<OutlivesBound<'tcx>> = vec![];
+
+    while let Some(arg) = wf_args.pop() {
+        if !checked_wf_args.insert(arg) {
+            continue;
+        }
+
+        // From the full set of obligations, just filter down to the region relationships.
+        for obligation in
+            wf::unnormalized_obligations(ocx.infcx, param_env, arg).into_iter().flatten()
+        {
+            assert!(!obligation.has_escaping_bound_vars());
+            let Some(pred) = obligation.predicate.kind().no_bound_vars() else {
+                continue;
+            };
+            match pred {
+                // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
+                // if we ever support that
+                ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
+                | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Ambiguous
+                | ty::PredicateKind::NormalizesTo(..)
+                | ty::PredicateKind::AliasRelate(..) => {}
+
+                // We need to search through *all* WellFormed predicates
+                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                    wf_args.push(arg);
+                }
+
+                // We need to register region relationships
+                ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
+                    ty::OutlivesPredicate(r_a, r_b),
+                )) => outlives_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a)),
+
+                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
+                    ty_a,
+                    r_b,
+                ))) => {
+                    let ty_a = normalize_op(ty_a)?;
+                    let mut components = smallvec![];
+                    push_outlives_components(ocx.infcx.tcx, ty_a, &mut components);
+                    outlives_bounds.extend(implied_bounds_from_components(r_b, components))
+                }
+            }
+        }
+    }
+
+    Ok(outlives_bounds)
+}
+
+pub fn compute_implied_outlives_bounds_compat_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
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 959838ab348..24e91c263e3 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -8,13 +8,29 @@ use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner;
+use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{
+    compute_implied_outlives_bounds_compat_inner, 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_compat, ..*p };
     *p = Providers { implied_outlives_bounds, ..*p };
 }
 
+fn implied_outlives_bounds_compat<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    goal: CanonicalTyGoal<'tcx>,
+) -> Result<
+    &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
+    NoSolution,
+> {
+    tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
+        let (param_env, ty) = key.into_parts();
+        compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty)
+    })
+}
+
 fn implied_outlives_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     goal: CanonicalTyGoal<'tcx>,
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
index 0a2280545da..ec5f32539f2 100644
--- a/library/alloc/src/vec/in_place_collect.rs
+++ b/library/alloc/src/vec/in_place_collect.rs
@@ -9,7 +9,7 @@
 //! or [`BinaryHeap<T>`], the adapters guarantee to consume enough items per step to make room
 //! for the results (represented by [`InPlaceIterable`]), provide transitive access to `source`
 //! (via [`SourceIter`]) and thus the underlying allocation.
-//! And finally there are alignment and size constriants to consider, this is currently ensured via
+//! And finally there are alignment and size constraints to consider, this is currently ensured via
 //! const eval instead of trait bounds in the specialized [`SpecFromIter`] implementation.
 //!
 //! [`BinaryHeap<T>`]: crate::collections::BinaryHeap
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index eeee98f754e..f5988a4df13 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -121,10 +121,16 @@ extern "C" {}
 #[link(name = "unwind", kind = "static", modifiers = "-bundle")]
 extern "C" {}
 
-#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
+#[cfg(target_os = "netbsd")]
 #[link(name = "gcc_s")]
 extern "C" {}
 
+#[cfg(target_os = "freebsd")]
+#[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+#[link(name = "gcc_eh", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
+extern "C" {}
+
 #[cfg(all(target_os = "openbsd", target_arch = "sparc64"))]
 #[link(name = "gcc")]
 extern "C" {}
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index fea194a80ef..6f3be1f6e93 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -917,6 +917,19 @@ class RustBuild(object):
             if toml_val is not None:
                 env["{}_{}".format(var_name, host_triple_sanitized)] = toml_val
 
+        # In src/etc/rust_analyzer_settings.json, we configure rust-analyzer to
+        # pass RUSTC_BOOTSTRAP=1 to all cargo invocations because the standard
+        # library uses unstable Cargo features. Without RUSTC_BOOTSTRAP,
+        # rust-analyzer would fail to fetch workspace layout when the system's
+        # default toolchain is not nightly.
+        #
+        # But that setting has the collateral effect of rust-analyzer also
+        # passing RUSTC_BOOTSTRAP=1 to all x.py invocations too (the various
+        # overrideCommand). For compiling bootstrap, that is unwanted and can
+        # cause spurious rebuilding of bootstrap when rust-analyzer x.py
+        # invocations are interleaved with handwritten ones on the command line.
+        env.pop("RUSTC_BOOTSTRAP", None)
+
         # preserve existing RUSTFLAGS
         env.setdefault("RUSTFLAGS", "")
 
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 4e20babc55a..3770d0687b2 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1799,15 +1799,20 @@ impl<'a> Builder<'a> {
         }
 
         if self.config.rust_remap_debuginfo {
-            // FIXME: handle vendored sources
-            let registry_src = t!(home::cargo_home()).join("registry").join("src");
             let mut env_var = OsString::new();
-            for entry in t!(std::fs::read_dir(registry_src)) {
-                if !env_var.is_empty() {
-                    env_var.push("\t");
-                }
-                env_var.push(t!(entry).path());
+            if self.config.vendor {
+                let vendor = self.build.src.join("vendor");
+                env_var.push(vendor);
                 env_var.push("=/rust/deps");
+            } else {
+                let registry_src = t!(home::cargo_home()).join("registry").join("src");
+                for entry in t!(std::fs::read_dir(registry_src)) {
+                    if !env_var.is_empty() {
+                        env_var.push("\t");
+                    }
+                    env_var.push(t!(entry).path());
+                    env_var.push("=/rust/deps");
+                }
             }
             cargo.env("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP", env_var);
         }
diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md
index 95932db14e1..48b58f6f06a 100644
--- a/src/doc/rustc/src/target-tier-policy.md
+++ b/src/doc/rustc/src/target-tier-policy.md
@@ -246,6 +246,8 @@ approved by the appropriate team for that shared code before acceptance.
     introducing unconditional uses of features that another variation of the
     target may not have; use conditional compilation or runtime detection, as
     appropriate, to let each target run code supported by that target.
+- Tier 3 targets must be able to produce assembly using at least one of
+  rustc's supported backends from any host target.
 
 If a tier 3 target stops meeting these requirements, or the target maintainers
 no longer have interest or time, or the target shows no signs of activity and
diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
index 78bc8dceb78..bf83f6ad7c5 100644
--- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
@@ -44,15 +44,20 @@ To enable checking of values, but to provide an *none*/empty set of expected val
 
 ```bash
 rustc --check-cfg 'cfg(name)'
-rustc --check-cfg 'cfg(name, values())'
 rustc --check-cfg 'cfg(name, values(none()))'
 ```
 
-To enable checking of name but not values (i.e. unknown expected values), use this form:
+To enable checking of name but not values, use one of these forms:
 
-```bash
-rustc --check-cfg 'cfg(name, values(any()))'
-```
+  - No expected values (_will lint on every value_):
+    ```bash
+    rustc --check-cfg 'cfg(name, values())'
+    ```
+
+  - Unknown expected values (_will never lint_):
+    ```bash
+    rustc --check-cfg 'cfg(name, values(any()))'
+    ```
 
 To avoid repeating the same set of values, use this form:
 
@@ -114,18 +119,14 @@ as argument to `--check-cfg`.
 This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument.
 
 | `--cfg`                       | `--check-cfg`                                              |
-|-----------------------------|----------------------------------------------------------|
+|-------------------------------|------------------------------------------------------------|
 | *nothing*                     | *nothing* or `--check-cfg=cfg()` (to enable the checking)  |
-| `--cfg foo`                   | `--check-cfg=cfg(foo), --check-cfg=cfg(foo, values())` or `--check-cfg=cfg(foo, values(none()))`   |
+| `--cfg foo`                   | `--check-cfg=cfg(foo)` or `--check-cfg=cfg(foo, values(none()))` |
 | `--cfg foo=""`                | `--check-cfg=cfg(foo, values(""))`                         |
 | `--cfg foo="bar"`             | `--check-cfg=cfg(foo, values("bar"))`                      |
 | `--cfg foo="1" --cfg foo="2"` | `--check-cfg=cfg(foo, values("1", "2"))`                   |
 | `--cfg foo="1" --cfg bar="2"` | `--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))` |
-| `--cfg foo --cfg foo="bar"`   | `--check-cfg=cfg(foo) --check-cfg=cfg(foo, values("bar"))` |
-
-NOTE: There is (currently) no way to express that a condition name is expected but no (!= none)
-values are expected. Passing an empty `values()` means *(none)* in the sense of `#[cfg(foo)]`
-with no value. Users are expected to NOT pass a `--check-cfg` with that condition name.
+| `--cfg foo --cfg foo="bar"`   | `--check-cfg=cfg(foo, values(none(), "bar"))`              |
 
 ### Example: Cargo-like `feature` example
 
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 014bcb1a881..aab974ad79e 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -312,7 +312,7 @@ pub(crate) fn build_impls(
     let tcx = cx.tcx;
 
     // for each implementation of an item represented by `did`, build the clean::Item for that impl
-    for &did in tcx.inherent_impls(did).iter() {
+    for &did in tcx.inherent_impls(did).into_iter().flatten() {
         build_impl(cx, did, attrs, ret);
     }
 
@@ -325,7 +325,7 @@ pub(crate) fn build_impls(
     if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
         let type_ =
             if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) };
-        for &did in tcx.incoherent_impls(type_) {
+        for &did in tcx.incoherent_impls(type_).into_iter().flatten() {
             build_impl(cx, did, attrs, ret);
         }
     }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 90eb783c7ca..6710193f961 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1862,7 +1862,7 @@ impl PrimitiveType {
             .get(self)
             .into_iter()
             .flatten()
-            .flat_map(move |&simp| tcx.incoherent_impls(simp))
+            .flat_map(move |&simp| tcx.incoherent_impls(simp).into_iter().flatten())
             .copied()
     }
 
@@ -1870,7 +1870,7 @@ impl PrimitiveType {
         Self::simplified_types()
             .values()
             .flatten()
-            .flat_map(move |&simp| tcx.incoherent_impls(simp))
+            .flat_map(move |&simp| tcx.incoherent_impls(simp).into_iter().flatten())
             .copied()
     }
 
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 437517598ac..b2b20c95a7e 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -312,7 +312,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
 
     Symbol::intern(&match p.kind {
         // FIXME(never_patterns): does this make sense?
-        PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore,
+        PatKind::Wild | PatKind::Err(_) | PatKind::Never | PatKind::Struct(..) => {
+            return kw::Underscore;
+        }
         PatKind::Binding(_, _, ident, _) => return ident.name,
         PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
         PatKind::Or(pats) => {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index dbff33dc1ec..30b3e5c784d 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -624,7 +624,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 // Checks if item_name belongs to `impl SomeItem`
                 let mut assoc_items: Vec<_> = tcx
                     .inherent_impls(did)
-                    .iter()
+                    .into_iter()
+                    .flatten()
                     .flat_map(|&imp| {
                         filter_assoc_items_by_name_and_namespace(
                             tcx,
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 1cff2ee6b92e0ad3f87c44b70b28f788b2528b3
+Subproject 1ae631085f01c1a72d05df1ec81f3759a836004
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index bb08ac7508b..eeaa3de3725 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -45,50 +45,72 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
 
 impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        // For functions, with explicitly defined types, don't warn.
-        // XXXkhuey maybe we should?
-        if let ExprKind::Closure(Closure {
-            kind:
-                ClosureKind::Coroutine(CoroutineKind::Desugared(
-                    CoroutineDesugaring::Async,
-                    CoroutineSource::Block | CoroutineSource::Closure,
-                )),
+        let ExprKind::Closure(Closure {
+            kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, kind)),
             body: body_id,
             ..
         }) = expr.kind
-        {
-            if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
-                let typeck_results = cx.tcx.typeck_body(*body_id);
-                let body = cx.tcx.hir().body(*body_id);
-                let expr_ty = typeck_results.expr_ty(body.value);
+        else {
+            return;
+        };
 
-                if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
-                    let return_expr_span = match &body.value.kind {
-                        // XXXkhuey there has to be a better way.
-                        ExprKind::Block(block, _) => block.expr.map(|e| e.span),
-                        ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
-                        _ => None,
-                    };
-                    if let Some(return_expr_span) = return_expr_span {
-                        span_lint_hir_and_then(
-                            cx,
-                            ASYNC_YIELDS_ASYNC,
-                            body.value.hir_id,
+        let body_expr = match kind {
+            CoroutineSource::Fn => {
+                // For functions, with explicitly defined types, don't warn.
+                // XXXkhuey maybe we should?
+                return;
+            },
+            CoroutineSource::Block => cx.tcx.hir().body(*body_id).value,
+            CoroutineSource::Closure => {
+                // Like `async fn`, async closures are wrapped in an additional block
+                // to move all of the closure's arguments into the future.
+
+                let async_closure_body = cx.tcx.hir().body(*body_id).value;
+                let ExprKind::Block(block, _) = async_closure_body.kind else {
+                    return;
+                };
+                let Some(block_expr) = block.expr else {
+                    return;
+                };
+                let ExprKind::DropTemps(body_expr) = block_expr.kind else {
+                    return;
+                };
+                body_expr
+            },
+        };
+
+        let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() else {
+            return;
+        };
+
+        let typeck_results = cx.tcx.typeck_body(*body_id);
+        let expr_ty = typeck_results.expr_ty(body_expr);
+
+        if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
+            let return_expr_span = match &body_expr.kind {
+                // XXXkhuey there has to be a better way.
+                ExprKind::Block(block, _) => block.expr.map(|e| e.span),
+                ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
+                _ => None,
+            };
+            if let Some(return_expr_span) = return_expr_span {
+                span_lint_hir_and_then(
+                    cx,
+                    ASYNC_YIELDS_ASYNC,
+                    body_expr.hir_id,
+                    return_expr_span,
+                    "an async construct yields a type which is itself awaitable",
+                    |db| {
+                        db.span_label(body_expr.span, "outer async construct");
+                        db.span_label(return_expr_span, "awaitable value not awaited");
+                        db.span_suggestion(
                             return_expr_span,
-                            "an async construct yields a type which is itself awaitable",
-                            |db| {
-                                db.span_label(body.value.span, "outer async construct");
-                                db.span_label(return_expr_span, "awaitable value not awaited");
-                                db.span_suggestion(
-                                    return_expr_span,
-                                    "consider awaiting this value",
-                                    format!("{}.await", snippet(cx, return_expr_span, "..")),
-                                    Applicability::MaybeIncorrect,
-                                );
-                            },
+                            "consider awaiting this value",
+                            format!("{}.await", snippet(cx, return_expr_span, "..")),
+                            Applicability::MaybeIncorrect,
                         );
-                    }
-                }
+                    },
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index d8abe411030..d1fe9f5cbec 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -386,7 +386,8 @@ fn check_unsafe_derive_deserialize<'tcx>(
         && cx
             .tcx
             .inherent_impls(def.did())
-            .iter()
+            .into_iter()
+            .flatten()
             .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
             .any(|imp| has_unsafe(cx, imp))
     {
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 3c435294252..4e728d61b85 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -51,7 +51,8 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         | PatKind::Binding(..)
         | PatKind::Wild
         | PatKind::Never
-        | PatKind::Or(_) => false,
+        | PatKind::Or(_)
+        | PatKind::Err(_) => false,
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
         PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
         PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index e4781752e75..fb7b82ec304 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -53,9 +53,10 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
         // List of spans to lint. (lint_span, first_span)
         let mut lint_spans = Vec::new();
 
+        let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { return };
         let inherent_impls = cx
             .tcx
-            .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true));
+            .with_stable_hashing_context(|hcx| impls.inherent_impls.to_sorted(&hcx, true));
 
         for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| {
             impls.len() > 1
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 903d3a2ab89..82a37bb4f27 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -139,7 +139,7 @@ fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iter
 
 fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
     if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
-        cx.tcx.inherent_impls(ty_did).iter().any(|&did| {
+        cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| {
             cx.tcx
                 .associated_items(did)
                 .filter_by_name_unhygienic(method_name)
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index c09d3d1862b..c1ab020117c 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -441,7 +441,8 @@ fn check_for_is_empty(
     let is_empty = cx
         .tcx
         .inherent_impls(impl_ty)
-        .iter()
+        .into_iter()
+        .flatten()
         .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
         .find(|item| item.kind == AssocKind::Fn);
 
@@ -605,7 +606,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Checks the inherent impl's items for an `is_empty(self)` method.
     fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
         let is_empty = sym!(is_empty);
-        cx.tcx.inherent_impls(id).iter().any(|imp| {
+        cx.tcx.inherent_impls(id).into_iter().flatten().any(|imp| {
             cx.tcx
                 .associated_items(*imp)
                 .filter_by_name_unhygienic(is_empty)
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index c823d07e2bd..5ca161e9309 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -11,7 +11,7 @@ use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, P
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::Symbol;
+use rustc_span::{ErrorGuaranteed, Symbol};
 
 use super::MATCH_SAME_ARMS;
 
@@ -167,6 +167,8 @@ enum NormalizedPat<'a> {
     /// contains everything afterwards. Note that either side, or both sides, may contain zero
     /// patterns.
     Slice(&'a [Self], Option<&'a [Self]>),
+    /// A placeholder for a pattern that wasn't well formed in some way.
+    Err(ErrorGuaranteed),
 }
 
 #[derive(Clone, Copy)]
@@ -329,6 +331,7 @@ impl<'a> NormalizedPat<'a> {
                 arena.alloc_from_iter(front.iter().map(|pat| Self::from_pat(cx, arena, pat))),
                 wild_pat.map(|_| &*arena.alloc_from_iter(back.iter().map(|pat| Self::from_pat(cx, arena, pat)))),
             ),
+            PatKind::Err(guar) => Self::Err(guar),
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index e38c66f6741..0602eeaa704 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -73,7 +73,8 @@ pub(super) fn check<'tcx>(
         let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| {
             cx.tcx
                 .inherent_impls(adt_def.did())
-                .iter()
+                .into_iter()
+                .flatten()
                 .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
                 .any(|assoc| {
                     assoc.fn_has_self_parameter
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index cde08dfcc74..334e6770ae4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -5,7 +5,9 @@ use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
-use rustc_hir::{intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Node};
+use rustc_hir::{
+    intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
@@ -166,10 +168,22 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
                         if coroutine_kind.is_async()
                             && let hir::ExprKind::Closure(closure) = body.kind
                         {
-                            let async_closure_body = cx.tcx.hir().body(closure.body);
+                            // Like `async fn`, async closures are wrapped in an additional block
+                            // to move all of the closure's arguments into the future.
+
+                            let async_closure_body = cx.tcx.hir().body(closure.body).value;
+                            let ExprKind::Block(block, _) = async_closure_body.kind else {
+                                return;
+                            };
+                            let Some(block_expr) = block.expr else {
+                                return;
+                            };
+                            let ExprKind::DropTemps(body_expr) = block_expr.kind else {
+                                return;
+                            };
 
                             // `async x` is a syntax error, so it becomes `async { x }`
-                            if !matches!(async_closure_body.value.kind, hir::ExprKind::Block(_, _)) {
+                            if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) {
                                 hint = hint.blockify();
                             }
 
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 77adcdd0e6b..7246214f9bf 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
         // Therefore they are not some form of constructor `C`,
         // with which a pattern `C(p_0)` may be formed,
         // which we would want to join with other `C(p_j)`s.
-        Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_)
+        Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
         // Skip immutable refs, as grouping them saves few characters,
         // and almost always requires adding parens (increasing noisiness).
         // In the case of only two patterns, replacement adds net characters.
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 8d38b87e1d7..b26ebe5cee3 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -710,6 +710,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.slice(start, |pat| self.pat(pat));
                 self.slice(end, |pat| self.pat(pat));
             },
+            PatKind::Err(_) => kind!("Err"),
         }
     }
 
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 482eaed77d1..979b117db25 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1007,7 +1007,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
                 e.hash(&mut self.s);
             },
-            PatKind::Never | PatKind::Wild => {},
+            PatKind::Never | PatKind::Wild | PatKind::Err(_) => {},
         }
     }
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index cdf8528f48a..d264e46f133 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -534,10 +534,11 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<It
         "u128" => SimplifiedType::Uint(UintTy::U128),
         "f32" => SimplifiedType::Float(FloatTy::F32),
         "f64" => SimplifiedType::Float(FloatTy::F64),
-        _ => return [].iter().copied(),
+        #[allow(trivial_casts)]
+        _ => return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]).into_iter().flatten().copied(),
     };
 
-    tcx.incoherent_impls(ty).iter().copied()
+    tcx.incoherent_impls(ty).into_iter().flatten().copied()
 }
 
 fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
@@ -663,7 +664,8 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res> {
                 // `impl S { ... }`
                 let inherent_impl_children = tcx
                     .inherent_impls(def_id)
-                    .iter()
+                    .into_iter()
+                    .flatten()
                     .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
 
                 let direct_children = item_children_by_name(tcx, def_id, segment);
@@ -1733,6 +1735,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
                 },
             }
         },
+        PatKind::Err(_) => true,
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index 62de661f8ff..8c4d71e68f8 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -48,7 +48,11 @@ if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_
     && expr2 = &cx.tcx.hir().body(body_id1).value
     && let ExprKind::Block(block, None) = expr2.kind
     && block.stmts.is_empty()
-    && block.expr.is_none()
+    && let Some(trailing_expr) = block.expr
+    && let ExprKind::DropTemps(expr3) = trailing_expr.kind
+    && let ExprKind::Block(block1, None) = expr3.kind
+    && block1.stmts.is_empty()
+    && block1.expr.is_none()
 {
     // report your lint here
 }
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index f47ec49df1d..aa25f82ae1d 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -369,6 +369,7 @@ fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str {
             "non-ASCII character in byte string literal"
         }
         EscapeError::NonAsciiCharInByte => "non-ASCII character in raw byte string literal",
+        EscapeError::NulInCStr => "null character in C string literal",
         EscapeError::UnskippedWhitespaceWarning => "",
         EscapeError::MultipleSkippedLinesWarning => "",
     }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
index 6c6916c585f..69dffbf79f1 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs
@@ -106,6 +106,9 @@ fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str,
         EE::NonAsciiCharInByte  => {
             "Byte literals must not contain non-ASCII characters"
         }
+        EE::NulInCStr  => {
+            "C strings literals must not contain null characters"
+        }
         EE::UnskippedWhitespaceWarning => "Whitespace after this escape is not skipped",
         EE::MultipleSkippedLinesWarning => "Multiple lines are skipped by this escape",
 
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 0fa6edaa5d7..7f576279432 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -40,9 +40,11 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
 
 fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
     match pat.kind {
-        ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => {
-            true
-        }
+        ast::PatKind::Rest
+        | ast::PatKind::Never
+        | ast::PatKind::Wild
+        | ast::PatKind::Err(_)
+        | ast::PatKind::Lit(_) => true,
         ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
         ast::PatKind::Struct(..)
         | ast::PatKind::MacCall(..)
@@ -274,6 +276,7 @@ impl Rewrite for Pat {
             PatKind::Paren(ref pat) => pat
                 .rewrite(context, shape.offset_left(1)?.sub_width(1)?)
                 .map(|inner_pat| format!("({})", inner_pat)),
+            PatKind::Err(_) => None,
         }
     }
 }
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index eb0a2fda290..95149987033 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -70,6 +70,7 @@ pub mod pal;
 pub mod rustdoc_css_themes;
 pub mod rustdoc_gui_tests;
 pub mod style;
+pub mod target_policy;
 pub mod target_specific_tests;
 pub mod tests_placement;
 pub mod ui_tests;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 9f92b8995b7..a9340c40f44 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -109,6 +109,7 @@ fn main() {
         // Checks that only make sense for the compiler.
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
         check!(fluent_alphabetical, &compiler_path, bless);
+        check!(target_policy, &root_path);
 
         // Checks that only make sense for the std libs.
         check!(pal, &library_path);
diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs
new file mode 100644
index 00000000000..ca6590d1502
--- /dev/null
+++ b/src/tools/tidy/src/target_policy.rs
@@ -0,0 +1,52 @@
+//! Tests for target tier policy compliance.
+//!
+//! As of writing, only checks that sanity-check assembly test for targets doesn't miss any targets.
+
+use crate::walk::{filter_not_rust, walk};
+use std::{collections::HashSet, path::Path};
+
+const TARGET_DEFINITIONS_PATH: &str = "compiler/rustc_target/src/spec/targets/";
+const ASSEMBLY_TEST_PATH: &str = "tests/assembly/targets/";
+const REVISION_LINE_START: &str = "// revisions: ";
+const EXCEPTIONS: &[&str] = &[
+    // FIXME: disabled since it fails on CI saying the csky component is missing
+    "csky_unknown_linux_gnuabiv2",
+    "csky_unknown_linux_gnuabiv2hf",
+];
+
+pub fn check(root_path: &Path, bad: &mut bool) {
+    let mut targets_to_find = HashSet::new();
+
+    let definitions_path = root_path.join(TARGET_DEFINITIONS_PATH);
+    for defn in ignore::WalkBuilder::new(&definitions_path)
+        .max_depth(Some(1))
+        .filter_entry(|e| !filter_not_rust(e.path()))
+        .build()
+    {
+        let defn = defn.unwrap();
+        // Skip directory itself.
+        if defn.path() == definitions_path {
+            continue;
+        }
+
+        let path = defn.path();
+        let target_name = path.file_stem().unwrap().to_string_lossy().into_owned();
+        let _ = targets_to_find.insert(target_name);
+    }
+
+    walk(&root_path.join(ASSEMBLY_TEST_PATH), |_, _| false, &mut |_, contents| {
+        for line in contents.lines() {
+            let Some(_) = line.find(REVISION_LINE_START) else {
+                continue;
+            };
+            let (_, target_name) = line.split_at(REVISION_LINE_START.len());
+            targets_to_find.remove(target_name);
+        }
+    });
+
+    for target in targets_to_find {
+        if !EXCEPTIONS.contains(&target.as_str()) {
+            tidy_error!(bad, "{ASSEMBLY_TEST_PATH}: missing assembly test for {target}")
+        }
+    }
+}
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
new file mode 100644
index 00000000000..72a35f38eca
--- /dev/null
+++ b/tests/assembly/targets/targets-elf.rs
@@ -0,0 +1,633 @@
+// assembly-output: emit-asm
+// ignore-tidy-linelength
+// revisions: aarch64_apple_darwin
+// [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin
+// [aarch64_apple_darwin] needs-llvm-components: aarch64
+// revisions: aarch64_apple_ios
+// [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios
+// [aarch64_apple_ios] needs-llvm-components: aarch64
+// revisions: aarch64_apple_ios_macabi
+// [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi
+// [aarch64_apple_ios_macabi] needs-llvm-components: aarch64
+// revisions: aarch64_apple_ios_sim
+// [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim
+// [aarch64_apple_ios_sim] needs-llvm-components: aarch64
+// revisions: aarch64_apple_tvos
+// [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos
+// [aarch64_apple_tvos] needs-llvm-components: aarch64
+// revisions: aarch64_apple_tvos_sim
+// [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim
+// [aarch64_apple_tvos_sim] needs-llvm-components: aarch64
+// revisions: aarch64_apple_watchos
+// [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos
+// [aarch64_apple_watchos] needs-llvm-components: aarch64
+// revisions: aarch64_apple_watchos_sim
+// [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim
+// [aarch64_apple_watchos_sim] needs-llvm-components: aarch64
+// revisions: aarch64_be_unknown_linux_gnu
+// [aarch64_be_unknown_linux_gnu] compile-flags: --target aarch64_be-unknown-linux-gnu
+// [aarch64_be_unknown_linux_gnu] needs-llvm-components: aarch64
+// revisions: aarch64_be_unknown_linux_gnu_ilp32
+// [aarch64_be_unknown_linux_gnu_ilp32] compile-flags: --target aarch64_be-unknown-linux-gnu_ilp32
+// [aarch64_be_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64
+// revisions: aarch64_be_unknown_netbsd
+// [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd
+// [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64
+// revisions: aarch64_fuchsia
+// [aarch64_fuchsia] compile-flags: --target aarch64-fuchsia
+// [aarch64_fuchsia] needs-llvm-components: aarch64
+// revisions: aarch64_kmc_solid_asp3
+// [aarch64_kmc_solid_asp3] compile-flags: --target aarch64-kmc-solid_asp3
+// [aarch64_kmc_solid_asp3] needs-llvm-components: aarch64
+// revisions: aarch64_linux_android
+// [aarch64_linux_android] compile-flags: --target aarch64-linux-android
+// [aarch64_linux_android] needs-llvm-components: aarch64
+// revisions: aarch64_nintendo_switch_freestanding
+// [aarch64_nintendo_switch_freestanding] compile-flags: --target aarch64-nintendo-switch-freestanding
+// [aarch64_nintendo_switch_freestanding] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_freebsd
+// [aarch64_unknown_freebsd] compile-flags: --target aarch64-unknown-freebsd
+// [aarch64_unknown_freebsd] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_fuchsia
+// [aarch64_unknown_fuchsia] compile-flags: --target aarch64-unknown-fuchsia
+// [aarch64_unknown_fuchsia] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_hermit
+// [aarch64_unknown_hermit] compile-flags: --target aarch64-unknown-hermit
+// [aarch64_unknown_hermit] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_illumos
+// [aarch64_unknown_illumos] compile-flags: --target aarch64-unknown-illumos
+// [aarch64_unknown_illumos] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_linux_gnu
+// [aarch64_unknown_linux_gnu] compile-flags: --target aarch64-unknown-linux-gnu
+// [aarch64_unknown_linux_gnu] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_linux_gnu_ilp32
+// [aarch64_unknown_linux_gnu_ilp32] compile-flags: --target aarch64-unknown-linux-gnu_ilp32
+// [aarch64_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_linux_musl
+// [aarch64_unknown_linux_musl] compile-flags: --target aarch64-unknown-linux-musl
+// [aarch64_unknown_linux_musl] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_linux_ohos
+// [aarch64_unknown_linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos
+// [aarch64_unknown_linux_ohos] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_netbsd
+// [aarch64_unknown_netbsd] compile-flags: --target aarch64-unknown-netbsd
+// [aarch64_unknown_netbsd] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_none
+// [aarch64_unknown_none] compile-flags: --target aarch64-unknown-none
+// [aarch64_unknown_none] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_none_softfloat
+// [aarch64_unknown_none_softfloat] compile-flags: --target aarch64-unknown-none-softfloat
+// [aarch64_unknown_none_softfloat] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_nto_qnx_710
+// [aarch64_unknown_nto_qnx_710] compile-flags: --target aarch64-unknown-nto-qnx710
+// [aarch64_unknown_nto_qnx_710] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_openbsd
+// [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd
+// [aarch64_unknown_openbsd] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_redox
+// [aarch64_unknown_redox] compile-flags: --target aarch64-unknown-redox
+// [aarch64_unknown_redox] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_teeos
+// [aarch64_unknown_teeos] compile-flags: --target aarch64-unknown-teeos
+// [aarch64_unknown_teeos] needs-llvm-components: aarch64
+// revisions: aarch64_wrs_vxworks
+// [aarch64_wrs_vxworks] compile-flags: --target aarch64-wrs-vxworks
+// [aarch64_wrs_vxworks] needs-llvm-components: aarch64
+// revisions: arm64_32_apple_watchos
+// [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos
+// [arm64_32_apple_watchos] needs-llvm-components: aarch64
+// revisions: arm64e_apple_darwin
+// [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin
+// [arm64e_apple_darwin] needs-llvm-components: aarch64
+// revisions: arm64e_apple_ios
+// [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios
+// [arm64e_apple_ios] needs-llvm-components: aarch64
+// revisions: arm_linux_androideabi
+// [arm_linux_androideabi] compile-flags: --target arm-linux-androideabi
+// [arm_linux_androideabi] needs-llvm-components: arm
+// revisions: arm_unknown_linux_gnueabi
+// [arm_unknown_linux_gnueabi] compile-flags: --target arm-unknown-linux-gnueabi
+// [arm_unknown_linux_gnueabi] needs-llvm-components: arm
+// revisions: arm_unknown_linux_gnueabihf
+// [arm_unknown_linux_gnueabihf] compile-flags: --target arm-unknown-linux-gnueabihf
+// [arm_unknown_linux_gnueabihf] needs-llvm-components: arm
+// revisions: arm_unknown_linux_musleabi
+// [arm_unknown_linux_musleabi] compile-flags: --target arm-unknown-linux-musleabi
+// [arm_unknown_linux_musleabi] needs-llvm-components: arm
+// revisions: arm_unknown_linux_musleabihf
+// [arm_unknown_linux_musleabihf] compile-flags: --target arm-unknown-linux-musleabihf
+// [arm_unknown_linux_musleabihf] needs-llvm-components: arm
+// revisions: armeb_unknown_linux_gnueabi
+// [armeb_unknown_linux_gnueabi] compile-flags: --target armeb-unknown-linux-gnueabi
+// [armeb_unknown_linux_gnueabi] needs-llvm-components: arm
+// revisions: armebv7r_none_eabi
+// [armebv7r_none_eabi] compile-flags: --target armebv7r-none-eabi
+// [armebv7r_none_eabi] needs-llvm-components: arm
+// revisions: armebv7r_none_eabihf
+// [armebv7r_none_eabihf] compile-flags: --target armebv7r-none-eabihf
+// [armebv7r_none_eabihf] needs-llvm-components: arm
+// revisions: armv4t_none_eabi
+// [armv4t_none_eabi] compile-flags: --target armv4t-none-eabi
+// [armv4t_none_eabi] needs-llvm-components: arm
+// revisions: armv4t_unknown_linux_gnueabi
+// [armv4t_unknown_linux_gnueabi] compile-flags: --target armv4t-unknown-linux-gnueabi
+// [armv4t_unknown_linux_gnueabi] needs-llvm-components: arm
+// revisions: armv5te_none_eabi
+// [armv5te_none_eabi] compile-flags: --target armv5te-none-eabi
+// [armv5te_none_eabi] needs-llvm-components: arm
+// revisions: armv5te_unknown_linux_gnueabi
+// [armv5te_unknown_linux_gnueabi] compile-flags: --target armv5te-unknown-linux-gnueabi
+// [armv5te_unknown_linux_gnueabi] needs-llvm-components: arm
+// revisions: armv5te_unknown_linux_musleabi
+// [armv5te_unknown_linux_musleabi] compile-flags: --target armv5te-unknown-linux-musleabi
+// [armv5te_unknown_linux_musleabi] needs-llvm-components: arm
+// revisions: armv5te_unknown_linux_uclibceabi
+// [armv5te_unknown_linux_uclibceabi] compile-flags: --target armv5te-unknown-linux-uclibceabi
+// [armv5te_unknown_linux_uclibceabi] needs-llvm-components: arm
+// revisions: armv6_unknown_freebsd
+// [armv6_unknown_freebsd] compile-flags: --target armv6-unknown-freebsd
+// [armv6_unknown_freebsd] needs-llvm-components: arm
+// revisions: armv6_unknown_netbsd_eabihf
+// [armv6_unknown_netbsd_eabihf] compile-flags: --target armv6-unknown-netbsd-eabihf
+// [armv6_unknown_netbsd_eabihf] needs-llvm-components: arm
+// revisions: armv6k_nintendo_3ds
+// [armv6k_nintendo_3ds] compile-flags: --target armv6k-nintendo-3ds
+// [armv6k_nintendo_3ds] needs-llvm-components: arm
+// revisions: armv7_linux_androideabi
+// [armv7_linux_androideabi] compile-flags: --target armv7-linux-androideabi
+// [armv7_linux_androideabi] needs-llvm-components: arm
+// revisions: armv7_sony_vita_newlibeabihf
+// [armv7_sony_vita_newlibeabihf] compile-flags: --target armv7-sony-vita-newlibeabihf
+// [armv7_sony_vita_newlibeabihf] needs-llvm-components: arm
+// revisions: armv7_unknown_freebsd
+// [armv7_unknown_freebsd] compile-flags: --target armv7-unknown-freebsd
+// [armv7_unknown_freebsd] needs-llvm-components: arm
+// revisions: armv7_unknown_linux_gnueabi
+// [armv7_unknown_linux_gnueabi] compile-flags: --target armv7-unknown-linux-gnueabi
+// [armv7_unknown_linux_gnueabi] needs-llvm-components: arm
+// revisions: armv7_unknown_linux_gnueabihf
+// [armv7_unknown_linux_gnueabihf] compile-flags: --target armv7-unknown-linux-gnueabihf
+// [armv7_unknown_linux_gnueabihf] needs-llvm-components: arm
+// revisions: armv7_unknown_linux_musleabi
+// [armv7_unknown_linux_musleabi] compile-flags: --target armv7-unknown-linux-musleabi
+// [armv7_unknown_linux_musleabi] needs-llvm-components: arm
+// revisions: armv7_unknown_linux_musleabihf
+// [armv7_unknown_linux_musleabihf] compile-flags: --target armv7-unknown-linux-musleabihf
+// [armv7_unknown_linux_musleabihf] needs-llvm-components: arm
+// revisions: armv7_unknown_linux_ohos
+// [armv7_unknown_linux_ohos] compile-flags: --target armv7-unknown-linux-ohos
+// [armv7_unknown_linux_ohos] needs-llvm-components: arm
+// revisions: armv7_unknown_linux_uclibceabi
+// [armv7_unknown_linux_uclibceabi] compile-flags: --target armv7-unknown-linux-uclibceabi
+// [armv7_unknown_linux_uclibceabi] needs-llvm-components: arm
+// revisions: armv7_unknown_linux_uclibceabihf
+// [armv7_unknown_linux_uclibceabihf] compile-flags: --target armv7-unknown-linux-uclibceabihf
+// [armv7_unknown_linux_uclibceabihf] needs-llvm-components: arm
+// revisions: armv7_unknown_netbsd_eabihf
+// [armv7_unknown_netbsd_eabihf] compile-flags: --target armv7-unknown-netbsd-eabihf
+// [armv7_unknown_netbsd_eabihf] needs-llvm-components: arm
+// revisions: armv7_wrs_vxworks_eabihf
+// [armv7_wrs_vxworks_eabihf] compile-flags: --target armv7-wrs-vxworks-eabihf
+// [armv7_wrs_vxworks_eabihf] needs-llvm-components: arm
+// revisions: armv7a_kmc_solid_asp3_eabi
+// [armv7a_kmc_solid_asp3_eabi] compile-flags: --target armv7a-kmc-solid_asp3-eabi
+// [armv7a_kmc_solid_asp3_eabi] needs-llvm-components: arm
+// revisions: armv7a_kmc_solid_asp3_eabihf
+// [armv7a_kmc_solid_asp3_eabihf] compile-flags: --target armv7a-kmc-solid_asp3-eabihf
+// [armv7a_kmc_solid_asp3_eabihf] needs-llvm-components: arm
+// revisions: armv7a_none_eabi
+// [armv7a_none_eabi] compile-flags: --target armv7a-none-eabi
+// [armv7a_none_eabi] needs-llvm-components: arm
+// revisions: armv7a_none_eabihf
+// [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf
+// [armv7a_none_eabihf] needs-llvm-components: arm
+// revisions: armv7k_apple_watchos
+// [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos
+// [armv7k_apple_watchos] needs-llvm-components: arm
+// revisions: armv7r_none_eabi
+// [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi
+// [armv7r_none_eabi] needs-llvm-components: arm
+// revisions: armv7r_none_eabihf
+// [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf
+// [armv7r_none_eabihf] needs-llvm-components: arm
+// revisions: armv7s_apple_ios
+// [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios
+// [armv7s_apple_ios] needs-llvm-components: arm
+// FIXME: disabled since it fails on CI saying the csky component is missing
+/*
+    revisions: csky_unknown_linux_gnuabiv2
+    [csky_unknown_linux_gnuabiv2] compile-flags: --target csky-unknown-linux-gnuabiv2
+    [csky_unknown_linux_gnuabiv2] needs-llvm-components: csky
+    revisions: csky_unknown_linux_gnuabiv2hf
+    [csky_unknown_linux_gnuabiv2hf] compile-flags: --target csky-unknown-linux-gnuabiv2hf
+    [csky_unknown_linux_gnuabiv2hf] needs-llvm-components: csky
+*/
+// revisions: hexagon_unknown_linux_musl
+// [hexagon_unknown_linux_musl] compile-flags: --target hexagon-unknown-linux-musl
+// [hexagon_unknown_linux_musl] needs-llvm-components: hexagon
+// revisions: hexagon_unknown_none_elf
+// [hexagon_unknown_none_elf] compile-flags: --target hexagon-unknown-none-elf
+// [hexagon_unknown_none_elf] needs-llvm-components: hexagon
+// revisions: i386_apple_ios
+// [i386_apple_ios] compile-flags: --target i386-apple-ios
+// [i386_apple_ios] needs-llvm-components: x86
+// revisions: i586_pc_nto_qnx700
+// [i586_pc_nto_qnx700] compile-flags: --target i586-pc-nto-qnx700
+// [i586_pc_nto_qnx700] needs-llvm-components: x86
+// revisions: i586_unknown_linux_gnu
+// [i586_unknown_linux_gnu] compile-flags: --target i586-unknown-linux-gnu
+// [i586_unknown_linux_gnu] needs-llvm-components: x86
+// revisions: i586_unknown_linux_musl
+// [i586_unknown_linux_musl] compile-flags: --target i586-unknown-linux-musl
+// [i586_unknown_linux_musl] needs-llvm-components: x86
+// revisions: i586_unknown_netbsd
+// [i586_unknown_netbsd] compile-flags: --target i586-unknown-netbsd
+// [i586_unknown_netbsd] needs-llvm-components: x86
+// revisions: i686_apple_darwin
+// [i686_apple_darwin] compile-flags: --target i686-apple-darwin
+// [i686_apple_darwin] needs-llvm-components: x86
+// revisions: i686_linux_android
+// [i686_linux_android] compile-flags: --target i686-linux-android
+// [i686_linux_android] needs-llvm-components: x86
+// revisions: i686_unknown_freebsd
+// [i686_unknown_freebsd] compile-flags: --target i686-unknown-freebsd
+// [i686_unknown_freebsd] needs-llvm-components: x86
+// revisions: i686_unknown_haiku
+// [i686_unknown_haiku] compile-flags: --target i686-unknown-haiku
+// [i686_unknown_haiku] needs-llvm-components: x86
+// revisions: i686_unknown_hurd_gnu
+// [i686_unknown_hurd_gnu] compile-flags: --target i686-unknown-hurd-gnu
+// [i686_unknown_hurd_gnu] needs-llvm-components: x86
+// revisions: i686_unknown_linux_gnu
+// [i686_unknown_linux_gnu] compile-flags: --target i686-unknown-linux-gnu
+// [i686_unknown_linux_gnu] needs-llvm-components: x86
+// revisions: i686_unknown_linux_musl
+// [i686_unknown_linux_musl] compile-flags: --target i686-unknown-linux-musl
+// [i686_unknown_linux_musl] needs-llvm-components: x86
+// revisions: i686_unknown_netbsd
+// [i686_unknown_netbsd] compile-flags: --target i686-unknown-netbsd
+// [i686_unknown_netbsd] needs-llvm-components: x86
+// revisions: i686_unknown_openbsd
+// [i686_unknown_openbsd] compile-flags: --target i686-unknown-openbsd
+// [i686_unknown_openbsd] needs-llvm-components: x86
+// revisions: i686_wrs_vxworks
+// [i686_wrs_vxworks] compile-flags: --target i686-wrs-vxworks
+// [i686_wrs_vxworks] needs-llvm-components: x86
+// revisions: loongarch64_unknown_linux_gnu
+// [loongarch64_unknown_linux_gnu] compile-flags: --target loongarch64-unknown-linux-gnu
+// [loongarch64_unknown_linux_gnu] needs-llvm-components: loongarch
+// revisions: loongarch64_unknown_none
+// [loongarch64_unknown_none] compile-flags: --target loongarch64-unknown-none
+// [loongarch64_unknown_none] needs-llvm-components: loongarch
+// revisions: loongarch64_unknown_none_softfloat
+// [loongarch64_unknown_none_softfloat] compile-flags: --target loongarch64-unknown-none-softfloat
+// [loongarch64_unknown_none_softfloat] needs-llvm-components: loongarch
+// revisions: m68k_unknown_linux_gnu
+// [m68k_unknown_linux_gnu] compile-flags: --target m68k-unknown-linux-gnu
+// [m68k_unknown_linux_gnu] needs-llvm-components: m68k
+// revisions: mips64_openwrt_linux_musl
+// [mips64_openwrt_linux_musl] compile-flags: --target mips64-openwrt-linux-musl
+// [mips64_openwrt_linux_musl] needs-llvm-components: mips
+// revisions: mips64_unknown_linux_gnuabi64
+// [mips64_unknown_linux_gnuabi64] compile-flags: --target mips64-unknown-linux-gnuabi64
+// [mips64_unknown_linux_gnuabi64] needs-llvm-components: mips
+// revisions: mips64_unknown_linux_muslabi64
+// [mips64_unknown_linux_muslabi64] compile-flags: --target mips64-unknown-linux-muslabi64
+// [mips64_unknown_linux_muslabi64] needs-llvm-components: mips
+// revisions: mips64el_unknown_linux_gnuabi64
+// [mips64el_unknown_linux_gnuabi64] compile-flags: --target mips64el-unknown-linux-gnuabi64
+// [mips64el_unknown_linux_gnuabi64] needs-llvm-components: mips
+// revisions: mips64el_unknown_linux_muslabi64
+// [mips64el_unknown_linux_muslabi64] compile-flags: --target mips64el-unknown-linux-muslabi64
+// [mips64el_unknown_linux_muslabi64] needs-llvm-components: mips
+// revisions: mips_unknown_linux_gnu
+// [mips_unknown_linux_gnu] compile-flags: --target mips-unknown-linux-gnu
+// [mips_unknown_linux_gnu] needs-llvm-components: mips
+// revisions: mips_unknown_linux_musl
+// [mips_unknown_linux_musl] compile-flags: --target mips-unknown-linux-musl
+// [mips_unknown_linux_musl] needs-llvm-components: mips
+// revisions: mips_unknown_linux_uclibc
+// [mips_unknown_linux_uclibc] compile-flags: --target mips-unknown-linux-uclibc
+// [mips_unknown_linux_uclibc] needs-llvm-components: mips
+// revisions: mipsel_sony_psp
+// [mipsel_sony_psp] compile-flags: --target mipsel-sony-psp
+// [mipsel_sony_psp] needs-llvm-components: mips
+// revisions: mipsel_sony_psx
+// [mipsel_sony_psx] compile-flags: --target mipsel-sony-psx
+// [mipsel_sony_psx] needs-llvm-components: mips
+// revisions: mipsel_unknown_linux_gnu
+// [mipsel_unknown_linux_gnu] compile-flags: --target mipsel-unknown-linux-gnu
+// [mipsel_unknown_linux_gnu] needs-llvm-components: mips
+// revisions: mipsel_unknown_linux_musl
+// [mipsel_unknown_linux_musl] compile-flags: --target mipsel-unknown-linux-musl
+// [mipsel_unknown_linux_musl] needs-llvm-components: mips
+// revisions: mipsel_unknown_linux_uclibc
+// [mipsel_unknown_linux_uclibc] compile-flags: --target mipsel-unknown-linux-uclibc
+// [mipsel_unknown_linux_uclibc] needs-llvm-components: mips
+// revisions: mipsel_unknown_netbsd
+// [mipsel_unknown_netbsd] compile-flags: --target mipsel-unknown-netbsd
+// [mipsel_unknown_netbsd] needs-llvm-components: mips
+// revisions: mipsel_unknown_none
+// [mipsel_unknown_none] compile-flags: --target mipsel-unknown-none
+// [mipsel_unknown_none] needs-llvm-components: mips
+// revisions: mipsisa32r6_unknown_linux_gnu
+// [mipsisa32r6_unknown_linux_gnu] compile-flags: --target mipsisa32r6-unknown-linux-gnu
+// [mipsisa32r6_unknown_linux_gnu] needs-llvm-components: mips
+// revisions: mipsisa32r6el_unknown_linux_gnu
+// [mipsisa32r6el_unknown_linux_gnu] compile-flags: --target mipsisa32r6el-unknown-linux-gnu
+// [mipsisa32r6el_unknown_linux_gnu] needs-llvm-components: mips
+// revisions: mipsisa64r6_unknown_linux_gnuabi64
+// [mipsisa64r6_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64
+// [mipsisa64r6_unknown_linux_gnuabi64] needs-llvm-components: mips
+// revisions: mipsisa64r6el_unknown_linux_gnuabi64
+// [mipsisa64r6el_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6el-unknown-linux-gnuabi64
+// [mipsisa64r6el_unknown_linux_gnuabi64] needs-llvm-components: mips
+// revisions: msp430_none_elf
+// [msp430_none_elf] compile-flags: --target msp430-none-elf
+// [msp430_none_elf] needs-llvm-components: msp430
+// revisions: powerpc64_unknown_freebsd
+// [powerpc64_unknown_freebsd] compile-flags: --target powerpc64-unknown-freebsd
+// [powerpc64_unknown_freebsd] needs-llvm-components: powerpc
+// revisions: powerpc64_unknown_linux_gnu
+// [powerpc64_unknown_linux_gnu] compile-flags: --target powerpc64-unknown-linux-gnu
+// [powerpc64_unknown_linux_gnu] needs-llvm-components: powerpc
+// revisions: powerpc64_unknown_linux_musl
+// [powerpc64_unknown_linux_musl] compile-flags: --target powerpc64-unknown-linux-musl
+// [powerpc64_unknown_linux_musl] needs-llvm-components: powerpc
+// revisions: powerpc64_unknown_openbsd
+// [powerpc64_unknown_openbsd] compile-flags: --target powerpc64-unknown-openbsd
+// [powerpc64_unknown_openbsd] needs-llvm-components: powerpc
+// revisions: powerpc64_wrs_vxworks
+// [powerpc64_wrs_vxworks] compile-flags: --target powerpc64-wrs-vxworks
+// [powerpc64_wrs_vxworks] needs-llvm-components: powerpc
+// revisions: powerpc64le_unknown_freebsd
+// [powerpc64le_unknown_freebsd] compile-flags: --target powerpc64le-unknown-freebsd
+// [powerpc64le_unknown_freebsd] needs-llvm-components: powerpc
+// revisions: powerpc64le_unknown_linux_gnu
+// [powerpc64le_unknown_linux_gnu] compile-flags: --target powerpc64le-unknown-linux-gnu
+// [powerpc64le_unknown_linux_gnu] needs-llvm-components: powerpc
+// revisions: powerpc64le_unknown_linux_musl
+// [powerpc64le_unknown_linux_musl] compile-flags: --target powerpc64le-unknown-linux-musl
+// [powerpc64le_unknown_linux_musl] needs-llvm-components: powerpc
+// revisions: powerpc_unknown_freebsd
+// [powerpc_unknown_freebsd] compile-flags: --target powerpc-unknown-freebsd
+// [powerpc_unknown_freebsd] needs-llvm-components: powerpc
+// revisions: powerpc_unknown_linux_gnu
+// [powerpc_unknown_linux_gnu] compile-flags: --target powerpc-unknown-linux-gnu
+// [powerpc_unknown_linux_gnu] needs-llvm-components: powerpc
+// revisions: powerpc_unknown_linux_gnuspe
+// [powerpc_unknown_linux_gnuspe] compile-flags: --target powerpc-unknown-linux-gnuspe
+// [powerpc_unknown_linux_gnuspe] needs-llvm-components: powerpc
+// revisions: powerpc_unknown_linux_musl
+// [powerpc_unknown_linux_musl] compile-flags: --target powerpc-unknown-linux-musl
+// [powerpc_unknown_linux_musl] needs-llvm-components: powerpc
+// revisions: powerpc_unknown_netbsd
+// [powerpc_unknown_netbsd] compile-flags: --target powerpc-unknown-netbsd
+// [powerpc_unknown_netbsd] needs-llvm-components: powerpc
+// revisions: powerpc_unknown_openbsd
+// [powerpc_unknown_openbsd] compile-flags: --target powerpc-unknown-openbsd
+// [powerpc_unknown_openbsd] needs-llvm-components: powerpc
+// revisions: powerpc_wrs_vxworks
+// [powerpc_wrs_vxworks] compile-flags: --target powerpc-wrs-vxworks
+// [powerpc_wrs_vxworks] needs-llvm-components: powerpc
+// revisions: powerpc_wrs_vxworks_spe
+// [powerpc_wrs_vxworks_spe] compile-flags: --target powerpc-wrs-vxworks-spe
+// [powerpc_wrs_vxworks_spe] needs-llvm-components: powerpc
+// revisions: riscv32gc_unknown_linux_gnu
+// [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu
+// [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv
+// revisions: riscv32gc_unknown_linux_musl
+// [riscv32gc_unknown_linux_musl] compile-flags: --target riscv32gc-unknown-linux-musl
+// [riscv32gc_unknown_linux_musl] needs-llvm-components: riscv
+// revisions: riscv32i_unknown_none_elf
+// [riscv32i_unknown_none_elf] compile-flags: --target riscv32i-unknown-none-elf
+// [riscv32i_unknown_none_elf] needs-llvm-components: riscv
+// revisions: riscv32im_unknown_none_elf
+// [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf
+// [riscv32im_unknown_none_elf] needs-llvm-components: riscv
+// revisions: riscv32imac_esp_espidf
+// [riscv32imac_esp_espidf] compile-flags: --target riscv32imac-esp-espidf
+// [riscv32imac_esp_espidf] needs-llvm-components: riscv
+// revisions: riscv32imac_unknown_none_elf
+// [riscv32imac_unknown_none_elf] compile-flags: --target riscv32imac-unknown-none-elf
+// [riscv32imac_unknown_none_elf] needs-llvm-components: riscv
+// revisions: riscv32imac_unknown_xous_elf
+// [riscv32imac_unknown_xous_elf] compile-flags: --target riscv32imac-unknown-xous-elf
+// [riscv32imac_unknown_xous_elf] needs-llvm-components: riscv
+// revisions: riscv32imafc_unknown_none_elf
+// [riscv32imafc_unknown_none_elf] compile-flags: --target riscv32imafc-unknown-none-elf
+// [riscv32imafc_unknown_none_elf] needs-llvm-components: riscv
+// revisions: riscv32imafc_esp_espidf
+// [riscv32imafc_esp_espidf] compile-flags: --target riscv32imafc-esp-espidf
+// [riscv32imafc_esp_espidf] needs-llvm-components: riscv
+// revisions: riscv32imc_esp_espidf
+// [riscv32imc_esp_espidf] compile-flags: --target riscv32imc-esp-espidf
+// [riscv32imc_esp_espidf] needs-llvm-components: riscv
+// revisions: riscv32imc_unknown_none_elf
+// [riscv32imc_unknown_none_elf] compile-flags: --target riscv32imc-unknown-none-elf
+// [riscv32imc_unknown_none_elf] needs-llvm-components: riscv
+// revisions: riscv64_linux_android
+// [riscv64_linux_android] compile-flags: --target riscv64-linux-android
+// [riscv64_linux_android] needs-llvm-components: riscv
+// revisions: riscv64gc_unknown_freebsd
+// [riscv64gc_unknown_freebsd] compile-flags: --target riscv64gc-unknown-freebsd
+// [riscv64gc_unknown_freebsd] needs-llvm-components: riscv
+// revisions: riscv64gc_unknown_fuchsia
+// [riscv64gc_unknown_fuchsia] compile-flags: --target riscv64gc-unknown-fuchsia
+// [riscv64gc_unknown_fuchsia] needs-llvm-components: riscv
+// revisions: riscv64gc_unknown_hermit
+// [riscv64gc_unknown_hermit] compile-flags: --target riscv64gc-unknown-hermit
+// [riscv64gc_unknown_hermit] needs-llvm-components: riscv
+// revisions: riscv64gc_unknown_linux_gnu
+// [riscv64gc_unknown_linux_gnu] compile-flags: --target riscv64gc-unknown-linux-gnu
+// [riscv64gc_unknown_linux_gnu] needs-llvm-components: riscv
+// revisions: riscv64gc_unknown_linux_musl
+// [riscv64gc_unknown_linux_musl] compile-flags: --target riscv64gc-unknown-linux-musl
+// [riscv64gc_unknown_linux_musl] needs-llvm-components: riscv
+// revisions: riscv64gc_unknown_netbsd
+// [riscv64gc_unknown_netbsd] compile-flags: --target riscv64gc-unknown-netbsd
+// [riscv64gc_unknown_netbsd] needs-llvm-components: riscv
+// revisions: riscv64gc_unknown_none_elf
+// [riscv64gc_unknown_none_elf] compile-flags: --target riscv64gc-unknown-none-elf
+// [riscv64gc_unknown_none_elf] needs-llvm-components: riscv
+// revisions: riscv64gc_unknown_openbsd
+// [riscv64gc_unknown_openbsd] compile-flags: --target riscv64gc-unknown-openbsd
+// [riscv64gc_unknown_openbsd] needs-llvm-components: riscv
+// revisions: riscv64imac_unknown_none_elf
+// [riscv64imac_unknown_none_elf] compile-flags: --target riscv64imac-unknown-none-elf
+// [riscv64imac_unknown_none_elf] needs-llvm-components: riscv
+// revisions: s390x_unknown_linux_gnu
+// [s390x_unknown_linux_gnu] compile-flags: --target s390x-unknown-linux-gnu
+// [s390x_unknown_linux_gnu] needs-llvm-components: systemz
+// revisions: s390x_unknown_linux_musl
+// [s390x_unknown_linux_musl] compile-flags: --target s390x-unknown-linux-musl
+// [s390x_unknown_linux_musl] needs-llvm-components: systemz
+// revisions: sparc64_unknown_linux_gnu
+// [sparc64_unknown_linux_gnu] compile-flags: --target sparc64-unknown-linux-gnu
+// [sparc64_unknown_linux_gnu] needs-llvm-components: sparc
+// revisions: sparc64_unknown_netbsd
+// [sparc64_unknown_netbsd] compile-flags: --target sparc64-unknown-netbsd
+// [sparc64_unknown_netbsd] needs-llvm-components: sparc
+// revisions: sparc64_unknown_openbsd
+// [sparc64_unknown_openbsd] compile-flags: --target sparc64-unknown-openbsd
+// [sparc64_unknown_openbsd] needs-llvm-components: sparc
+// revisions: sparc_unknown_linux_gnu
+// [sparc_unknown_linux_gnu] compile-flags: --target sparc-unknown-linux-gnu
+// [sparc_unknown_linux_gnu] needs-llvm-components: sparc
+// revisions: sparc_unknown_none_elf
+// [sparc_unknown_none_elf] compile-flags: --target sparc-unknown-none-elf
+// [sparc_unknown_none_elf] needs-llvm-components: sparc
+// revisions: sparcv9_sun_solaris
+// [sparcv9_sun_solaris] compile-flags: --target sparcv9-sun-solaris
+// [sparcv9_sun_solaris] needs-llvm-components: sparc
+// revisions: thumbv4t_none_eabi
+// [thumbv4t_none_eabi] compile-flags: --target thumbv4t-none-eabi
+// [thumbv4t_none_eabi] needs-llvm-components: arm
+// revisions: thumbv5te_none_eabi
+// [thumbv5te_none_eabi] compile-flags: --target thumbv5te-none-eabi
+// [thumbv5te_none_eabi] needs-llvm-components: arm
+// revisions: thumbv6m_none_eabi
+// [thumbv6m_none_eabi] compile-flags: --target thumbv6m-none-eabi
+// [thumbv6m_none_eabi] needs-llvm-components: arm
+// revisions: thumbv7em_none_eabi
+// [thumbv7em_none_eabi] compile-flags: --target thumbv7em-none-eabi
+// [thumbv7em_none_eabi] needs-llvm-components: arm
+// revisions: thumbv7em_none_eabihf
+// [thumbv7em_none_eabihf] compile-flags: --target thumbv7em-none-eabihf
+// [thumbv7em_none_eabihf] needs-llvm-components: arm
+// revisions: thumbv7m_none_eabi
+// [thumbv7m_none_eabi] compile-flags: --target thumbv7m-none-eabi
+// [thumbv7m_none_eabi] needs-llvm-components: arm
+// revisions: thumbv7neon_linux_androideabi
+// [thumbv7neon_linux_androideabi] compile-flags: --target thumbv7neon-linux-androideabi
+// [thumbv7neon_linux_androideabi] needs-llvm-components: arm
+// revisions: thumbv7neon_unknown_linux_gnueabihf
+// [thumbv7neon_unknown_linux_gnueabihf] compile-flags: --target thumbv7neon-unknown-linux-gnueabihf
+// [thumbv7neon_unknown_linux_gnueabihf] needs-llvm-components: arm
+// revisions: thumbv7neon_unknown_linux_musleabihf
+// [thumbv7neon_unknown_linux_musleabihf] compile-flags: --target thumbv7neon-unknown-linux-musleabihf
+// [thumbv7neon_unknown_linux_musleabihf] needs-llvm-components: arm
+// revisions: thumbv8m_base_none_eabi
+// [thumbv8m_base_none_eabi] compile-flags: --target thumbv8m.base-none-eabi
+// [thumbv8m_base_none_eabi] needs-llvm-components: arm
+// revisions: thumbv8m_main_none_eabi
+// [thumbv8m_main_none_eabi] compile-flags: --target thumbv8m.main-none-eabi
+// [thumbv8m_main_none_eabi] needs-llvm-components: arm
+// revisions: thumbv8m_main_none_eabihf
+// [thumbv8m_main_none_eabihf] compile-flags: --target thumbv8m.main-none-eabihf
+// [thumbv8m_main_none_eabihf] needs-llvm-components: arm
+// revisions: wasm32_unknown_emscripten
+// [wasm32_unknown_emscripten] compile-flags: --target wasm32-unknown-emscripten
+// [wasm32_unknown_emscripten] needs-llvm-components: webassembly
+// revisions: wasm32_unknown_unknown
+// [wasm32_unknown_unknown] compile-flags: --target wasm32-unknown-unknown
+// [wasm32_unknown_unknown] needs-llvm-components: webassembly
+// revisions: wasm32_wasi
+// [wasm32_wasi] compile-flags: --target wasm32-wasi
+// [wasm32_wasi] needs-llvm-components: webassembly
+// revisions: wasm32_wasi_preview1_threads
+// [wasm32_wasi_preview1_threads] compile-flags: --target wasm32-wasi-preview1-threads
+// [wasm32_wasi_preview1_threads] needs-llvm-components: webassembly
+// revisions: wasm64_unknown_unknown
+// [wasm64_unknown_unknown] compile-flags: --target wasm64-unknown-unknown
+// [wasm64_unknown_unknown] needs-llvm-components: webassembly
+// revisions: x86_64_apple_darwin
+// [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin
+// [x86_64_apple_darwin] needs-llvm-components: x86
+// revisions: x86_64_apple_ios
+// [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios
+// [x86_64_apple_ios] needs-llvm-components: x86
+// revisions: x86_64_apple_ios_macabi
+// [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi
+// [x86_64_apple_ios_macabi] needs-llvm-components: x86
+// revisions: x86_64_apple_tvos
+// [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos
+// [x86_64_apple_tvos] needs-llvm-components: x86
+// revisions: x86_64_apple_watchos_sim
+// [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim
+// [x86_64_apple_watchos_sim] needs-llvm-components: x86
+// revisions: x86_64_fortanix_unknown_sgx
+// [x86_64_fortanix_unknown_sgx] compile-flags: --target x86_64-fortanix-unknown-sgx
+// [x86_64_fortanix_unknown_sgx] needs-llvm-components: x86
+// revisions: x86_64_fuchsia
+// [x86_64_fuchsia] compile-flags: --target x86_64-fuchsia
+// [x86_64_fuchsia] needs-llvm-components: x86
+// revisions: x86_64_linux_android
+// [x86_64_linux_android] compile-flags: --target x86_64-linux-android
+// [x86_64_linux_android] needs-llvm-components: x86
+// revisions: x86_64_pc_nto_qnx710
+// [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710
+// [x86_64_pc_nto_qnx710] needs-llvm-components: x86
+// revisions: x86_64_pc_solaris
+// [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris
+// [x86_64_pc_solaris] needs-llvm-components: x86
+// revisions: x86_64_unikraft_linux_musl
+// [x86_64_unikraft_linux_musl] compile-flags: --target x86_64-unikraft-linux-musl
+// [x86_64_unikraft_linux_musl] needs-llvm-components: x86
+// revisions: x86_64_unknown_dragonfly
+// [x86_64_unknown_dragonfly] compile-flags: --target x86_64-unknown-dragonfly
+// [x86_64_unknown_dragonfly] needs-llvm-components: x86
+// revisions: x86_64_unknown_freebsd
+// [x86_64_unknown_freebsd] compile-flags: --target x86_64-unknown-freebsd
+// [x86_64_unknown_freebsd] needs-llvm-components: x86
+// revisions: x86_64_unknown_fuchsia
+// [x86_64_unknown_fuchsia] compile-flags: --target x86_64-unknown-fuchsia
+// [x86_64_unknown_fuchsia] needs-llvm-components: x86
+// revisions: x86_64_unknown_haiku
+// [x86_64_unknown_haiku] compile-flags: --target x86_64-unknown-haiku
+// [x86_64_unknown_haiku] needs-llvm-components: x86
+// revisions: x86_64_unknown_hermit
+// [x86_64_unknown_hermit] compile-flags: --target x86_64-unknown-hermit
+// [x86_64_unknown_hermit] needs-llvm-components: x86
+// revisions: x86_64_unknown_illumos
+// [x86_64_unknown_illumos] compile-flags: --target x86_64-unknown-illumos
+// [x86_64_unknown_illumos] needs-llvm-components: x86
+// revisions: x86_64_unknown_l4re_uclibc
+// [x86_64_unknown_l4re_uclibc] compile-flags: --target x86_64-unknown-l4re-uclibc
+// [x86_64_unknown_l4re_uclibc] needs-llvm-components: x86
+// revisions: x86_64_unknown_linux_gnu
+// [x86_64_unknown_linux_gnu] compile-flags: --target x86_64-unknown-linux-gnu
+// [x86_64_unknown_linux_gnu] needs-llvm-components: x86
+// revisions: x86_64_unknown_linux_gnux32
+// [x86_64_unknown_linux_gnux32] compile-flags: --target x86_64-unknown-linux-gnux32
+// [x86_64_unknown_linux_gnux32] needs-llvm-components: x86
+// revisions: x86_64_unknown_linux_musl
+// [x86_64_unknown_linux_musl] compile-flags: --target x86_64-unknown-linux-musl
+// [x86_64_unknown_linux_musl] needs-llvm-components: x86
+// revisions: x86_64_unknown_linux_ohos
+// [x86_64_unknown_linux_ohos] compile-flags: --target x86_64-unknown-linux-ohos
+// [x86_64_unknown_linux_ohos] needs-llvm-components: x86
+// revisions: x86_64_unknown_netbsd
+// [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd
+// [x86_64_unknown_netbsd] needs-llvm-components: x86
+// revisions: x86_64_unknown_none
+// [x86_64_unknown_none] compile-flags: --target x86_64-unknown-none
+// [x86_64_unknown_none] needs-llvm-components: x86
+// revisions: x86_64_unknown_openbsd
+// [x86_64_unknown_openbsd] compile-flags: --target x86_64-unknown-openbsd
+// [x86_64_unknown_openbsd] needs-llvm-components: x86
+// revisions: x86_64_unknown_redox
+// [x86_64_unknown_redox] compile-flags: --target x86_64-unknown-redox
+// [x86_64_unknown_redox] needs-llvm-components: x86
+// revisions: x86_64_wrs_vxworks
+// [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks
+// [x86_64_wrs_vxworks] needs-llvm-components: x86
+// revisions: x86_64h_apple_darwin
+// [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin
+// [x86_64h_apple_darwin] needs-llvm-components: x86
+
+// Sanity-check that each target can produce assembly code.
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized {}
+
+pub fn test() -> u8 {
+    42
+}
+
+// CHECK: .section
diff --git a/tests/assembly/targets/targets-nvptx.rs b/tests/assembly/targets/targets-nvptx.rs
new file mode 100644
index 00000000000..06334230400
--- /dev/null
+++ b/tests/assembly/targets/targets-nvptx.rs
@@ -0,0 +1,21 @@
+// assembly-output: emit-asm
+// ignore-tidy-linelength
+// revisions: nvptx64_nvidia_cuda
+// [nvptx64_nvidia_cuda] compile-flags: --target nvptx64-nvidia-cuda
+// [nvptx64_nvidia_cuda] needs-llvm-components: nvptx
+
+// Sanity-check that each target can produce assembly code.
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized {}
+
+pub fn test() -> u8 {
+    42
+}
+
+// CHECK: .version
diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs
new file mode 100644
index 00000000000..7398d7ef790
--- /dev/null
+++ b/tests/assembly/targets/targets-pe.rs
@@ -0,0 +1,93 @@
+// assembly-output: emit-asm
+// ignore-tidy-linelength
+// revisions: aarch64_pc_windows_msvc
+// [aarch64_pc_windows_msvc] compile-flags: --target aarch64-pc-windows-msvc
+// [aarch64_pc_windows_msvc] needs-llvm-components: aarch64
+// revisions: aarch64_pc_windows_gnullvm
+// [aarch64_pc_windows_gnullvm] compile-flags: --target aarch64-pc-windows-gnullvm
+// [aarch64_pc_windows_gnullvm] needs-llvm-components: aarch64
+// revisions: aarch64_unknown_uefi
+// [aarch64_unknown_uefi] compile-flags: --target aarch64-unknown-uefi
+// [aarch64_unknown_uefi] needs-llvm-components: aarch64
+// revisions: aarch64_uwp_windows_msvc
+// [aarch64_uwp_windows_msvc] compile-flags: --target aarch64-uwp-windows-msvc
+// [aarch64_uwp_windows_msvc] needs-llvm-components: aarch64
+// revisions: avr_unknown_gnu_atmega328
+// [avr_unknown_gnu_atmega328] compile-flags: --target avr-unknown-gnu-atmega328
+// [avr_unknown_gnu_atmega328] needs-llvm-components: avr
+// revisions: bpfeb_unknown_none
+// [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none
+// [bpfeb_unknown_none] needs-llvm-components: bpf
+// revisions: bpfel_unknown_none
+// [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none
+// [bpfel_unknown_none] needs-llvm-components: bpf
+// revisions: i586_pc_windows_msvc
+// [i586_pc_windows_msvc] compile-flags: --target i586-pc-windows-msvc
+// [i586_pc_windows_msvc] needs-llvm-components: x86
+// revisions: i686_pc_windows_gnu
+// [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu
+// [i686_pc_windows_gnu] needs-llvm-components: x86
+// revisions: i686_pc_windows_msvc
+// [i686_pc_windows_msvc] compile-flags: --target i686-pc-windows-msvc
+// [i686_pc_windows_msvc] needs-llvm-components: x86
+// revisions: i686_pc_windows_gnullvm
+// [i686_pc_windows_gnullvm] compile-flags: --target i686-pc-windows-gnullvm
+// [i686_pc_windows_gnullvm] needs-llvm-components: x86
+// revisions: i686_uwp_windows_gnu
+// [i686_uwp_windows_gnu] compile-flags: --target i686-uwp-windows-gnu
+// [i686_uwp_windows_gnu] needs-llvm-components: x86
+// revisions: i686_unknown_uefi
+// [i686_unknown_uefi] compile-flags: --target i686-unknown-uefi
+// [i686_unknown_uefi] needs-llvm-components: x86
+// revisions: i686_uwp_windows_msvc
+// [i686_uwp_windows_msvc] compile-flags: --target i686-uwp-windows-msvc
+// [i686_uwp_windows_msvc] needs-llvm-components: x86
+// revisions: i686_win7_windows_msvc
+// [i686_win7_windows_msvc] compile-flags: --target i686-win7-windows-msvc
+// [i686_win7_windows_msvc] needs-llvm-components: x86
+// revisions: powerpc64_ibm_aix
+// [powerpc64_ibm_aix] compile-flags: --target powerpc64-ibm-aix
+// [powerpc64_ibm_aix] needs-llvm-components: powerpc
+// revisions: thumbv7a_uwp_windows_msvc
+// [thumbv7a_uwp_windows_msvc] compile-flags: --target thumbv7a-uwp-windows-msvc
+// [thumbv7a_uwp_windows_msvc] needs-llvm-components: arm
+// revisions: thumbv7a_pc_windows_msvc
+// [thumbv7a_pc_windows_msvc] compile-flags: --target thumbv7a-pc-windows-msvc
+// [thumbv7a_pc_windows_msvc] needs-llvm-components: arm
+// revisions: x86_64_pc_windows_gnu
+// [x86_64_pc_windows_gnu] compile-flags: --target x86_64-pc-windows-gnu
+// [x86_64_pc_windows_gnu] needs-llvm-components: x86
+// revisions: x86_64_pc_windows_gnullvm
+// [x86_64_pc_windows_gnullvm] compile-flags: --target x86_64-pc-windows-gnullvm
+// [x86_64_pc_windows_gnullvm] needs-llvm-components: x86
+// revisions: x86_64_pc_windows_msvc
+// [x86_64_pc_windows_msvc] compile-flags: --target x86_64-pc-windows-msvc
+// [x86_64_pc_windows_msvc] needs-llvm-components: x86
+// revisions: x86_64_unknown_uefi
+// [x86_64_unknown_uefi] compile-flags: --target x86_64-unknown-uefi
+// [x86_64_unknown_uefi] needs-llvm-components: x86
+// revisions: x86_64_uwp_windows_gnu
+// [x86_64_uwp_windows_gnu] compile-flags: --target x86_64-uwp-windows-gnu
+// [x86_64_uwp_windows_gnu] needs-llvm-components: x86
+// revisions: x86_64_uwp_windows_msvc
+// [x86_64_uwp_windows_msvc] compile-flags: --target x86_64-uwp-windows-msvc
+// [x86_64_uwp_windows_msvc] needs-llvm-components: x86
+// revisions: x86_64_win7_windows_msvc
+// [x86_64_win7_windows_msvc] compile-flags: --target x86_64-win7-windows-msvc
+// [x86_64_win7_windows_msvc] needs-llvm-components: x86
+
+// Sanity-check that each target can produce assembly code.
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized {}
+
+pub fn test() -> u8 {
+    42
+}
+
+// CHECK: .file
diff --git a/tests/debuginfo/collapse-debuginfo-external-attr.rs b/tests/debuginfo/collapse-debuginfo-external-attr.rs
new file mode 100644
index 00000000000..f36b0833ad5
--- /dev/null
+++ b/tests/debuginfo/collapse-debuginfo-external-attr.rs
@@ -0,0 +1,31 @@
+// ignore-lldb
+#![feature(collapse_debuginfo)]
+
+// Test that local macro debug info is not collapsed with #[collapse_debuginfo(external)]
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#one_callsite[...]
+// gdb-command:continue
+
+fn one() {
+    println!("one");
+}
+
+#[collapse_debuginfo(external)]
+macro_rules! outer {
+    () => {
+        one(); // #one_callsite
+    };
+}
+
+fn main() {
+    let ret = 0; // #break
+    outer!();
+    std::process::exit(ret);
+}
diff --git a/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs
new file mode 100644
index 00000000000..e5cbc1a685d
--- /dev/null
+++ b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs
@@ -0,0 +1,34 @@
+// ignore-lldb
+#![feature(collapse_debuginfo)]
+
+// Test that macro attribute #[collapse_debuginfo(no)]
+// overrides "collapse_macro_debuginfo=external" flag
+
+// compile-flags:-g -Z collapse_macro_debuginfo=external
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#one_callsite[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-command:continue
+
+fn one() {
+    println!("one");
+}
+
+#[collapse_debuginfo(no)]
+macro_rules! outer {
+    () => {
+        one(); // #one_callsite
+    };
+}
+
+fn main() {
+    let ret = 0; // #break
+    outer!();
+    std::process::exit(ret);
+}
diff --git a/tests/debuginfo/collapse-debuginfo-external-flag.rs b/tests/debuginfo/collapse-debuginfo-external-flag.rs
new file mode 100644
index 00000000000..9a0aef38ea6
--- /dev/null
+++ b/tests/debuginfo/collapse-debuginfo-external-flag.rs
@@ -0,0 +1,26 @@
+// ignore-lldb
+#![feature(collapse_debuginfo)]
+
+// Test that println macro debug info is collapsed with "collapse_macro_debuginfo=external" flag
+
+// compile-flags:-g -Z collapse_macro_debuginfo=external
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#println_callsite[...]
+// gdb-command:continue
+
+macro_rules! outer {
+    () => {
+        println!("one"); // #println_callsite
+    };
+}
+
+fn main() {
+    let ret = 0; // #break
+    outer!();
+    std::process::exit(ret);
+}
diff --git a/tests/debuginfo/collapse-debuginfo-no-attr.rs b/tests/debuginfo/collapse-debuginfo-no-attr.rs
index 230c8795be3..d156c381a15 100644
--- a/tests/debuginfo/collapse-debuginfo-no-attr.rs
+++ b/tests/debuginfo/collapse-debuginfo-no-attr.rs
@@ -4,7 +4,7 @@
 // Test that line numbers are not replaced with those of the outermost expansion site when the
 // `collapse_debuginfo` feature is active and the attribute is not provided.
 
-// compile-flags:-g
+// compile-flags:-g -Z collapse_macro_debuginfo=no
 
 // === GDB TESTS ===================================================================================
 
diff --git a/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs
new file mode 100644
index 00000000000..76a97a325d7
--- /dev/null
+++ b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs
@@ -0,0 +1,57 @@
+// ignore-lldb
+#![feature(collapse_debuginfo)]
+
+// Test that line numbers are replaced with those of the outermost expansion site when the
+// `collapse_debuginfo` feature is active and the command line flag is provided.
+
+// compile-flags:-g -Z collapse_macro_debuginfo=yes
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc1[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc2[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc3[...]
+// gdb-command:continue
+
+fn one() {
+    println!("one");
+}
+fn two() {
+    println!("two");
+}
+fn three() {
+    println!("three");
+}
+fn four() {
+    println!("four");
+}
+
+macro_rules! outer {
+    ($b:block) => {
+        one();
+        inner!();
+        $b
+    };
+}
+
+macro_rules! inner {
+    () => {
+        two();
+    };
+}
+
+fn main() {
+    let ret = 0; // #break
+    outer!({ // #loc1
+        three(); // #loc2
+        four(); // #loc3
+    });
+    std::process::exit(ret);
+}
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
index f9537661e8c..6d00dd5b212 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
index 07886779fea..7e2f72ab31b 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
index f9537661e8c..6d00dd5b212 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
index 07886779fea..7e2f72ab31b 100644
--- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
++         _4 = const 4_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/boolean_identities.rs b/tests/mir-opt/const_prop/boolean_identities.rs
index f6575ac8e54..3b7ea25ad46 100644
--- a/tests/mir-opt/const_prop/boolean_identities.rs
+++ b/tests/mir-opt/const_prop/boolean_identities.rs
@@ -5,10 +5,9 @@ pub fn test(x: bool, y: bool) -> bool {
     // CHECK-LABEL: fn test(
     // CHECK: debug a => [[a:_.*]];
     // CHECK: debug b => [[b:_.*]];
-    // FIXME(cjgillot) simplify algebraic identity
-    // CHECK-NOT: [[a]] = const true;
-    // CHECK-NOT: [[b]] = const false;
-    // CHECK-NOT: _0 = const false;
+    // CHECK: [[a]] = const true;
+    // CHECK: [[b]] = const false;
+    // CHECK: _0 = const false;
     let a = (y | true);
     let b = (x & false);
     a & b
diff --git a/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff
index eca87af7527..0bd8413289e 100644
--- a/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff
+++ b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff
@@ -24,21 +24,23 @@
           StorageLive(_4);
           _4 = _2;
 -         _3 = BitOr(move _4, const true);
-+         _3 = BitOr(_2, const true);
++         _3 = const true;
           StorageDead(_4);
 -         StorageLive(_5);
 +         nop;
           StorageLive(_6);
           _6 = _1;
 -         _5 = BitAnd(move _6, const false);
-+         _5 = BitAnd(_1, const false);
++         _5 = const false;
           StorageDead(_6);
           StorageLive(_7);
-          _7 = _3;
+-         _7 = _3;
++         _7 = const true;
           StorageLive(_8);
-          _8 = _5;
+-         _8 = _5;
 -         _0 = BitAnd(move _7, move _8);
-+         _0 = BitAnd(_3, _5);
++         _8 = const false;
++         _0 = const false;
           StorageDead(_8);
           StorageDead(_7);
 -         StorageDead(_5);
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
index b3fdaa5ee82..59ee38f5a2b 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
@@ -20,7 +20,8 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
 -         _4 = SizeOf(i32);
 -         _5 = AlignOf(i32);
@@ -39,8 +40,10 @@
           StorageDead(_7);
           _9 = (((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
           _2 = (*_9);
-          _1 = Add(move _2, const 0_i32);
-          StorageDead(_2);
+-         _1 = Add(move _2, const 0_i32);
+-         StorageDead(_2);
++         _1 = _2;
++         nop;
           drop(_3) -> [return: bb2, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
index d0350c97253..9d87bd809d1 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
@@ -20,7 +20,8 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
 -         _4 = SizeOf(i32);
 -         _5 = AlignOf(i32);
@@ -39,8 +40,10 @@
           StorageDead(_7);
           _9 = (((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
           _2 = (*_9);
-          _1 = Add(move _2, const 0_i32);
-          StorageDead(_2);
+-         _1 = Add(move _2, const 0_i32);
+-         StorageDead(_2);
++         _1 = _2;
++         nop;
           drop(_3) -> [return: bb2, unwind: bb3];
       }
   
diff --git a/tests/mir-opt/const_prop/boxes.rs b/tests/mir-opt/const_prop/boxes.rs
index 5227d7b8b8b..d2d61f86d5e 100644
--- a/tests/mir-opt/const_prop/boxes.rs
+++ b/tests/mir-opt/const_prop/boxes.rs
@@ -12,7 +12,7 @@ fn main() {
     // CHECK: debug x => [[x:_.*]];
     // CHECK: (*{{_.*}}) = const 42_i32;
     // CHECK: [[tmp:_.*]] = (*{{_.*}});
-    // CHECK: [[x]] = Add(move [[tmp]], const 0_i32);
+    // CHECK: [[x]] = [[tmp]];
     let x = *(#[rustc_box]
     Box::new(42))
         + 0;
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
index cf36109fdcb..bd987c01ab1 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
index 40ed9697180..e9ebef84ae0 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
index cf36109fdcb..bd987c01ab1 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
index 40ed9697180..e9ebef84ae0 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
-          _4 = Len(_2);
+-         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _5 = Lt(const 2_usize, _4);
-+         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
++         _4 = const 5000_usize;
++         _5 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/mult_by_zero.rs b/tests/mir-opt/const_prop/mult_by_zero.rs
index 2fdb75c3100..b8afaeef43f 100644
--- a/tests/mir-opt/const_prop/mult_by_zero.rs
+++ b/tests/mir-opt/const_prop/mult_by_zero.rs
@@ -3,8 +3,7 @@
 // EMIT_MIR mult_by_zero.test.GVN.diff
 fn test(x: i32) -> i32 {
     // CHECK: fn test(
-    // FIXME(cjgillot) simplify algebraic identity
-    // CHECK-NOT: _0 = const 0_i32;
+    // CHECK: _0 = const 0_i32;
     x * 0
 }
 
diff --git a/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff
index e9fb34749c1..6c2aab45d48 100644
--- a/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff
+++ b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff
@@ -10,7 +10,7 @@
           StorageLive(_2);
           _2 = _1;
 -         _0 = Mul(move _2, const 0_i32);
-+         _0 = Mul(_1, const 0_i32);
++         _0 = const 0_i32;
           StorageDead(_2);
           return;
       }
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
index a52e6e35483..71635b8e9c3 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
-          _5 = Len(_3);
+-         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
-+         _6 = Lt(const 2_usize, _5);
-+         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
index fe0acee71eb..84205028d6d 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
-          _5 = Len(_3);
+-         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
-+         _6 = Lt(const 2_usize, _5);
-+         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
index a52e6e35483..71635b8e9c3 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
-          _5 = Len(_3);
+-         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
-+         _6 = Lt(const 2_usize, _5);
-+         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
index fe0acee71eb..84205028d6d 100644
--- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
-          _5 = Len(_3);
+-         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
-+         _6 = Lt(const 2_usize, _5);
-+         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue];
++         _5 = const 8_usize;
++         _6 = const true;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff
index d524ad242fe..84eb6c5cfe8 100644
--- a/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff
@@ -13,13 +13,13 @@
       let _8: ();
       let mut _9: u64;
       let mut _10: u64;
-      let _11: ();
-      let mut _12: u64;
+      let mut _11: u64;
+      let _12: ();
       let mut _13: u64;
-      let _14: ();
-      let mut _15: u64;
+      let mut _14: u64;
+      let _15: ();
       let mut _16: u64;
-      let mut _17: bool;
+      let mut _17: u64;
       let _18: ();
       let mut _19: u64;
       let mut _20: u64;
@@ -51,18 +51,32 @@
       let _46: ();
       let mut _47: u64;
       let mut _48: u64;
-      let _49: ();
-      let mut _50: u64;
+      let mut _49: bool;
+      let _50: ();
       let mut _51: u64;
-      let _52: ();
-      let mut _53: u64;
+      let mut _52: u64;
+      let _53: ();
       let mut _54: u64;
-      let _55: ();
-      let mut _56: u64;
+      let mut _55: u64;
+      let _56: ();
       let mut _57: u64;
-      let _58: ();
-      let mut _59: u64;
+      let mut _58: u64;
+      let _59: ();
       let mut _60: u64;
+      let mut _61: u64;
+      let _62: ();
+      let mut _63: u64;
+      let mut _64: u64;
+      let _65: ();
+      let mut _66: u64;
+      let mut _67: u64;
+      let mut _68: u64;
+      let _69: ();
+      let mut _70: u64;
+      let mut _71: u64;
+      let _72: ();
+      let mut _73: u64;
+      let mut _74: u64;
   
       bb0: {
           StorageLive(_2);
@@ -70,9 +84,10 @@
           StorageLive(_4);
           _4 = _1;
 -         _3 = Add(move _4, const 0_u64);
-+         _3 = Add(_1, const 0_u64);
++         _3 = _1;
           StorageDead(_4);
-          _2 = opaque::<u64>(move _3) -> [return: bb1, unwind unreachable];
+-         _2 = opaque::<u64>(move _3) -> [return: bb1, unwind unreachable];
++         _2 = opaque::<u64>(_1) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -83,98 +98,101 @@
           StorageLive(_7);
           _7 = _1;
 -         _6 = Sub(move _7, const 0_u64);
-+         _6 = Sub(_1, const 0_u64);
++         _6 = _1;
           StorageDead(_7);
-          _5 = opaque::<u64>(move _6) -> [return: bb2, unwind unreachable];
+-         _5 = opaque::<u64>(move _6) -> [return: bb2, unwind unreachable];
++         _5 = opaque::<u64>(_1) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
           StorageDead(_6);
           StorageDead(_5);
           StorageLive(_8);
-          StorageLive(_9);
+-         StorageLive(_9);
++         nop;
           StorageLive(_10);
           _10 = _1;
--         _9 = Mul(move _10, const 0_u64);
-+         _9 = Mul(_1, const 0_u64);
+          StorageLive(_11);
+          _11 = _1;
+-         _9 = Sub(move _10, move _11);
++         _9 = const 0_u64;
+          StorageDead(_11);
           StorageDead(_10);
-          _8 = opaque::<u64>(move _9) -> [return: bb3, unwind unreachable];
+-         _8 = opaque::<u64>(move _9) -> [return: bb3, unwind unreachable];
++         _8 = opaque::<u64>(const 0_u64) -> [return: bb3, unwind unreachable];
       }
   
       bb3: {
-          StorageDead(_9);
+-         StorageDead(_9);
++         nop;
           StorageDead(_8);
-          StorageLive(_11);
           StorageLive(_12);
           StorageLive(_13);
-          _13 = _1;
--         _12 = Mul(move _13, const 1_u64);
-+         _12 = Mul(_1, const 1_u64);
-          StorageDead(_13);
-          _11 = opaque::<u64>(move _12) -> [return: bb4, unwind unreachable];
+          StorageLive(_14);
+          _14 = _1;
+-         _13 = Mul(move _14, const 0_u64);
++         _13 = const 0_u64;
+          StorageDead(_14);
+-         _12 = opaque::<u64>(move _13) -> [return: bb4, unwind unreachable];
++         _12 = opaque::<u64>(const 0_u64) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
+          StorageDead(_13);
           StorageDead(_12);
-          StorageDead(_11);
-          StorageLive(_14);
           StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
--         _17 = Eq(const 0_u64, const 0_u64);
--         assert(!move _17, "attempt to divide `{}` by zero", _16) -> [success: bb5, unwind unreachable];
-+         _17 = const true;
-+         assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb5, unwind unreachable];
+          StorageLive(_17);
+          _17 = _1;
+-         _16 = Mul(move _17, const 1_u64);
++         _16 = _1;
+          StorageDead(_17);
+-         _15 = opaque::<u64>(move _16) -> [return: bb5, unwind unreachable];
++         _15 = opaque::<u64>(_1) -> [return: bb5, unwind unreachable];
       }
   
       bb5: {
--         _15 = Div(move _16, const 0_u64);
-+         _15 = Div(_1, const 0_u64);
           StorageDead(_16);
-          _14 = opaque::<u64>(move _15) -> [return: bb6, unwind unreachable];
-      }
-  
-      bb6: {
           StorageDead(_15);
-          StorageDead(_14);
           StorageLive(_18);
           StorageLive(_19);
           StorageLive(_20);
           _20 = _1;
--         _21 = Eq(const 1_u64, const 0_u64);
--         assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb7, unwind unreachable];
-+         _21 = const false;
-+         assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb7, unwind unreachable];
+-         _21 = Eq(const 0_u64, const 0_u64);
+-         assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb6, unwind unreachable];
++         _21 = const true;
++         assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb6, unwind unreachable];
       }
   
-      bb7: {
--         _19 = Div(move _20, const 1_u64);
-+         _19 = Div(_1, const 1_u64);
+      bb6: {
+-         _19 = Div(move _20, const 0_u64);
++         _19 = Div(_1, const 0_u64);
           StorageDead(_20);
-          _18 = opaque::<u64>(move _19) -> [return: bb8, unwind unreachable];
+          _18 = opaque::<u64>(move _19) -> [return: bb7, unwind unreachable];
       }
   
-      bb8: {
+      bb7: {
           StorageDead(_19);
           StorageDead(_18);
           StorageLive(_22);
           StorageLive(_23);
           StorageLive(_24);
           _24 = _1;
--         _25 = Eq(_24, const 0_u64);
--         assert(!move _25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind unreachable];
-+         _25 = Eq(_1, const 0_u64);
-+         assert(!_25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind unreachable];
+-         _25 = Eq(const 1_u64, const 0_u64);
+-         assert(!move _25, "attempt to divide `{}` by zero", _24) -> [success: bb8, unwind unreachable];
++         _25 = const false;
++         assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb8, unwind unreachable];
       }
   
-      bb9: {
--         _23 = Div(const 0_u64, move _24);
-+         _23 = Div(const 0_u64, _1);
+      bb8: {
+-         _23 = Div(move _24, const 1_u64);
++         _23 = _1;
           StorageDead(_24);
-          _22 = opaque::<u64>(move _23) -> [return: bb10, unwind unreachable];
+-         _22 = opaque::<u64>(move _23) -> [return: bb9, unwind unreachable];
++         _22 = opaque::<u64>(_1) -> [return: bb9, unwind unreachable];
       }
   
-      bb10: {
+      bb9: {
           StorageDead(_23);
           StorageDead(_22);
           StorageLive(_26);
@@ -182,79 +200,81 @@
           StorageLive(_28);
           _28 = _1;
 -         _29 = Eq(_28, const 0_u64);
--         assert(!move _29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind unreachable];
-+         _29 = _25;
-+         assert(!_25, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind unreachable];
+-         assert(!move _29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind unreachable];
++         _29 = Eq(_1, const 0_u64);
++         assert(!_29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind unreachable];
       }
   
-      bb11: {
--         _27 = Div(const 1_u64, move _28);
-+         _27 = Div(const 1_u64, _1);
+      bb10: {
+-         _27 = Div(const 0_u64, move _28);
++         _27 = const 0_u64;
           StorageDead(_28);
-          _26 = opaque::<u64>(move _27) -> [return: bb12, unwind unreachable];
+-         _26 = opaque::<u64>(move _27) -> [return: bb11, unwind unreachable];
++         _26 = opaque::<u64>(const 0_u64) -> [return: bb11, unwind unreachable];
       }
   
-      bb12: {
+      bb11: {
           StorageDead(_27);
           StorageDead(_26);
           StorageLive(_30);
           StorageLive(_31);
           StorageLive(_32);
           _32 = _1;
--         _33 = Eq(const 0_u64, const 0_u64);
--         assert(!move _33, "attempt to calculate the remainder of `{}` with a divisor of zero", _32) -> [success: bb13, unwind unreachable];
-+         _33 = const true;
-+         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb13, unwind unreachable];
+-         _33 = Eq(_32, const 0_u64);
+-         assert(!move _33, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind unreachable];
++         _33 = _29;
++         assert(!_29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind unreachable];
       }
   
-      bb13: {
--         _31 = Rem(move _32, const 0_u64);
-+         _31 = Rem(_1, const 0_u64);
+      bb12: {
+-         _31 = Div(const 1_u64, move _32);
++         _31 = Div(const 1_u64, _1);
           StorageDead(_32);
-          _30 = opaque::<u64>(move _31) -> [return: bb14, unwind unreachable];
+          _30 = opaque::<u64>(move _31) -> [return: bb13, unwind unreachable];
       }
   
-      bb14: {
+      bb13: {
           StorageDead(_31);
           StorageDead(_30);
           StorageLive(_34);
           StorageLive(_35);
           StorageLive(_36);
           _36 = _1;
--         _37 = Eq(const 1_u64, const 0_u64);
--         assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb15, unwind unreachable];
-+         _37 = const false;
-+         assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb15, unwind unreachable];
+-         _37 = Eq(const 0_u64, const 0_u64);
+-         assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb14, unwind unreachable];
++         _37 = const true;
++         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb14, unwind unreachable];
       }
   
-      bb15: {
--         _35 = Rem(move _36, const 1_u64);
-+         _35 = Rem(_1, const 1_u64);
+      bb14: {
+-         _35 = Rem(move _36, const 0_u64);
++         _35 = Rem(_1, const 0_u64);
           StorageDead(_36);
-          _34 = opaque::<u64>(move _35) -> [return: bb16, unwind unreachable];
+          _34 = opaque::<u64>(move _35) -> [return: bb15, unwind unreachable];
       }
   
-      bb16: {
+      bb15: {
           StorageDead(_35);
           StorageDead(_34);
           StorageLive(_38);
           StorageLive(_39);
           StorageLive(_40);
           _40 = _1;
--         _41 = Eq(_40, const 0_u64);
--         assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind unreachable];
-+         _41 = _25;
-+         assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind unreachable];
+-         _41 = Eq(const 1_u64, const 0_u64);
+-         assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", _40) -> [success: bb16, unwind unreachable];
++         _41 = const false;
++         assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb16, unwind unreachable];
       }
   
-      bb17: {
--         _39 = Rem(const 0_u64, move _40);
-+         _39 = Rem(const 0_u64, _1);
+      bb16: {
+-         _39 = Rem(move _40, const 1_u64);
++         _39 = const 0_u64;
           StorageDead(_40);
-          _38 = opaque::<u64>(move _39) -> [return: bb18, unwind unreachable];
+-         _38 = opaque::<u64>(move _39) -> [return: bb17, unwind unreachable];
++         _38 = opaque::<u64>(const 0_u64) -> [return: bb17, unwind unreachable];
       }
   
-      bb18: {
+      bb17: {
           StorageDead(_39);
           StorageDead(_38);
           StorageLive(_42);
@@ -262,27 +282,35 @@
           StorageLive(_44);
           _44 = _1;
 -         _45 = Eq(_44, const 0_u64);
--         assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind unreachable];
-+         _45 = _25;
-+         assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind unreachable];
+-         assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind unreachable];
++         _45 = _29;
++         assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind unreachable];
       }
   
-      bb19: {
--         _43 = Rem(const 1_u64, move _44);
-+         _43 = Rem(const 1_u64, _1);
+      bb18: {
+-         _43 = Rem(const 0_u64, move _44);
++         _43 = const 0_u64;
           StorageDead(_44);
-          _42 = opaque::<u64>(move _43) -> [return: bb20, unwind unreachable];
+-         _42 = opaque::<u64>(move _43) -> [return: bb19, unwind unreachable];
++         _42 = opaque::<u64>(const 0_u64) -> [return: bb19, unwind unreachable];
       }
   
-      bb20: {
+      bb19: {
           StorageDead(_43);
           StorageDead(_42);
           StorageLive(_46);
           StorageLive(_47);
           StorageLive(_48);
           _48 = _1;
--         _47 = BitAnd(move _48, const 0_u64);
-+         _47 = BitAnd(_1, const 0_u64);
+-         _49 = Eq(_48, const 0_u64);
+-         assert(!move _49, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind unreachable];
++         _49 = _29;
++         assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind unreachable];
+      }
+  
+      bb20: {
+-         _47 = Rem(const 1_u64, move _48);
++         _47 = Rem(const 1_u64, _1);
           StorageDead(_48);
           _46 = opaque::<u64>(move _47) -> [return: bb21, unwind unreachable];
       }
@@ -290,58 +318,121 @@
       bb21: {
           StorageDead(_47);
           StorageDead(_46);
-          StorageLive(_49);
           StorageLive(_50);
           StorageLive(_51);
-          _51 = _1;
--         _50 = BitOr(move _51, const 0_u64);
-+         _50 = BitOr(_1, const 0_u64);
-          StorageDead(_51);
-          _49 = opaque::<u64>(move _50) -> [return: bb22, unwind unreachable];
+          StorageLive(_52);
+          _52 = _1;
+-         _51 = BitAnd(move _52, const 0_u64);
++         _51 = const 0_u64;
+          StorageDead(_52);
+-         _50 = opaque::<u64>(move _51) -> [return: bb22, unwind unreachable];
++         _50 = opaque::<u64>(const 0_u64) -> [return: bb22, unwind unreachable];
       }
   
       bb22: {
+          StorageDead(_51);
           StorageDead(_50);
-          StorageDead(_49);
-          StorageLive(_52);
           StorageLive(_53);
           StorageLive(_54);
-          _54 = _1;
--         _53 = BitXor(move _54, const 0_u64);
-+         _53 = BitXor(_1, const 0_u64);
-          StorageDead(_54);
-          _52 = opaque::<u64>(move _53) -> [return: bb23, unwind unreachable];
+          StorageLive(_55);
+          _55 = _1;
+-         _54 = BitAnd(move _55, const _);
++         _54 = _1;
+          StorageDead(_55);
+-         _53 = opaque::<u64>(move _54) -> [return: bb23, unwind unreachable];
++         _53 = opaque::<u64>(_1) -> [return: bb23, unwind unreachable];
       }
   
       bb23: {
+          StorageDead(_54);
           StorageDead(_53);
-          StorageDead(_52);
-          StorageLive(_55);
           StorageLive(_56);
           StorageLive(_57);
-          _57 = _1;
--         _56 = Shr(move _57, const 0_i32);
-+         _56 = Shr(_1, const 0_i32);
-          StorageDead(_57);
-          _55 = opaque::<u64>(move _56) -> [return: bb24, unwind unreachable];
+          StorageLive(_58);
+          _58 = _1;
+-         _57 = BitOr(move _58, const 0_u64);
++         _57 = _1;
+          StorageDead(_58);
+-         _56 = opaque::<u64>(move _57) -> [return: bb24, unwind unreachable];
++         _56 = opaque::<u64>(_1) -> [return: bb24, unwind unreachable];
       }
   
       bb24: {
+          StorageDead(_57);
           StorageDead(_56);
-          StorageDead(_55);
-          StorageLive(_58);
           StorageLive(_59);
           StorageLive(_60);
-          _60 = _1;
--         _59 = Shl(move _60, const 0_i32);
-+         _59 = Shl(_1, const 0_i32);
-          StorageDead(_60);
-          _58 = opaque::<u64>(move _59) -> [return: bb25, unwind unreachable];
+          StorageLive(_61);
+          _61 = _1;
+-         _60 = BitOr(move _61, const _);
++         _60 = const u64::MAX;
+          StorageDead(_61);
+-         _59 = opaque::<u64>(move _60) -> [return: bb25, unwind unreachable];
++         _59 = opaque::<u64>(const u64::MAX) -> [return: bb25, unwind unreachable];
       }
   
       bb25: {
+          StorageDead(_60);
           StorageDead(_59);
-          StorageDead(_58);
+          StorageLive(_62);
+          StorageLive(_63);
+          StorageLive(_64);
+          _64 = _1;
+-         _63 = BitXor(move _64, const 0_u64);
++         _63 = _1;
+          StorageDead(_64);
+-         _62 = opaque::<u64>(move _63) -> [return: bb26, unwind unreachable];
++         _62 = opaque::<u64>(_1) -> [return: bb26, unwind unreachable];
+      }
+  
+      bb26: {
+          StorageDead(_63);
+          StorageDead(_62);
+          StorageLive(_65);
+          StorageLive(_66);
+          StorageLive(_67);
+          _67 = _1;
+          StorageLive(_68);
+          _68 = _1;
+-         _66 = BitXor(move _67, move _68);
++         _66 = const 0_u64;
+          StorageDead(_68);
+          StorageDead(_67);
+-         _65 = opaque::<u64>(move _66) -> [return: bb27, unwind unreachable];
++         _65 = opaque::<u64>(const 0_u64) -> [return: bb27, unwind unreachable];
+      }
+  
+      bb27: {
+          StorageDead(_66);
+          StorageDead(_65);
+          StorageLive(_69);
+          StorageLive(_70);
+          StorageLive(_71);
+          _71 = _1;
+-         _70 = Shr(move _71, const 0_i32);
++         _70 = _1;
+          StorageDead(_71);
+-         _69 = opaque::<u64>(move _70) -> [return: bb28, unwind unreachable];
++         _69 = opaque::<u64>(_1) -> [return: bb28, unwind unreachable];
+      }
+  
+      bb28: {
+          StorageDead(_70);
+          StorageDead(_69);
+          StorageLive(_72);
+          StorageLive(_73);
+          StorageLive(_74);
+          _74 = _1;
+-         _73 = Shl(move _74, const 0_i32);
++         _73 = _1;
+          StorageDead(_74);
+-         _72 = opaque::<u64>(move _73) -> [return: bb29, unwind unreachable];
++         _72 = opaque::<u64>(_1) -> [return: bb29, unwind unreachable];
+      }
+  
+      bb29: {
+          StorageDead(_73);
+          StorageDead(_72);
           _0 = const ();
           return;
       }
diff --git a/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff
index 9d69353934c..98e92d2a310 100644
--- a/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff
@@ -13,13 +13,13 @@
       let _8: ();
       let mut _9: u64;
       let mut _10: u64;
-      let _11: ();
-      let mut _12: u64;
+      let mut _11: u64;
+      let _12: ();
       let mut _13: u64;
-      let _14: ();
-      let mut _15: u64;
+      let mut _14: u64;
+      let _15: ();
       let mut _16: u64;
-      let mut _17: bool;
+      let mut _17: u64;
       let _18: ();
       let mut _19: u64;
       let mut _20: u64;
@@ -51,18 +51,32 @@
       let _46: ();
       let mut _47: u64;
       let mut _48: u64;
-      let _49: ();
-      let mut _50: u64;
+      let mut _49: bool;
+      let _50: ();
       let mut _51: u64;
-      let _52: ();
-      let mut _53: u64;
+      let mut _52: u64;
+      let _53: ();
       let mut _54: u64;
-      let _55: ();
-      let mut _56: u64;
+      let mut _55: u64;
+      let _56: ();
       let mut _57: u64;
-      let _58: ();
-      let mut _59: u64;
+      let mut _58: u64;
+      let _59: ();
       let mut _60: u64;
+      let mut _61: u64;
+      let _62: ();
+      let mut _63: u64;
+      let mut _64: u64;
+      let _65: ();
+      let mut _66: u64;
+      let mut _67: u64;
+      let mut _68: u64;
+      let _69: ();
+      let mut _70: u64;
+      let mut _71: u64;
+      let _72: ();
+      let mut _73: u64;
+      let mut _74: u64;
   
       bb0: {
           StorageLive(_2);
@@ -70,9 +84,10 @@
           StorageLive(_4);
           _4 = _1;
 -         _3 = Add(move _4, const 0_u64);
-+         _3 = Add(_1, const 0_u64);
++         _3 = _1;
           StorageDead(_4);
-          _2 = opaque::<u64>(move _3) -> [return: bb1, unwind continue];
+-         _2 = opaque::<u64>(move _3) -> [return: bb1, unwind continue];
++         _2 = opaque::<u64>(_1) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -83,98 +98,101 @@
           StorageLive(_7);
           _7 = _1;
 -         _6 = Sub(move _7, const 0_u64);
-+         _6 = Sub(_1, const 0_u64);
++         _6 = _1;
           StorageDead(_7);
-          _5 = opaque::<u64>(move _6) -> [return: bb2, unwind continue];
+-         _5 = opaque::<u64>(move _6) -> [return: bb2, unwind continue];
++         _5 = opaque::<u64>(_1) -> [return: bb2, unwind continue];
       }
   
       bb2: {
           StorageDead(_6);
           StorageDead(_5);
           StorageLive(_8);
-          StorageLive(_9);
+-         StorageLive(_9);
++         nop;
           StorageLive(_10);
           _10 = _1;
--         _9 = Mul(move _10, const 0_u64);
-+         _9 = Mul(_1, const 0_u64);
+          StorageLive(_11);
+          _11 = _1;
+-         _9 = Sub(move _10, move _11);
++         _9 = const 0_u64;
+          StorageDead(_11);
           StorageDead(_10);
-          _8 = opaque::<u64>(move _9) -> [return: bb3, unwind continue];
+-         _8 = opaque::<u64>(move _9) -> [return: bb3, unwind continue];
++         _8 = opaque::<u64>(const 0_u64) -> [return: bb3, unwind continue];
       }
   
       bb3: {
-          StorageDead(_9);
+-         StorageDead(_9);
++         nop;
           StorageDead(_8);
-          StorageLive(_11);
           StorageLive(_12);
           StorageLive(_13);
-          _13 = _1;
--         _12 = Mul(move _13, const 1_u64);
-+         _12 = Mul(_1, const 1_u64);
-          StorageDead(_13);
-          _11 = opaque::<u64>(move _12) -> [return: bb4, unwind continue];
+          StorageLive(_14);
+          _14 = _1;
+-         _13 = Mul(move _14, const 0_u64);
++         _13 = const 0_u64;
+          StorageDead(_14);
+-         _12 = opaque::<u64>(move _13) -> [return: bb4, unwind continue];
++         _12 = opaque::<u64>(const 0_u64) -> [return: bb4, unwind continue];
       }
   
       bb4: {
+          StorageDead(_13);
           StorageDead(_12);
-          StorageDead(_11);
-          StorageLive(_14);
           StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
--         _17 = Eq(const 0_u64, const 0_u64);
--         assert(!move _17, "attempt to divide `{}` by zero", _16) -> [success: bb5, unwind continue];
-+         _17 = const true;
-+         assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb5, unwind continue];
+          StorageLive(_17);
+          _17 = _1;
+-         _16 = Mul(move _17, const 1_u64);
++         _16 = _1;
+          StorageDead(_17);
+-         _15 = opaque::<u64>(move _16) -> [return: bb5, unwind continue];
++         _15 = opaque::<u64>(_1) -> [return: bb5, unwind continue];
       }
   
       bb5: {
--         _15 = Div(move _16, const 0_u64);
-+         _15 = Div(_1, const 0_u64);
           StorageDead(_16);
-          _14 = opaque::<u64>(move _15) -> [return: bb6, unwind continue];
-      }
-  
-      bb6: {
           StorageDead(_15);
-          StorageDead(_14);
           StorageLive(_18);
           StorageLive(_19);
           StorageLive(_20);
           _20 = _1;
--         _21 = Eq(const 1_u64, const 0_u64);
--         assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb7, unwind continue];
-+         _21 = const false;
-+         assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb7, unwind continue];
+-         _21 = Eq(const 0_u64, const 0_u64);
+-         assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb6, unwind continue];
++         _21 = const true;
++         assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb6, unwind continue];
       }
   
-      bb7: {
--         _19 = Div(move _20, const 1_u64);
-+         _19 = Div(_1, const 1_u64);
+      bb6: {
+-         _19 = Div(move _20, const 0_u64);
++         _19 = Div(_1, const 0_u64);
           StorageDead(_20);
-          _18 = opaque::<u64>(move _19) -> [return: bb8, unwind continue];
+          _18 = opaque::<u64>(move _19) -> [return: bb7, unwind continue];
       }
   
-      bb8: {
+      bb7: {
           StorageDead(_19);
           StorageDead(_18);
           StorageLive(_22);
           StorageLive(_23);
           StorageLive(_24);
           _24 = _1;
--         _25 = Eq(_24, const 0_u64);
--         assert(!move _25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind continue];
-+         _25 = Eq(_1, const 0_u64);
-+         assert(!_25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind continue];
+-         _25 = Eq(const 1_u64, const 0_u64);
+-         assert(!move _25, "attempt to divide `{}` by zero", _24) -> [success: bb8, unwind continue];
++         _25 = const false;
++         assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb8, unwind continue];
       }
   
-      bb9: {
--         _23 = Div(const 0_u64, move _24);
-+         _23 = Div(const 0_u64, _1);
+      bb8: {
+-         _23 = Div(move _24, const 1_u64);
++         _23 = _1;
           StorageDead(_24);
-          _22 = opaque::<u64>(move _23) -> [return: bb10, unwind continue];
+-         _22 = opaque::<u64>(move _23) -> [return: bb9, unwind continue];
++         _22 = opaque::<u64>(_1) -> [return: bb9, unwind continue];
       }
   
-      bb10: {
+      bb9: {
           StorageDead(_23);
           StorageDead(_22);
           StorageLive(_26);
@@ -182,79 +200,81 @@
           StorageLive(_28);
           _28 = _1;
 -         _29 = Eq(_28, const 0_u64);
--         assert(!move _29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind continue];
-+         _29 = _25;
-+         assert(!_25, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind continue];
+-         assert(!move _29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind continue];
++         _29 = Eq(_1, const 0_u64);
++         assert(!_29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind continue];
       }
   
-      bb11: {
--         _27 = Div(const 1_u64, move _28);
-+         _27 = Div(const 1_u64, _1);
+      bb10: {
+-         _27 = Div(const 0_u64, move _28);
++         _27 = const 0_u64;
           StorageDead(_28);
-          _26 = opaque::<u64>(move _27) -> [return: bb12, unwind continue];
+-         _26 = opaque::<u64>(move _27) -> [return: bb11, unwind continue];
++         _26 = opaque::<u64>(const 0_u64) -> [return: bb11, unwind continue];
       }
   
-      bb12: {
+      bb11: {
           StorageDead(_27);
           StorageDead(_26);
           StorageLive(_30);
           StorageLive(_31);
           StorageLive(_32);
           _32 = _1;
--         _33 = Eq(const 0_u64, const 0_u64);
--         assert(!move _33, "attempt to calculate the remainder of `{}` with a divisor of zero", _32) -> [success: bb13, unwind continue];
-+         _33 = const true;
-+         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb13, unwind continue];
+-         _33 = Eq(_32, const 0_u64);
+-         assert(!move _33, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind continue];
++         _33 = _29;
++         assert(!_29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind continue];
       }
   
-      bb13: {
--         _31 = Rem(move _32, const 0_u64);
-+         _31 = Rem(_1, const 0_u64);
+      bb12: {
+-         _31 = Div(const 1_u64, move _32);
++         _31 = Div(const 1_u64, _1);
           StorageDead(_32);
-          _30 = opaque::<u64>(move _31) -> [return: bb14, unwind continue];
+          _30 = opaque::<u64>(move _31) -> [return: bb13, unwind continue];
       }
   
-      bb14: {
+      bb13: {
           StorageDead(_31);
           StorageDead(_30);
           StorageLive(_34);
           StorageLive(_35);
           StorageLive(_36);
           _36 = _1;
--         _37 = Eq(const 1_u64, const 0_u64);
--         assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb15, unwind continue];
-+         _37 = const false;
-+         assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb15, unwind continue];
+-         _37 = Eq(const 0_u64, const 0_u64);
+-         assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb14, unwind continue];
++         _37 = const true;
++         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb14, unwind continue];
       }
   
-      bb15: {
--         _35 = Rem(move _36, const 1_u64);
-+         _35 = Rem(_1, const 1_u64);
+      bb14: {
+-         _35 = Rem(move _36, const 0_u64);
++         _35 = Rem(_1, const 0_u64);
           StorageDead(_36);
-          _34 = opaque::<u64>(move _35) -> [return: bb16, unwind continue];
+          _34 = opaque::<u64>(move _35) -> [return: bb15, unwind continue];
       }
   
-      bb16: {
+      bb15: {
           StorageDead(_35);
           StorageDead(_34);
           StorageLive(_38);
           StorageLive(_39);
           StorageLive(_40);
           _40 = _1;
--         _41 = Eq(_40, const 0_u64);
--         assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind continue];
-+         _41 = _25;
-+         assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind continue];
+-         _41 = Eq(const 1_u64, const 0_u64);
+-         assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", _40) -> [success: bb16, unwind continue];
++         _41 = const false;
++         assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb16, unwind continue];
       }
   
-      bb17: {
--         _39 = Rem(const 0_u64, move _40);
-+         _39 = Rem(const 0_u64, _1);
+      bb16: {
+-         _39 = Rem(move _40, const 1_u64);
++         _39 = const 0_u64;
           StorageDead(_40);
-          _38 = opaque::<u64>(move _39) -> [return: bb18, unwind continue];
+-         _38 = opaque::<u64>(move _39) -> [return: bb17, unwind continue];
++         _38 = opaque::<u64>(const 0_u64) -> [return: bb17, unwind continue];
       }
   
-      bb18: {
+      bb17: {
           StorageDead(_39);
           StorageDead(_38);
           StorageLive(_42);
@@ -262,27 +282,35 @@
           StorageLive(_44);
           _44 = _1;
 -         _45 = Eq(_44, const 0_u64);
--         assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind continue];
-+         _45 = _25;
-+         assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind continue];
+-         assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind continue];
++         _45 = _29;
++         assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind continue];
       }
   
-      bb19: {
--         _43 = Rem(const 1_u64, move _44);
-+         _43 = Rem(const 1_u64, _1);
+      bb18: {
+-         _43 = Rem(const 0_u64, move _44);
++         _43 = const 0_u64;
           StorageDead(_44);
-          _42 = opaque::<u64>(move _43) -> [return: bb20, unwind continue];
+-         _42 = opaque::<u64>(move _43) -> [return: bb19, unwind continue];
++         _42 = opaque::<u64>(const 0_u64) -> [return: bb19, unwind continue];
       }
   
-      bb20: {
+      bb19: {
           StorageDead(_43);
           StorageDead(_42);
           StorageLive(_46);
           StorageLive(_47);
           StorageLive(_48);
           _48 = _1;
--         _47 = BitAnd(move _48, const 0_u64);
-+         _47 = BitAnd(_1, const 0_u64);
+-         _49 = Eq(_48, const 0_u64);
+-         assert(!move _49, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind continue];
++         _49 = _29;
++         assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind continue];
+      }
+  
+      bb20: {
+-         _47 = Rem(const 1_u64, move _48);
++         _47 = Rem(const 1_u64, _1);
           StorageDead(_48);
           _46 = opaque::<u64>(move _47) -> [return: bb21, unwind continue];
       }
@@ -290,58 +318,121 @@
       bb21: {
           StorageDead(_47);
           StorageDead(_46);
-          StorageLive(_49);
           StorageLive(_50);
           StorageLive(_51);
-          _51 = _1;
--         _50 = BitOr(move _51, const 0_u64);
-+         _50 = BitOr(_1, const 0_u64);
-          StorageDead(_51);
-          _49 = opaque::<u64>(move _50) -> [return: bb22, unwind continue];
+          StorageLive(_52);
+          _52 = _1;
+-         _51 = BitAnd(move _52, const 0_u64);
++         _51 = const 0_u64;
+          StorageDead(_52);
+-         _50 = opaque::<u64>(move _51) -> [return: bb22, unwind continue];
++         _50 = opaque::<u64>(const 0_u64) -> [return: bb22, unwind continue];
       }
   
       bb22: {
+          StorageDead(_51);
           StorageDead(_50);
-          StorageDead(_49);
-          StorageLive(_52);
           StorageLive(_53);
           StorageLive(_54);
-          _54 = _1;
--         _53 = BitXor(move _54, const 0_u64);
-+         _53 = BitXor(_1, const 0_u64);
-          StorageDead(_54);
-          _52 = opaque::<u64>(move _53) -> [return: bb23, unwind continue];
+          StorageLive(_55);
+          _55 = _1;
+-         _54 = BitAnd(move _55, const _);
++         _54 = _1;
+          StorageDead(_55);
+-         _53 = opaque::<u64>(move _54) -> [return: bb23, unwind continue];
++         _53 = opaque::<u64>(_1) -> [return: bb23, unwind continue];
       }
   
       bb23: {
+          StorageDead(_54);
           StorageDead(_53);
-          StorageDead(_52);
-          StorageLive(_55);
           StorageLive(_56);
           StorageLive(_57);
-          _57 = _1;
--         _56 = Shr(move _57, const 0_i32);
-+         _56 = Shr(_1, const 0_i32);
-          StorageDead(_57);
-          _55 = opaque::<u64>(move _56) -> [return: bb24, unwind continue];
+          StorageLive(_58);
+          _58 = _1;
+-         _57 = BitOr(move _58, const 0_u64);
++         _57 = _1;
+          StorageDead(_58);
+-         _56 = opaque::<u64>(move _57) -> [return: bb24, unwind continue];
++         _56 = opaque::<u64>(_1) -> [return: bb24, unwind continue];
       }
   
       bb24: {
+          StorageDead(_57);
           StorageDead(_56);
-          StorageDead(_55);
-          StorageLive(_58);
           StorageLive(_59);
           StorageLive(_60);
-          _60 = _1;
--         _59 = Shl(move _60, const 0_i32);
-+         _59 = Shl(_1, const 0_i32);
-          StorageDead(_60);
-          _58 = opaque::<u64>(move _59) -> [return: bb25, unwind continue];
+          StorageLive(_61);
+          _61 = _1;
+-         _60 = BitOr(move _61, const _);
++         _60 = const u64::MAX;
+          StorageDead(_61);
+-         _59 = opaque::<u64>(move _60) -> [return: bb25, unwind continue];
++         _59 = opaque::<u64>(const u64::MAX) -> [return: bb25, unwind continue];
       }
   
       bb25: {
+          StorageDead(_60);
           StorageDead(_59);
-          StorageDead(_58);
+          StorageLive(_62);
+          StorageLive(_63);
+          StorageLive(_64);
+          _64 = _1;
+-         _63 = BitXor(move _64, const 0_u64);
++         _63 = _1;
+          StorageDead(_64);
+-         _62 = opaque::<u64>(move _63) -> [return: bb26, unwind continue];
++         _62 = opaque::<u64>(_1) -> [return: bb26, unwind continue];
+      }
+  
+      bb26: {
+          StorageDead(_63);
+          StorageDead(_62);
+          StorageLive(_65);
+          StorageLive(_66);
+          StorageLive(_67);
+          _67 = _1;
+          StorageLive(_68);
+          _68 = _1;
+-         _66 = BitXor(move _67, move _68);
++         _66 = const 0_u64;
+          StorageDead(_68);
+          StorageDead(_67);
+-         _65 = opaque::<u64>(move _66) -> [return: bb27, unwind continue];
++         _65 = opaque::<u64>(const 0_u64) -> [return: bb27, unwind continue];
+      }
+  
+      bb27: {
+          StorageDead(_66);
+          StorageDead(_65);
+          StorageLive(_69);
+          StorageLive(_70);
+          StorageLive(_71);
+          _71 = _1;
+-         _70 = Shr(move _71, const 0_i32);
++         _70 = _1;
+          StorageDead(_71);
+-         _69 = opaque::<u64>(move _70) -> [return: bb28, unwind continue];
++         _69 = opaque::<u64>(_1) -> [return: bb28, unwind continue];
+      }
+  
+      bb28: {
+          StorageDead(_70);
+          StorageDead(_69);
+          StorageLive(_72);
+          StorageLive(_73);
+          StorageLive(_74);
+          _74 = _1;
+-         _73 = Shl(move _74, const 0_i32);
++         _73 = _1;
+          StorageDead(_74);
+-         _72 = opaque::<u64>(move _73) -> [return: bb29, unwind continue];
++         _72 = opaque::<u64>(_1) -> [return: bb29, unwind continue];
+      }
+  
+      bb29: {
+          StorageDead(_73);
+          StorageDead(_72);
           _0 = const ();
           return;
       }
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
index 6633df3ae70..a45d9920a68 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
@@ -15,11 +15,16 @@
       let _10: ();
       let mut _11: u64;
       let mut _12: u64;
-      let mut _13: (u64, bool);
-      let _14: ();
-      let mut _15: u64;
+      let mut _13: u64;
+      let mut _14: (u64, bool);
+      let _15: ();
       let mut _16: u64;
-      let mut _17: (u64, bool);
+      let mut _17: u64;
+      let mut _18: (u64, bool);
+      let _19: ();
+      let mut _20: u64;
+      let mut _21: u64;
+      let mut _22: (u64, bool);
   
       bb0: {
           StorageLive(_2);
@@ -29,13 +34,15 @@
 -         _5 = CheckedAdd(_4, const 0_u64);
 -         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind unreachable];
 +         _5 = CheckedAdd(_1, const 0_u64);
-+         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable];
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
-          _3 = move (_5.0: u64);
+-         _3 = move (_5.0: u64);
++         _3 = _1;
           StorageDead(_4);
-          _2 = opaque::<u64>(move _3) -> [return: bb2, unwind unreachable];
+-         _2 = opaque::<u64>(move _3) -> [return: bb2, unwind unreachable];
++         _2 = opaque::<u64>(_1) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
@@ -47,59 +54,95 @@
           _8 = _1;
 -         _9 = CheckedSub(_8, const 0_u64);
 -         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind unreachable];
-+         _9 = CheckedSub(_1, const 0_u64);
-+         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable];
++         _9 = _5;
++         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable];
       }
   
       bb3: {
-          _7 = move (_9.0: u64);
+-         _7 = move (_9.0: u64);
++         _7 = _1;
           StorageDead(_8);
-          _6 = opaque::<u64>(move _7) -> [return: bb4, unwind unreachable];
+-         _6 = opaque::<u64>(move _7) -> [return: bb4, unwind unreachable];
++         _6 = opaque::<u64>(_1) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
           StorageDead(_7);
           StorageDead(_6);
           StorageLive(_10);
-          StorageLive(_11);
+-         StorageLive(_11);
++         nop;
           StorageLive(_12);
           _12 = _1;
--         _13 = CheckedMul(_12, const 0_u64);
--         assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", move _12, const 0_u64) -> [success: bb5, unwind unreachable];
-+         _13 = CheckedMul(_1, const 0_u64);
-+         assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb5, unwind unreachable];
+          StorageLive(_13);
+          _13 = _1;
+-         _14 = CheckedSub(_12, _13);
+-         assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind unreachable];
++         _14 = const (0_u64, false);
++         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind unreachable];
       }
   
       bb5: {
-          _11 = move (_13.0: u64);
+-         _11 = move (_14.0: u64);
++         _11 = const 0_u64;
+          StorageDead(_13);
           StorageDead(_12);
-          _10 = opaque::<u64>(move _11) -> [return: bb6, unwind unreachable];
+-         _10 = opaque::<u64>(move _11) -> [return: bb6, unwind unreachable];
++         _10 = opaque::<u64>(const 0_u64) -> [return: bb6, unwind unreachable];
       }
   
       bb6: {
-          StorageDead(_11);
+-         StorageDead(_11);
++         nop;
           StorageDead(_10);
-          StorageLive(_14);
           StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
--         _17 = CheckedMul(_16, const 1_u64);
--         assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", move _16, const 1_u64) -> [success: bb7, unwind unreachable];
-+         _17 = CheckedMul(_1, const 1_u64);
-+         assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb7, unwind unreachable];
+          StorageLive(_17);
+          _17 = _1;
+-         _18 = CheckedMul(_17, const 0_u64);
+-         assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind unreachable];
++         _18 = const (0_u64, false);
++         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind unreachable];
       }
   
       bb7: {
-          _15 = move (_17.0: u64);
-          StorageDead(_16);
-          _14 = opaque::<u64>(move _15) -> [return: bb8, unwind unreachable];
+-         _16 = move (_18.0: u64);
++         _16 = const 0_u64;
+          StorageDead(_17);
+-         _15 = opaque::<u64>(move _16) -> [return: bb8, unwind unreachable];
++         _15 = opaque::<u64>(const 0_u64) -> [return: bb8, unwind unreachable];
       }
   
       bb8: {
+          StorageDead(_16);
           StorageDead(_15);
-          StorageDead(_14);
+          StorageLive(_19);
+          StorageLive(_20);
+          StorageLive(_21);
+          _21 = _1;
+-         _22 = CheckedMul(_21, const 1_u64);
+-         assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind unreachable];
++         _22 = _5;
++         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind unreachable];
+      }
+  
+      bb9: {
+-         _20 = move (_22.0: u64);
++         _20 = _1;
+          StorageDead(_21);
+-         _19 = opaque::<u64>(move _20) -> [return: bb10, unwind unreachable];
++         _19 = opaque::<u64>(_1) -> [return: bb10, unwind unreachable];
+      }
+  
+      bb10: {
+          StorageDead(_20);
+          StorageDead(_19);
           _0 = const ();
           return;
       }
++ }
++ 
++ ALLOC0 (size: 16, align: 8) {
++     00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░
   }
   
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
index d100a77fee5..9033b392bd4 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
@@ -15,11 +15,16 @@
       let _10: ();
       let mut _11: u64;
       let mut _12: u64;
-      let mut _13: (u64, bool);
-      let _14: ();
-      let mut _15: u64;
+      let mut _13: u64;
+      let mut _14: (u64, bool);
+      let _15: ();
       let mut _16: u64;
-      let mut _17: (u64, bool);
+      let mut _17: u64;
+      let mut _18: (u64, bool);
+      let _19: ();
+      let mut _20: u64;
+      let mut _21: u64;
+      let mut _22: (u64, bool);
   
       bb0: {
           StorageLive(_2);
@@ -29,13 +34,15 @@
 -         _5 = CheckedAdd(_4, const 0_u64);
 -         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind continue];
 +         _5 = CheckedAdd(_1, const 0_u64);
-+         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue];
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue];
       }
   
       bb1: {
-          _3 = move (_5.0: u64);
+-         _3 = move (_5.0: u64);
++         _3 = _1;
           StorageDead(_4);
-          _2 = opaque::<u64>(move _3) -> [return: bb2, unwind continue];
+-         _2 = opaque::<u64>(move _3) -> [return: bb2, unwind continue];
++         _2 = opaque::<u64>(_1) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -47,59 +54,95 @@
           _8 = _1;
 -         _9 = CheckedSub(_8, const 0_u64);
 -         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind continue];
-+         _9 = CheckedSub(_1, const 0_u64);
-+         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue];
++         _9 = _5;
++         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue];
       }
   
       bb3: {
-          _7 = move (_9.0: u64);
+-         _7 = move (_9.0: u64);
++         _7 = _1;
           StorageDead(_8);
-          _6 = opaque::<u64>(move _7) -> [return: bb4, unwind continue];
+-         _6 = opaque::<u64>(move _7) -> [return: bb4, unwind continue];
++         _6 = opaque::<u64>(_1) -> [return: bb4, unwind continue];
       }
   
       bb4: {
           StorageDead(_7);
           StorageDead(_6);
           StorageLive(_10);
-          StorageLive(_11);
+-         StorageLive(_11);
++         nop;
           StorageLive(_12);
           _12 = _1;
--         _13 = CheckedMul(_12, const 0_u64);
--         assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", move _12, const 0_u64) -> [success: bb5, unwind continue];
-+         _13 = CheckedMul(_1, const 0_u64);
-+         assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb5, unwind continue];
+          StorageLive(_13);
+          _13 = _1;
+-         _14 = CheckedSub(_12, _13);
+-         assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind continue];
++         _14 = const (0_u64, false);
++         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind continue];
       }
   
       bb5: {
-          _11 = move (_13.0: u64);
+-         _11 = move (_14.0: u64);
++         _11 = const 0_u64;
+          StorageDead(_13);
           StorageDead(_12);
-          _10 = opaque::<u64>(move _11) -> [return: bb6, unwind continue];
+-         _10 = opaque::<u64>(move _11) -> [return: bb6, unwind continue];
++         _10 = opaque::<u64>(const 0_u64) -> [return: bb6, unwind continue];
       }
   
       bb6: {
-          StorageDead(_11);
+-         StorageDead(_11);
++         nop;
           StorageDead(_10);
-          StorageLive(_14);
           StorageLive(_15);
           StorageLive(_16);
-          _16 = _1;
--         _17 = CheckedMul(_16, const 1_u64);
--         assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", move _16, const 1_u64) -> [success: bb7, unwind continue];
-+         _17 = CheckedMul(_1, const 1_u64);
-+         assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb7, unwind continue];
+          StorageLive(_17);
+          _17 = _1;
+-         _18 = CheckedMul(_17, const 0_u64);
+-         assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind continue];
++         _18 = const (0_u64, false);
++         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind continue];
       }
   
       bb7: {
-          _15 = move (_17.0: u64);
-          StorageDead(_16);
-          _14 = opaque::<u64>(move _15) -> [return: bb8, unwind continue];
+-         _16 = move (_18.0: u64);
++         _16 = const 0_u64;
+          StorageDead(_17);
+-         _15 = opaque::<u64>(move _16) -> [return: bb8, unwind continue];
++         _15 = opaque::<u64>(const 0_u64) -> [return: bb8, unwind continue];
       }
   
       bb8: {
+          StorageDead(_16);
           StorageDead(_15);
-          StorageDead(_14);
+          StorageLive(_19);
+          StorageLive(_20);
+          StorageLive(_21);
+          _21 = _1;
+-         _22 = CheckedMul(_21, const 1_u64);
+-         assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind continue];
++         _22 = _5;
++         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind continue];
+      }
+  
+      bb9: {
+-         _20 = move (_22.0: u64);
++         _20 = _1;
+          StorageDead(_21);
+-         _19 = opaque::<u64>(move _20) -> [return: bb10, unwind continue];
++         _19 = opaque::<u64>(_1) -> [return: bb10, unwind continue];
+      }
+  
+      bb10: {
+          StorageDead(_20);
+          StorageDead(_19);
           _0 = const ();
           return;
       }
++ }
++ 
++ ALLOC0 (size: 16, align: 8) {
++     00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░
   }
   
diff --git a/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff b/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff
index ee3b9da2122..fefdf14bddc 100644
--- a/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff
@@ -30,10 +30,11 @@
           StorageLive(_6);
           _6 = _1;
 -         _4 = Eq(move _5, move _6);
-+         _4 = Eq(_1, _1);
++         _4 = const true;
           StorageDead(_6);
           StorageDead(_5);
-          _3 = opaque::<bool>(move _4) -> [return: bb1, unwind unreachable];
+-         _3 = opaque::<bool>(move _4) -> [return: bb1, unwind unreachable];
++         _3 = opaque::<bool>(const true) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -46,10 +47,11 @@
           StorageLive(_10);
           _10 = _1;
 -         _8 = Ne(move _9, move _10);
-+         _8 = Ne(_1, _1);
++         _8 = const false;
           StorageDead(_10);
           StorageDead(_9);
-          _7 = opaque::<bool>(move _8) -> [return: bb2, unwind unreachable];
+-         _7 = opaque::<bool>(move _8) -> [return: bb2, unwind unreachable];
++         _7 = opaque::<bool>(const false) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
diff --git a/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff b/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff
index a1408fe3434..9f19b2b59fa 100644
--- a/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff
@@ -30,10 +30,11 @@
           StorageLive(_6);
           _6 = _1;
 -         _4 = Eq(move _5, move _6);
-+         _4 = Eq(_1, _1);
++         _4 = const true;
           StorageDead(_6);
           StorageDead(_5);
-          _3 = opaque::<bool>(move _4) -> [return: bb1, unwind continue];
+-         _3 = opaque::<bool>(move _4) -> [return: bb1, unwind continue];
++         _3 = opaque::<bool>(const true) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -46,10 +47,11 @@
           StorageLive(_10);
           _10 = _1;
 -         _8 = Ne(move _9, move _10);
-+         _8 = Ne(_1, _1);
++         _8 = const false;
           StorageDead(_10);
           StorageDead(_9);
-          _7 = opaque::<bool>(move _8) -> [return: bb2, unwind continue];
+-         _7 = opaque::<bool>(move _8) -> [return: bb2, unwind continue];
++         _7 = opaque::<bool>(const false) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
index d8248d22d38..02bf95840da 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21};
+      let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21};
+      let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:591:19: 591:21};
+              let _7: {closure@$DIR/gvn.rs:610:19: 610:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:591:19: 591:21};
+-         _7 = {closure@$DIR/gvn.rs:610:19: 610:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
index e38a3d85209..c5dcc8a8ec9 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21};
+      let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21};
+      let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:591:19: 591:21};
+              let _7: {closure@$DIR/gvn.rs:610:19: 610:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:591:19: 591:21};
+-         _7 = {closure@$DIR/gvn.rs:610:19: 610:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
index d937902e891..8ce05c9b340 100644
--- a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff
@@ -32,11 +32,12 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = const 0_usize;
-          _8 = Len(_3);
+-         _8 = Len(_3);
 -         _9 = Lt(_7, _8);
 -         assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb1, unwind unreachable];
-+         _9 = Lt(const 0_usize, _8);
-+         assert(move _9, "index out of bounds: the length is {} but the index is {}", _8, const 0_usize) -> [success: bb1, unwind unreachable];
++         _8 = const N;
++         _9 = Lt(const 0_usize, const N);
++         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -57,9 +58,9 @@
 -         _13 = Len(_3);
 -         _14 = Lt(_12, _13);
 -         assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, _12) -> [success: bb3, unwind unreachable];
-+         _13 = _8;
-+         _14 = Lt(_2, _8);
-+         assert(move _14, "index out of bounds: the length is {} but the index is {}", _8, _2) -> [success: bb3, unwind unreachable];
++         _13 = const N;
++         _14 = Lt(_2, const N);
++         assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, _2) -> [success: bb3, unwind unreachable];
       }
   
       bb3: {
diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
index dd4d24b12ea..7ed547eeb4a 100644
--- a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff
@@ -32,11 +32,12 @@
           StorageLive(_6);
           StorageLive(_7);
           _7 = const 0_usize;
-          _8 = Len(_3);
+-         _8 = Len(_3);
 -         _9 = Lt(_7, _8);
 -         assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb1, unwind continue];
-+         _9 = Lt(const 0_usize, _8);
-+         assert(move _9, "index out of bounds: the length is {} but the index is {}", _8, const 0_usize) -> [success: bb1, unwind continue];
++         _8 = const N;
++         _9 = Lt(const 0_usize, const N);
++         assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -57,9 +58,9 @@
 -         _13 = Len(_3);
 -         _14 = Lt(_12, _13);
 -         assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, _12) -> [success: bb3, unwind continue];
-+         _13 = _8;
-+         _14 = Lt(_2, _8);
-+         assert(move _14, "index out of bounds: the length is {} but the index is {}", _8, _2) -> [success: bb3, unwind continue];
++         _13 = const N;
++         _14 = Lt(_2, const N);
++         assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, _2) -> [success: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 23e33a0fa49..31ea237cbec 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -166,69 +166,89 @@ fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) {
     opaque(a[idx]);
 }
 
+fn unary(x: i64) {
+    // CHECK-LABEL: fn unary(
+    // CHECK: opaque::<i64>(_1)
+    opaque(--x); // This is `x`.
+
+    // CHECK: [[b:_.*]] = Lt(_1, const 13_i64);
+    // CHECK: opaque::<bool>([[b]])
+    let b = x < 13;
+    opaque(!!b); // This is `b`.
+
+    // Both lines should test the same thing.
+    // CHECK: [[c:_.*]] = Ne(_1, const 15_i64);
+    // CHECK: opaque::<bool>([[c]])
+    // CHECK: opaque::<bool>([[c]])
+    opaque(x != 15);
+    opaque(!(x == 15));
+
+    // Both lines should test the same thing.
+    // CHECK: [[d:_.*]] = Eq(_1, const 35_i64);
+    // CHECK: opaque::<bool>([[d]])
+    // CHECK: opaque::<bool>([[d]])
+    opaque(x == 35);
+    opaque(!(x != 35));
+}
+
 /// Verify symbolic integer arithmetic simplifications.
 fn arithmetic(x: u64) {
     // CHECK-LABEL: fn arithmetic(
-    // CHECK: [[add:_.*]] = Add(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[add]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x + 0);
-    // CHECK: [[sub:_.*]] = Sub(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[sub]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x - 0);
-    // CHECK: [[mul0:_.*]] = Mul(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[mul0]])
+    // CHECK: opaque::<u64>(const 0_u64)
+    opaque(x - x);
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(x * 0);
-    // CHECK: [[mul1:_.*]] = Mul(_1, const 1_u64);
-    // CHECK: opaque::<u64>(move [[mul1]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x * 1);
+    // CHECK: assert(!const true, "attempt to divide `{}` by zero",
     // CHECK: [[div0:_.*]] = Div(_1, const 0_u64);
     // CHECK: opaque::<u64>(move [[div0]])
     opaque(x / 0);
-    // CHECK: [[div1:_.*]] = Div(_1, const 1_u64);
-    // CHECK: opaque::<u64>(move [[div1]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x / 1);
-    // CHECK: [[zdiv:_.*]] = Div(const 0_u64, _1);
-    // CHECK: opaque::<u64>(move [[zdiv]])
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(0 / x);
     // CHECK: [[odiv:_.*]] = Div(const 1_u64, _1);
     // CHECK: opaque::<u64>(move [[odiv]])
     opaque(1 / x);
+    // CHECK: assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero"
     // CHECK: [[rem0:_.*]] = Rem(_1, const 0_u64);
     // CHECK: opaque::<u64>(move [[rem0]])
     opaque(x % 0);
-    // CHECK: [[rem1:_.*]] = Rem(_1, const 1_u64);
-    // CHECK: opaque::<u64>(move [[rem1]])
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(x % 1);
-    // CHECK: [[zrem:_.*]] = Rem(const 0_u64, _1);
-    // CHECK: opaque::<u64>(move [[zrem]])
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(0 % x);
     // CHECK: [[orem:_.*]] = Rem(const 1_u64, _1);
     // CHECK: opaque::<u64>(move [[orem]])
     opaque(1 % x);
-    // CHECK: [[and:_.*]] = BitAnd(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[and]])
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(x & 0);
-    // CHECK: [[or:_.*]] = BitOr(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[or]])
+    // CHECK: opaque::<u64>(_1)
+    opaque(x & u64::MAX);
+    // CHECK: opaque::<u64>(_1)
     opaque(x | 0);
-    // CHECK: [[xor:_.*]] = BitXor(_1, const 0_u64);
-    // CHECK: opaque::<u64>(move [[xor]])
+    // CHECK: opaque::<u64>(const u64::MAX)
+    opaque(x | u64::MAX);
+    // CHECK: opaque::<u64>(_1)
     opaque(x ^ 0);
-    // CHECK: [[shr:_.*]] = Shr(_1, const 0_i32);
-    // CHECK: opaque::<u64>(move [[shr]])
+    // CHECK: opaque::<u64>(const 0_u64)
+    opaque(x ^ x);
+    // CHECK: opaque::<u64>(_1)
     opaque(x >> 0);
-    // CHECK: [[shl:_.*]] = Shl(_1, const 0_i32);
-    // CHECK: opaque::<u64>(move [[shl]])
+    // CHECK: opaque::<u64>(_1)
     opaque(x << 0);
 }
 
 fn comparison(x: u64, y: u64) {
     // CHECK-LABEL: fn comparison(
-    // CHECK: [[eqxx:_.*]] = Eq(_1, _1);
-    // CHECK: opaque::<bool>(move [[eqxx]])
+    // CHECK: opaque::<bool>(const true)
     opaque(x == x);
-    // CHECK: [[nexx:_.*]] = Ne(_1, _1);
-    // CHECK: opaque::<bool>(move [[nexx]])
+    // CHECK: opaque::<bool>(const false)
     opaque(x != x);
     // CHECK: [[eqxy:_.*]] = Eq(_1, _2);
     // CHECK: opaque::<bool>(move [[eqxy]])
@@ -242,21 +262,20 @@ fn comparison(x: u64, y: u64) {
 #[rustc_inherit_overflow_checks]
 fn arithmetic_checked(x: u64) {
     // CHECK-LABEL: fn arithmetic_checked(
-    // CHECK: [[cadd:_.*]] = CheckedAdd(_1, const 0_u64);
-    // CHECK: [[add:_.*]] = move ([[cadd]].0: u64);
-    // CHECK: opaque::<u64>(move [[add]])
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(_1)
     opaque(x + 0);
-    // CHECK: [[csub:_.*]] = CheckedSub(_1, const 0_u64);
-    // CHECK: [[sub:_.*]] = move ([[csub]].0: u64);
-    // CHECK: opaque::<u64>(move [[sub]])
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(_1)
     opaque(x - 0);
-    // CHECK: [[cmul0:_.*]] = CheckedMul(_1, const 0_u64);
-    // CHECK: [[mul0:_.*]] = move ([[cmul0]].0: u64);
-    // CHECK: opaque::<u64>(move [[mul0]])
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(const 0_u64)
+    opaque(x - x);
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(const 0_u64)
     opaque(x * 0);
-    // CHECK: [[cmul1:_.*]] = CheckedMul(_1, const 1_u64);
-    // CHECK: [[mul1:_.*]] = move ([[cmul1]].0: u64);
-    // CHECK: opaque::<u64>(move [[mul1]])
+    // CHECK: assert(!const false,
+    // CHECK: opaque::<u64>(_1)
     opaque(x * 1);
 }
 
@@ -625,10 +644,32 @@ fn constant_index_overflow<T: Copy>(x: &[T]) {
     opaque(b)
 }
 
+fn wide_ptr_ops() {
+    let a: *const dyn Send = &1 as &dyn Send;
+    let b: *const dyn Send = &1 as &dyn Send;
+    let _val = a == b;
+    let _val = a != b;
+    let _val = a < b;
+    let _val = a <= b;
+    let _val = a > b;
+    let _val = a >= b;
+
+    let a: *const [u8] = unsafe { transmute((1usize, 1usize)) };
+    let b: *const [u8] = unsafe { transmute((1usize, 2usize)) };
+
+    opaque(!(a == b));
+    opaque(a != b);
+    opaque(a <= b);
+    opaque(a < b);
+    opaque(!(a >= b));
+    opaque(!(a > b));
+}
+
 fn main() {
     subexpression_elimination(2, 4, 5);
     wrap_unwrap(5);
     repeated_index::<u32, 7>(5, 3);
+    unary(i64::MIN);
     arithmetic(5);
     comparison(5, 6);
     arithmetic_checked(5);
@@ -644,6 +685,7 @@ fn main() {
     fn_pointers();
     indirect_static();
     constant_index_overflow(&[5, 3]);
+    wide_ptr_ops();
 }
 
 #[inline(never)]
@@ -657,6 +699,7 @@ fn identity<T>(x: T) -> T {
 // EMIT_MIR gvn.subexpression_elimination.GVN.diff
 // EMIT_MIR gvn.wrap_unwrap.GVN.diff
 // EMIT_MIR gvn.repeated_index.GVN.diff
+// EMIT_MIR gvn.unary.GVN.diff
 // EMIT_MIR gvn.arithmetic.GVN.diff
 // EMIT_MIR gvn.comparison.GVN.diff
 // EMIT_MIR gvn.arithmetic_checked.GVN.diff
@@ -671,3 +714,4 @@ fn identity<T>(x: T) -> T {
 // EMIT_MIR gvn.fn_pointers.GVN.diff
 // EMIT_MIR gvn.indirect_static.GVN.diff
 // EMIT_MIR gvn.constant_index_overflow.GVN.diff
+// EMIT_MIR gvn.wide_ptr_ops.GVN.diff
diff --git a/tests/mir-opt/gvn.unary.GVN.panic-abort.diff b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff
new file mode 100644
index 00000000000..9469032f294
--- /dev/null
+++ b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff
@@ -0,0 +1,153 @@
+- // MIR for `unary` before GVN
++ // MIR for `unary` after GVN
+  
+  fn unary(_1: i64) -> () {
+      debug x => _1;
+      let mut _0: ();
+      let _2: ();
+      let mut _3: i64;
+      let mut _4: i64;
+      let mut _5: i64;
+      let _6: bool;
+      let mut _7: i64;
+      let _8: ();
+      let mut _9: bool;
+      let mut _10: bool;
+      let mut _11: bool;
+      let _12: ();
+      let mut _13: bool;
+      let mut _14: i64;
+      let _15: ();
+      let mut _16: bool;
+      let mut _17: bool;
+      let mut _18: i64;
+      let _19: ();
+      let mut _20: bool;
+      let mut _21: i64;
+      let _22: ();
+      let mut _23: bool;
+      let mut _24: bool;
+      let mut _25: i64;
+      scope 1 {
+          debug b => _6;
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = _1;
+-         _4 = Neg(move _5);
++         _4 = Neg(_1);
+          StorageDead(_5);
+-         _3 = Neg(move _4);
++         _3 = _1;
+          StorageDead(_4);
+-         _2 = opaque::<i64>(move _3) -> [return: bb1, unwind unreachable];
++         _2 = opaque::<i64>(_1) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+          StorageDead(_2);
+-         StorageLive(_6);
++         nop;
+          StorageLive(_7);
+          _7 = _1;
+-         _6 = Lt(move _7, const 13_i64);
++         _6 = Lt(_1, const 13_i64);
+          StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          StorageLive(_10);
+          StorageLive(_11);
+          _11 = _6;
+-         _10 = Not(move _11);
++         _10 = Not(_6);
+          StorageDead(_11);
+-         _9 = Not(move _10);
++         _9 = _6;
+          StorageDead(_10);
+-         _8 = opaque::<bool>(move _9) -> [return: bb2, unwind unreachable];
++         _8 = opaque::<bool>(_6) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageLive(_12);
+-         StorageLive(_13);
++         nop;
+          StorageLive(_14);
+          _14 = _1;
+-         _13 = Ne(move _14, const 15_i64);
++         _13 = Ne(_1, const 15_i64);
+          StorageDead(_14);
+-         _12 = opaque::<bool>(move _13) -> [return: bb3, unwind unreachable];
++         _12 = opaque::<bool>(_13) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+-         StorageDead(_13);
++         nop;
+          StorageDead(_12);
+          StorageLive(_15);
+          StorageLive(_16);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = _1;
+-         _17 = Eq(move _18, const 15_i64);
++         _17 = Eq(_1, const 15_i64);
+          StorageDead(_18);
+-         _16 = Not(move _17);
++         _16 = _13;
+          StorageDead(_17);
+-         _15 = opaque::<bool>(move _16) -> [return: bb4, unwind unreachable];
++         _15 = opaque::<bool>(_13) -> [return: bb4, unwind unreachable];
+      }
+  
+      bb4: {
+          StorageDead(_16);
+          StorageDead(_15);
+          StorageLive(_19);
+-         StorageLive(_20);
++         nop;
+          StorageLive(_21);
+          _21 = _1;
+-         _20 = Eq(move _21, const 35_i64);
++         _20 = Eq(_1, const 35_i64);
+          StorageDead(_21);
+-         _19 = opaque::<bool>(move _20) -> [return: bb5, unwind unreachable];
++         _19 = opaque::<bool>(_20) -> [return: bb5, unwind unreachable];
+      }
+  
+      bb5: {
+-         StorageDead(_20);
++         nop;
+          StorageDead(_19);
+          StorageLive(_22);
+          StorageLive(_23);
+          StorageLive(_24);
+          StorageLive(_25);
+          _25 = _1;
+-         _24 = Ne(move _25, const 35_i64);
++         _24 = Ne(_1, const 35_i64);
+          StorageDead(_25);
+-         _23 = Not(move _24);
++         _23 = _20;
+          StorageDead(_24);
+-         _22 = opaque::<bool>(move _23) -> [return: bb6, unwind unreachable];
++         _22 = opaque::<bool>(_20) -> [return: bb6, unwind unreachable];
+      }
+  
+      bb6: {
+          StorageDead(_23);
+          StorageDead(_22);
+          _0 = const ();
+-         StorageDead(_6);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..e672f6fb6ba
--- /dev/null
+++ b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff
@@ -0,0 +1,153 @@
+- // MIR for `unary` before GVN
++ // MIR for `unary` after GVN
+  
+  fn unary(_1: i64) -> () {
+      debug x => _1;
+      let mut _0: ();
+      let _2: ();
+      let mut _3: i64;
+      let mut _4: i64;
+      let mut _5: i64;
+      let _6: bool;
+      let mut _7: i64;
+      let _8: ();
+      let mut _9: bool;
+      let mut _10: bool;
+      let mut _11: bool;
+      let _12: ();
+      let mut _13: bool;
+      let mut _14: i64;
+      let _15: ();
+      let mut _16: bool;
+      let mut _17: bool;
+      let mut _18: i64;
+      let _19: ();
+      let mut _20: bool;
+      let mut _21: i64;
+      let _22: ();
+      let mut _23: bool;
+      let mut _24: bool;
+      let mut _25: i64;
+      scope 1 {
+          debug b => _6;
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = _1;
+-         _4 = Neg(move _5);
++         _4 = Neg(_1);
+          StorageDead(_5);
+-         _3 = Neg(move _4);
++         _3 = _1;
+          StorageDead(_4);
+-         _2 = opaque::<i64>(move _3) -> [return: bb1, unwind continue];
++         _2 = opaque::<i64>(_1) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+          StorageDead(_2);
+-         StorageLive(_6);
++         nop;
+          StorageLive(_7);
+          _7 = _1;
+-         _6 = Lt(move _7, const 13_i64);
++         _6 = Lt(_1, const 13_i64);
+          StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          StorageLive(_10);
+          StorageLive(_11);
+          _11 = _6;
+-         _10 = Not(move _11);
++         _10 = Not(_6);
+          StorageDead(_11);
+-         _9 = Not(move _10);
++         _9 = _6;
+          StorageDead(_10);
+-         _8 = opaque::<bool>(move _9) -> [return: bb2, unwind continue];
++         _8 = opaque::<bool>(_6) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageLive(_12);
+-         StorageLive(_13);
++         nop;
+          StorageLive(_14);
+          _14 = _1;
+-         _13 = Ne(move _14, const 15_i64);
++         _13 = Ne(_1, const 15_i64);
+          StorageDead(_14);
+-         _12 = opaque::<bool>(move _13) -> [return: bb3, unwind continue];
++         _12 = opaque::<bool>(_13) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+-         StorageDead(_13);
++         nop;
+          StorageDead(_12);
+          StorageLive(_15);
+          StorageLive(_16);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = _1;
+-         _17 = Eq(move _18, const 15_i64);
++         _17 = Eq(_1, const 15_i64);
+          StorageDead(_18);
+-         _16 = Not(move _17);
++         _16 = _13;
+          StorageDead(_17);
+-         _15 = opaque::<bool>(move _16) -> [return: bb4, unwind continue];
++         _15 = opaque::<bool>(_13) -> [return: bb4, unwind continue];
+      }
+  
+      bb4: {
+          StorageDead(_16);
+          StorageDead(_15);
+          StorageLive(_19);
+-         StorageLive(_20);
++         nop;
+          StorageLive(_21);
+          _21 = _1;
+-         _20 = Eq(move _21, const 35_i64);
++         _20 = Eq(_1, const 35_i64);
+          StorageDead(_21);
+-         _19 = opaque::<bool>(move _20) -> [return: bb5, unwind continue];
++         _19 = opaque::<bool>(_20) -> [return: bb5, unwind continue];
+      }
+  
+      bb5: {
+-         StorageDead(_20);
++         nop;
+          StorageDead(_19);
+          StorageLive(_22);
+          StorageLive(_23);
+          StorageLive(_24);
+          StorageLive(_25);
+          _25 = _1;
+-         _24 = Ne(move _25, const 35_i64);
++         _24 = Ne(_1, const 35_i64);
+          StorageDead(_25);
+-         _23 = Not(move _24);
++         _23 = _20;
+          StorageDead(_24);
+-         _22 = opaque::<bool>(move _23) -> [return: bb6, unwind continue];
++         _22 = opaque::<bool>(_20) -> [return: bb6, unwind continue];
+      }
+  
+      bb6: {
+          StorageDead(_23);
+          StorageDead(_22);
+          _0 = const ();
+-         StorageDead(_6);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff
new file mode 100644
index 00000000000..e49d759b8fc
--- /dev/null
+++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff
@@ -0,0 +1,386 @@
+- // MIR for `wide_ptr_ops` before GVN
++ // MIR for `wide_ptr_ops` after GVN
+  
+  fn wide_ptr_ops() -> () {
+      let mut _0: ();
+      let _1: *const dyn std::marker::Send;
+      let mut _2: *const dyn std::marker::Send;
+      let _3: &dyn std::marker::Send;
+      let mut _4: &i32;
+      let _5: &i32;
+      let _6: i32;
+      let mut _8: *const dyn std::marker::Send;
+      let _9: &dyn std::marker::Send;
+      let mut _10: &i32;
+      let _11: &i32;
+      let _12: i32;
+      let mut _14: *const dyn std::marker::Send;
+      let mut _15: *const dyn std::marker::Send;
+      let mut _16: *const dyn std::marker::Send;
+      let mut _18: *const dyn std::marker::Send;
+      let mut _19: *const dyn std::marker::Send;
+      let mut _20: *const dyn std::marker::Send;
+      let mut _22: *const dyn std::marker::Send;
+      let mut _23: *const dyn std::marker::Send;
+      let mut _24: *const dyn std::marker::Send;
+      let mut _26: *const dyn std::marker::Send;
+      let mut _27: *const dyn std::marker::Send;
+      let mut _28: *const dyn std::marker::Send;
+      let mut _30: *const dyn std::marker::Send;
+      let mut _31: *const dyn std::marker::Send;
+      let mut _32: *const dyn std::marker::Send;
+      let mut _34: *const dyn std::marker::Send;
+      let mut _35: *const dyn std::marker::Send;
+      let mut _36: *const dyn std::marker::Send;
+      let mut _38: (usize, usize);
+      let mut _40: (usize, usize);
+      let _41: ();
+      let mut _42: bool;
+      let mut _43: bool;
+      let mut _44: *const [u8];
+      let mut _45: *const [u8];
+      let _46: ();
+      let mut _47: bool;
+      let mut _48: *const [u8];
+      let mut _49: *const [u8];
+      let _50: ();
+      let mut _51: bool;
+      let mut _52: *const [u8];
+      let mut _53: *const [u8];
+      let _54: ();
+      let mut _55: bool;
+      let mut _56: *const [u8];
+      let mut _57: *const [u8];
+      let _58: ();
+      let mut _59: bool;
+      let mut _60: bool;
+      let mut _61: *const [u8];
+      let mut _62: *const [u8];
+      let _63: ();
+      let mut _64: bool;
+      let mut _65: bool;
+      let mut _66: *const [u8];
+      let mut _67: *const [u8];
+      let mut _69: &i32;
+      scope 1 {
+          debug a => _1;
+          let _7: *const dyn std::marker::Send;
+          let mut _68: &i32;
+          scope 2 {
+              debug b => _7;
+              let _13: bool;
+              scope 3 {
+                  debug _val => _13;
+                  let _17: bool;
+                  scope 4 {
+                      debug _val => _17;
+                      let _21: bool;
+                      scope 5 {
+                          debug _val => _21;
+                          let _25: bool;
+                          scope 6 {
+                              debug _val => _25;
+                              let _29: bool;
+                              scope 7 {
+                                  debug _val => _29;
+                                  let _33: bool;
+                                  scope 8 {
+                                      debug _val => _33;
+                                      let _37: *const [u8];
+                                      scope 9 {
+                                          debug a => _37;
+                                          let _39: *const [u8];
+                                          scope 11 {
+                                              debug b => _39;
+                                          }
+                                          scope 12 {
+                                          }
+                                      }
+                                      scope 10 {
+                                      }
+                                  }
+                              }
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_1);
++         nop;
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _69 = const _;
+          _5 = &(*_69);
+          _4 = &(*_5);
+          _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_4);
+          _2 = &raw const (*_3);
+          _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_2);
+          StorageDead(_5);
+          StorageDead(_3);
+-         StorageLive(_7);
++         nop;
+          StorageLive(_8);
+          StorageLive(_9);
+          StorageLive(_10);
+          StorageLive(_11);
+          _68 = const _;
+          _11 = &(*_68);
+          _10 = &(*_11);
+          _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_10);
+          _8 = &raw const (*_9);
+          _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_8);
+          StorageDead(_11);
+          StorageDead(_9);
+          StorageLive(_13);
+          StorageLive(_14);
+          _14 = _1;
+-         StorageLive(_15);
++         nop;
+          StorageLive(_16);
+          _16 = _7;
+-         _15 = move _16 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _15 = _7 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_16);
+-         _13 = Eq(move _14, move _15);
+-         StorageDead(_15);
++         _13 = Eq(_1, _15);
++         nop;
+          StorageDead(_14);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = _1;
+          StorageLive(_19);
+          StorageLive(_20);
+          _20 = _7;
+-         _19 = move _20 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _19 = _15;
+          StorageDead(_20);
+-         _17 = Ne(move _18, move _19);
++         _17 = Ne(_1, _15);
+          StorageDead(_19);
+          StorageDead(_18);
+          StorageLive(_21);
+          StorageLive(_22);
+          _22 = _1;
+          StorageLive(_23);
+          StorageLive(_24);
+          _24 = _7;
+-         _23 = move _24 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _23 = _15;
+          StorageDead(_24);
+-         _21 = Lt(move _22, move _23);
++         _21 = Lt(_1, _15);
+          StorageDead(_23);
+          StorageDead(_22);
+          StorageLive(_25);
+          StorageLive(_26);
+          _26 = _1;
+          StorageLive(_27);
+          StorageLive(_28);
+          _28 = _7;
+-         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _27 = _15;
+          StorageDead(_28);
+-         _25 = Le(move _26, move _27);
++         _25 = Le(_1, _15);
+          StorageDead(_27);
+          StorageDead(_26);
+          StorageLive(_29);
+          StorageLive(_30);
+          _30 = _1;
+          StorageLive(_31);
+          StorageLive(_32);
+          _32 = _7;
+-         _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _31 = _15;
+          StorageDead(_32);
+-         _29 = Gt(move _30, move _31);
++         _29 = Gt(_1, _15);
+          StorageDead(_31);
+          StorageDead(_30);
+          StorageLive(_33);
+          StorageLive(_34);
+          _34 = _1;
+          StorageLive(_35);
+          StorageLive(_36);
+          _36 = _7;
+-         _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _35 = _15;
+          StorageDead(_36);
+-         _33 = Ge(move _34, move _35);
++         _33 = Ge(_1, _15);
+          StorageDead(_35);
+          StorageDead(_34);
+-         StorageLive(_37);
++         nop;
+          StorageLive(_38);
+-         _38 = (const 1_usize, const 1_usize);
+-         _37 = move _38 as *const [u8] (Transmute);
++         _38 = const (1_usize, 1_usize);
++         _37 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageDead(_38);
+-         StorageLive(_39);
++         nop;
+          StorageLive(_40);
+-         _40 = (const 1_usize, const 2_usize);
+-         _39 = move _40 as *const [u8] (Transmute);
++         _40 = const (1_usize, 2_usize);
++         _39 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
+          StorageDead(_40);
+          StorageLive(_41);
+-         StorageLive(_42);
++         nop;
+          StorageLive(_43);
+          StorageLive(_44);
+-         _44 = _37;
++         _44 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_45);
+-         _45 = _39;
+-         _43 = Eq(move _44, move _45);
++         _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_45);
+          StorageDead(_44);
+          _42 = Not(move _43);
+          StorageDead(_43);
+-         _41 = opaque::<bool>(move _42) -> [return: bb1, unwind unreachable];
++         _41 = opaque::<bool>(_42) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         StorageDead(_42);
++         nop;
+          StorageDead(_41);
+          StorageLive(_46);
+          StorageLive(_47);
+          StorageLive(_48);
+-         _48 = _37;
++         _48 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_49);
+-         _49 = _39;
+-         _47 = Ne(move _48, move _49);
++         _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _47 = _42;
+          StorageDead(_49);
+          StorageDead(_48);
+-         _46 = opaque::<bool>(move _47) -> [return: bb2, unwind unreachable];
++         _46 = opaque::<bool>(_42) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_47);
+          StorageDead(_46);
+          StorageLive(_50);
+          StorageLive(_51);
+          StorageLive(_52);
+-         _52 = _37;
++         _52 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_53);
+-         _53 = _39;
+-         _51 = Le(move _52, move _53);
++         _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_53);
+          StorageDead(_52);
+          _50 = opaque::<bool>(move _51) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          StorageDead(_51);
+          StorageDead(_50);
+          StorageLive(_54);
+          StorageLive(_55);
+          StorageLive(_56);
+-         _56 = _37;
++         _56 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_57);
+-         _57 = _39;
+-         _55 = Lt(move _56, move _57);
++         _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_57);
+          StorageDead(_56);
+          _54 = opaque::<bool>(move _55) -> [return: bb4, unwind unreachable];
+      }
+  
+      bb4: {
+          StorageDead(_55);
+          StorageDead(_54);
+          StorageLive(_58);
+          StorageLive(_59);
+          StorageLive(_60);
+          StorageLive(_61);
+-         _61 = _37;
++         _61 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_62);
+-         _62 = _39;
+-         _60 = Ge(move _61, move _62);
++         _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_62);
+          StorageDead(_61);
+          _59 = Not(move _60);
+          StorageDead(_60);
+          _58 = opaque::<bool>(move _59) -> [return: bb5, unwind unreachable];
+      }
+  
+      bb5: {
+          StorageDead(_59);
+          StorageDead(_58);
+          StorageLive(_63);
+          StorageLive(_64);
+          StorageLive(_65);
+          StorageLive(_66);
+-         _66 = _37;
++         _66 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_67);
+-         _67 = _39;
+-         _65 = Gt(move _66, move _67);
++         _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_67);
+          StorageDead(_66);
+          _64 = Not(move _65);
+          StorageDead(_65);
+          _63 = opaque::<bool>(move _64) -> [return: bb6, unwind unreachable];
+      }
+  
+      bb6: {
+          StorageDead(_64);
+          StorageDead(_63);
+          _0 = const ();
+-         StorageDead(_39);
+-         StorageDead(_37);
++         nop;
++         nop;
+          StorageDead(_33);
+          StorageDead(_29);
+          StorageDead(_25);
+          StorageDead(_21);
+          StorageDead(_17);
+          StorageDead(_13);
+-         StorageDead(_7);
+-         StorageDead(_1);
++         nop;
++         nop;
+          return;
+      }
++ }
++ 
++ ALLOC1 (size: 16, align: 8) {
++     01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................
++ }
++ 
++ ALLOC0 (size: 16, align: 8) {
++     01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
+  }
+  
diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..4e5608a4425
--- /dev/null
+++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff
@@ -0,0 +1,386 @@
+- // MIR for `wide_ptr_ops` before GVN
++ // MIR for `wide_ptr_ops` after GVN
+  
+  fn wide_ptr_ops() -> () {
+      let mut _0: ();
+      let _1: *const dyn std::marker::Send;
+      let mut _2: *const dyn std::marker::Send;
+      let _3: &dyn std::marker::Send;
+      let mut _4: &i32;
+      let _5: &i32;
+      let _6: i32;
+      let mut _8: *const dyn std::marker::Send;
+      let _9: &dyn std::marker::Send;
+      let mut _10: &i32;
+      let _11: &i32;
+      let _12: i32;
+      let mut _14: *const dyn std::marker::Send;
+      let mut _15: *const dyn std::marker::Send;
+      let mut _16: *const dyn std::marker::Send;
+      let mut _18: *const dyn std::marker::Send;
+      let mut _19: *const dyn std::marker::Send;
+      let mut _20: *const dyn std::marker::Send;
+      let mut _22: *const dyn std::marker::Send;
+      let mut _23: *const dyn std::marker::Send;
+      let mut _24: *const dyn std::marker::Send;
+      let mut _26: *const dyn std::marker::Send;
+      let mut _27: *const dyn std::marker::Send;
+      let mut _28: *const dyn std::marker::Send;
+      let mut _30: *const dyn std::marker::Send;
+      let mut _31: *const dyn std::marker::Send;
+      let mut _32: *const dyn std::marker::Send;
+      let mut _34: *const dyn std::marker::Send;
+      let mut _35: *const dyn std::marker::Send;
+      let mut _36: *const dyn std::marker::Send;
+      let mut _38: (usize, usize);
+      let mut _40: (usize, usize);
+      let _41: ();
+      let mut _42: bool;
+      let mut _43: bool;
+      let mut _44: *const [u8];
+      let mut _45: *const [u8];
+      let _46: ();
+      let mut _47: bool;
+      let mut _48: *const [u8];
+      let mut _49: *const [u8];
+      let _50: ();
+      let mut _51: bool;
+      let mut _52: *const [u8];
+      let mut _53: *const [u8];
+      let _54: ();
+      let mut _55: bool;
+      let mut _56: *const [u8];
+      let mut _57: *const [u8];
+      let _58: ();
+      let mut _59: bool;
+      let mut _60: bool;
+      let mut _61: *const [u8];
+      let mut _62: *const [u8];
+      let _63: ();
+      let mut _64: bool;
+      let mut _65: bool;
+      let mut _66: *const [u8];
+      let mut _67: *const [u8];
+      let mut _69: &i32;
+      scope 1 {
+          debug a => _1;
+          let _7: *const dyn std::marker::Send;
+          let mut _68: &i32;
+          scope 2 {
+              debug b => _7;
+              let _13: bool;
+              scope 3 {
+                  debug _val => _13;
+                  let _17: bool;
+                  scope 4 {
+                      debug _val => _17;
+                      let _21: bool;
+                      scope 5 {
+                          debug _val => _21;
+                          let _25: bool;
+                          scope 6 {
+                              debug _val => _25;
+                              let _29: bool;
+                              scope 7 {
+                                  debug _val => _29;
+                                  let _33: bool;
+                                  scope 8 {
+                                      debug _val => _33;
+                                      let _37: *const [u8];
+                                      scope 9 {
+                                          debug a => _37;
+                                          let _39: *const [u8];
+                                          scope 11 {
+                                              debug b => _39;
+                                          }
+                                          scope 12 {
+                                          }
+                                      }
+                                      scope 10 {
+                                      }
+                                  }
+                              }
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_1);
++         nop;
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _69 = const _;
+          _5 = &(*_69);
+          _4 = &(*_5);
+          _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_4);
+          _2 = &raw const (*_3);
+          _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_2);
+          StorageDead(_5);
+          StorageDead(_3);
+-         StorageLive(_7);
++         nop;
+          StorageLive(_8);
+          StorageLive(_9);
+          StorageLive(_10);
+          StorageLive(_11);
+          _68 = const _;
+          _11 = &(*_68);
+          _10 = &(*_11);
+          _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_10);
+          _8 = &raw const (*_9);
+          _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_8);
+          StorageDead(_11);
+          StorageDead(_9);
+          StorageLive(_13);
+          StorageLive(_14);
+          _14 = _1;
+-         StorageLive(_15);
++         nop;
+          StorageLive(_16);
+          _16 = _7;
+-         _15 = move _16 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _15 = _7 as *const dyn std::marker::Send (PointerCoercion(Unsize));
+          StorageDead(_16);
+-         _13 = Eq(move _14, move _15);
+-         StorageDead(_15);
++         _13 = Eq(_1, _15);
++         nop;
+          StorageDead(_14);
+          StorageLive(_17);
+          StorageLive(_18);
+          _18 = _1;
+          StorageLive(_19);
+          StorageLive(_20);
+          _20 = _7;
+-         _19 = move _20 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _19 = _15;
+          StorageDead(_20);
+-         _17 = Ne(move _18, move _19);
++         _17 = Ne(_1, _15);
+          StorageDead(_19);
+          StorageDead(_18);
+          StorageLive(_21);
+          StorageLive(_22);
+          _22 = _1;
+          StorageLive(_23);
+          StorageLive(_24);
+          _24 = _7;
+-         _23 = move _24 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _23 = _15;
+          StorageDead(_24);
+-         _21 = Lt(move _22, move _23);
++         _21 = Lt(_1, _15);
+          StorageDead(_23);
+          StorageDead(_22);
+          StorageLive(_25);
+          StorageLive(_26);
+          _26 = _1;
+          StorageLive(_27);
+          StorageLive(_28);
+          _28 = _7;
+-         _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _27 = _15;
+          StorageDead(_28);
+-         _25 = Le(move _26, move _27);
++         _25 = Le(_1, _15);
+          StorageDead(_27);
+          StorageDead(_26);
+          StorageLive(_29);
+          StorageLive(_30);
+          _30 = _1;
+          StorageLive(_31);
+          StorageLive(_32);
+          _32 = _7;
+-         _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _31 = _15;
+          StorageDead(_32);
+-         _29 = Gt(move _30, move _31);
++         _29 = Gt(_1, _15);
+          StorageDead(_31);
+          StorageDead(_30);
+          StorageLive(_33);
+          StorageLive(_34);
+          _34 = _1;
+          StorageLive(_35);
+          StorageLive(_36);
+          _36 = _7;
+-         _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize));
++         _35 = _15;
+          StorageDead(_36);
+-         _33 = Ge(move _34, move _35);
++         _33 = Ge(_1, _15);
+          StorageDead(_35);
+          StorageDead(_34);
+-         StorageLive(_37);
++         nop;
+          StorageLive(_38);
+-         _38 = (const 1_usize, const 1_usize);
+-         _37 = move _38 as *const [u8] (Transmute);
++         _38 = const (1_usize, 1_usize);
++         _37 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageDead(_38);
+-         StorageLive(_39);
++         nop;
+          StorageLive(_40);
+-         _40 = (const 1_usize, const 2_usize);
+-         _39 = move _40 as *const [u8] (Transmute);
++         _40 = const (1_usize, 2_usize);
++         _39 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
+          StorageDead(_40);
+          StorageLive(_41);
+-         StorageLive(_42);
++         nop;
+          StorageLive(_43);
+          StorageLive(_44);
+-         _44 = _37;
++         _44 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_45);
+-         _45 = _39;
+-         _43 = Eq(move _44, move _45);
++         _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_45);
+          StorageDead(_44);
+          _42 = Not(move _43);
+          StorageDead(_43);
+-         _41 = opaque::<bool>(move _42) -> [return: bb1, unwind continue];
++         _41 = opaque::<bool>(_42) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         StorageDead(_42);
++         nop;
+          StorageDead(_41);
+          StorageLive(_46);
+          StorageLive(_47);
+          StorageLive(_48);
+-         _48 = _37;
++         _48 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_49);
+-         _49 = _39;
+-         _47 = Ne(move _48, move _49);
++         _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _47 = _42;
+          StorageDead(_49);
+          StorageDead(_48);
+-         _46 = opaque::<bool>(move _47) -> [return: bb2, unwind continue];
++         _46 = opaque::<bool>(_42) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_47);
+          StorageDead(_46);
+          StorageLive(_50);
+          StorageLive(_51);
+          StorageLive(_52);
+-         _52 = _37;
++         _52 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_53);
+-         _53 = _39;
+-         _51 = Le(move _52, move _53);
++         _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_53);
+          StorageDead(_52);
+          _50 = opaque::<bool>(move _51) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+          StorageDead(_51);
+          StorageDead(_50);
+          StorageLive(_54);
+          StorageLive(_55);
+          StorageLive(_56);
+-         _56 = _37;
++         _56 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_57);
+-         _57 = _39;
+-         _55 = Lt(move _56, move _57);
++         _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_57);
+          StorageDead(_56);
+          _54 = opaque::<bool>(move _55) -> [return: bb4, unwind continue];
+      }
+  
+      bb4: {
+          StorageDead(_55);
+          StorageDead(_54);
+          StorageLive(_58);
+          StorageLive(_59);
+          StorageLive(_60);
+          StorageLive(_61);
+-         _61 = _37;
++         _61 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_62);
+-         _62 = _39;
+-         _60 = Ge(move _61, move _62);
++         _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_62);
+          StorageDead(_61);
+          _59 = Not(move _60);
+          StorageDead(_60);
+          _58 = opaque::<bool>(move _59) -> [return: bb5, unwind continue];
+      }
+  
+      bb5: {
+          StorageDead(_59);
+          StorageDead(_58);
+          StorageLive(_63);
+          StorageLive(_64);
+          StorageLive(_65);
+          StorageLive(_66);
+-         _66 = _37;
++         _66 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8];
+          StorageLive(_67);
+-         _67 = _39;
+-         _65 = Gt(move _66, move _67);
++         _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
++         _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
+          StorageDead(_67);
+          StorageDead(_66);
+          _64 = Not(move _65);
+          StorageDead(_65);
+          _63 = opaque::<bool>(move _64) -> [return: bb6, unwind continue];
+      }
+  
+      bb6: {
+          StorageDead(_64);
+          StorageDead(_63);
+          _0 = const ();
+-         StorageDead(_39);
+-         StorageDead(_37);
++         nop;
++         nop;
+          StorageDead(_33);
+          StorageDead(_29);
+          StorageDead(_25);
+          StorageDead(_21);
+          StorageDead(_17);
+          StorageDead(_13);
+-         StorageDead(_7);
+-         StorageDead(_1);
++         nop;
++         nop;
+          return;
+      }
++ }
++ 
++ ALLOC1 (size: 16, align: 8) {
++     01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................
++ }
++ 
++ ALLOC0 (size: 16, align: 8) {
++     01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
+  }
+  
diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
index b04728a9b0f..187290785c0 100644
--- a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
+++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
@@ -19,7 +19,6 @@
       scope 1 (inlined imm8) {
           debug x => _5;
           let mut _14: u32;
-          let mut _15: u32;
           scope 2 {
               debug out => _4;
           }
@@ -36,14 +35,14 @@
           StorageLive(_5);
           _5 = _1;
           _4 = const 0_u32;
-          StorageLive(_15);
-          StorageLive(_14);
--         _14 = Shr(_5, const 0_i32);
-+         _14 = Shr(_1, const 0_i32);
-          _15 = BitAnd(move _14, const 255_u32);
-          StorageDead(_14);
-          _4 = BitOr(const 0_u32, move _15);
-          StorageDead(_15);
+-         StorageLive(_14);
+-         _14 = BitAnd(_5, const 255_u32);
+-         _4 = BitOr(const 0_u32, move _14);
+-         StorageDead(_14);
++         nop;
++         _14 = BitAnd(_1, const 255_u32);
++         _4 = _14;
++         nop;
           StorageDead(_5);
           StorageLive(_6);
           StorageLive(_7);
diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
index fcf99ac6918..99350bac478 100644
--- a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
+++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
@@ -19,7 +19,6 @@
       scope 1 (inlined imm8) {
           debug x => _5;
           let mut _14: u32;
-          let mut _15: u32;
           scope 2 {
               debug out => _4;
           }
@@ -36,14 +35,14 @@
           StorageLive(_5);
           _5 = _1;
           _4 = const 0_u32;
-          StorageLive(_15);
-          StorageLive(_14);
--         _14 = Shr(_5, const 0_i32);
-+         _14 = Shr(_1, const 0_i32);
-          _15 = BitAnd(move _14, const 255_u32);
-          StorageDead(_14);
-          _4 = BitOr(const 0_u32, move _15);
-          StorageDead(_15);
+-         StorageLive(_14);
+-         _14 = BitAnd(_5, const 255_u32);
+-         _4 = BitOr(const 0_u32, move _14);
+-         StorageDead(_14);
++         nop;
++         _14 = BitAnd(_1, const 255_u32);
++         _4 = _14;
++         nop;
           StorageDead(_5);
           StorageLive(_6);
           StorageLive(_7);
diff --git a/tests/rustdoc-ui/error-in-impl-trait/README.md b/tests/rustdoc-ui/error-in-impl-trait/README.md
index d969ab10ef5..0b42ff1771e 100644
--- a/tests/rustdoc-ui/error-in-impl-trait/README.md
+++ b/tests/rustdoc-ui/error-in-impl-trait/README.md
@@ -1,5 +1,5 @@
 Each of these needs to be in a separate file,
-because the `span_delayed_bug` ICE in rustdoc won't be triggerred
+because the `span_delayed_bug` ICE in rustdoc won't be triggered
 if even a single other error was emitted.
 
 However, conceptually they are all testing basically the same thing.
diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs
index 30b42bc3bfa..7d7469597af 100644
--- a/tests/ui-fulldeps/stable-mir/check_abi.rs
+++ b/tests/ui-fulldeps/stable-mir/check_abi.rs
@@ -12,14 +12,12 @@
 #![feature(ascii_char, ascii_char_variants)]
 
 extern crate rustc_hir;
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
 extern crate rustc_interface;
 extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
 use stable_mir::mir::mono::Instance;
@@ -32,7 +30,7 @@ use std::ops::ControlFlow;
 const CRATE_NAME: &str = "input";
 
 /// This function uses the Stable MIR APIs to get information about the test crate.
-fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_stable_mir() -> ControlFlow<()> {
     // Find items in the local crate.
     let items = stable_mir::all_local_items();
 
@@ -117,7 +115,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+    run!(args, test_stable_mir).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs
index 93def93127c..fb5e13eb13b 100644
--- a/tests/ui-fulldeps/stable-mir/check_allocation.rs
+++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs
@@ -14,14 +14,12 @@
 #![feature(ascii_char, ascii_char_variants)]
 
 extern crate rustc_hir;
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
 extern crate rustc_interface;
 extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::crate_def::CrateDef;
 use stable_mir::mir::alloc::GlobalAlloc;
@@ -40,7 +38,7 @@ use std::ops::ControlFlow;
 const CRATE_NAME: &str = "input";
 
 /// This function uses the Stable MIR APIs to get information about the test crate.
-fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_stable_mir() -> ControlFlow<()> {
     // Find items in the local crate.
     let items = stable_mir::all_local_items();
     check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap());
@@ -230,7 +228,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+    run!(args, test_stable_mir).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs
index e9a2599d873..4a124adb2b6 100644
--- a/tests/ui-fulldeps/stable-mir/check_defs.rs
+++ b/tests/ui-fulldeps/stable-mir/check_defs.rs
@@ -11,7 +11,6 @@
 #![feature(assert_matches)]
 #![feature(control_flow_enum)]
 
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
@@ -20,7 +19,6 @@ extern crate stable_mir;
 
 use std::assert_matches::assert_matches;
 use mir::{mono::Instance, TerminatorKind::*};
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy};
 use stable_mir::*;
@@ -30,7 +28,7 @@ use std::ops::ControlFlow;
 const CRATE_NAME: &str = "input";
 
 /// This function uses the Stable MIR APIs to get information about the test crate.
-fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_stable_mir() -> ControlFlow<()> {
     let entry = stable_mir::entry_fn().unwrap();
     let main_fn = Instance::try_from(entry).unwrap();
     assert_eq!(main_fn.name(), "main");
@@ -113,7 +111,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+    run!(args, test_stable_mir).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs
index 5cb07eabf41..1e039e5ae51 100644
--- a/tests/ui-fulldeps/stable-mir/check_instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -11,7 +11,6 @@
 #![feature(assert_matches)]
 #![feature(control_flow_enum)]
 
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
@@ -19,7 +18,6 @@ extern crate rustc_interface;
 extern crate stable_mir;
 
 use mir::{mono::Instance, TerminatorKind::*};
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::ty::{RigidTy, TyKind};
 use stable_mir::*;
@@ -29,7 +27,7 @@ use std::ops::ControlFlow;
 const CRATE_NAME: &str = "input";
 
 /// This function uses the Stable MIR APIs to get information about the test crate.
-fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_stable_mir() -> ControlFlow<()> {
     let items = stable_mir::all_local_items();
 
     // Get all items and split generic vs monomorphic items.
@@ -96,7 +94,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+    run!(args, test_stable_mir).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs
index 72e0e09e6e3..0a7f00029f2 100644
--- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs
+++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs
@@ -11,14 +11,12 @@
 #![feature(assert_matches)]
 #![feature(control_flow_enum)]
 
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
 extern crate rustc_interface;
 extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::*;
 use std::io::Write;
@@ -27,7 +25,7 @@ use std::ops::ControlFlow;
 const CRATE_NAME: &str = "input";
 
 /// This function uses the Stable MIR APIs to get information about the test crate.
-fn test_item_kind(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_item_kind() -> ControlFlow<()> {
     let items = stable_mir::all_local_items();
     assert_eq!(items.len(), 4);
     // Constructor item.
@@ -59,7 +57,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_item_kind(tcx)).unwrap();
+    run!(args, test_item_kind).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
index fb1197e4ecc..c9fbe15ffb0 100644
--- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
+++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
@@ -11,14 +11,12 @@
 #![feature(assert_matches)]
 #![feature(control_flow_enum)]
 
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
 extern crate rustc_interface;
 extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::CrateDef;
 use std::collections::HashSet;
@@ -83,7 +81,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, test_traits()).unwrap();
+    run!(args, test_traits).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
index b90d47d4540..14cbf9e9f81 100644
--- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
+++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
@@ -12,14 +12,12 @@
 #![feature(assert_matches)]
 #![feature(control_flow_enum)]
 
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
 extern crate rustc_interface;
 extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::ty::{RigidTy, TyKind, Ty, };
 use stable_mir::mir::{Body, MirVisitor, FieldIdx, Place, ProjectionElem, visit::{Location,
@@ -30,7 +28,7 @@ use std::ops::ControlFlow;
 const CRATE_NAME: &str = "input";
 
 /// This function uses the Stable MIR APIs to get information about the test crate.
-fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_stable_mir() -> ControlFlow<()> {
     let main_fn = stable_mir::entry_fn();
     let body = main_fn.unwrap().body();
     let mut visitor = PlaceVisitor{ body: &body, tested: false};
@@ -87,7 +85,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+    run!(args, test_stable_mir).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs
index fc56e24814b..e6dd9fa132d 100644
--- a/tests/ui-fulldeps/stable-mir/compilation-result.rs
+++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs
@@ -10,14 +10,12 @@
 #![feature(rustc_private)]
 #![feature(assert_matches)]
 
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
 extern crate rustc_interface;
 extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use std::io::Write;
 
@@ -32,33 +30,41 @@ fn main() {
     test_continue(args.clone());
     test_break(args.clone());
     test_failed(args.clone());
-    test_skipped(args);
+    test_skipped(args.clone());
+    test_captured(args)
 }
 
 fn test_continue(args: Vec<String>) {
-    let result = run!(args, ControlFlow::Continue::<(), bool>(true));
+    let result = run!(args, || ControlFlow::Continue::<(), bool>(true));
     assert_eq!(result, Ok(true));
 }
 
 fn test_break(args: Vec<String>) {
-    let result = run!(args, ControlFlow::Break::<bool, i32>(false));
+    let result = run!(args, || ControlFlow::Break::<bool, i32>(false));
     assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false)));
 }
 
 #[allow(unreachable_code)]
 fn test_skipped(mut args: Vec<String>) {
     args.push("--version".to_string());
-    let result = run!(args, unreachable!() as ControlFlow<()>);
+    let result = run!(args, || unreachable!() as ControlFlow<()>);
     assert_eq!(result, Err(stable_mir::CompilerError::Skipped));
 }
 
 #[allow(unreachable_code)]
 fn test_failed(mut args: Vec<String>) {
     args.push("--cfg=broken".to_string());
-    let result = run!(args, unreachable!() as ControlFlow<()>);
+    let result = run!(args, || unreachable!() as ControlFlow<()>);
     assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed));
 }
 
+/// Test that we are able to pass a closure and set the return according to the captured value.
+fn test_captured(args: Vec<String>) {
+    let captured = "10".to_string();
+    let result = run!(args, || ControlFlow::Continue::<(), usize>(captured.len()));
+    assert_eq!(result, Ok(captured.len()));
+}
+
 fn generate_input(path: &str) -> std::io::Result<()> {
     let mut file = std::fs::File::create(path)?;
     write!(
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index c2035430a33..8258883436f 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -12,7 +12,6 @@
 #![feature(control_flow_enum)]
 
 extern crate rustc_hir;
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
@@ -20,7 +19,6 @@ extern crate rustc_interface;
 extern crate stable_mir;
 
 use rustc_hir::def::DefKind;
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::ItemKind;
 use stable_mir::crate_def::CrateDef;
@@ -33,7 +31,7 @@ use std::ops::ControlFlow;
 const CRATE_NAME: &str = "input";
 
 /// This function uses the Stable MIR APIs to get information about the test crate.
-fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_stable_mir() -> ControlFlow<()> {
     // Get the local crate using stable_mir API.
     let local = stable_mir::local_crate();
     assert_eq!(&local.name, CRATE_NAME);
@@ -194,7 +192,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+    run!(args, test_stable_mir).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs
index 8c3fda7b6bb..40f2d901a2b 100644
--- a/tests/ui-fulldeps/stable-mir/projections.rs
+++ b/tests/ui-fulldeps/stable-mir/projections.rs
@@ -12,14 +12,12 @@
 #![feature(control_flow_enum)]
 
 extern crate rustc_hir;
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
 extern crate rustc_interface;
 extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::crate_def::CrateDef;
 use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
@@ -32,7 +30,7 @@ use std::ops::ControlFlow;
 const CRATE_NAME: &str = "input";
 
 /// Tests projections within Place objects
-fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_place_projections() -> ControlFlow<()> {
     let items = stable_mir::all_local_items();
     let body = get_item(&items, (ItemKind::Fn, "projections")).unwrap().body();
     assert_eq!(body.blocks.len(), 4);
@@ -159,7 +157,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_place_projections(tcx)).unwrap();
+    run!(args, test_place_projections).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs
index b0596b18823..b4faaeb4fc0 100644
--- a/tests/ui-fulldeps/stable-mir/smir_internal.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs
@@ -26,7 +26,7 @@ use std::ops::ControlFlow;
 
 const CRATE_NAME: &str = "input";
 
-fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_translation(_tcx: TyCtxt) -> ControlFlow<()> {
     let main_fn = stable_mir::entry_fn().unwrap();
     let body = main_fn.body();
     let orig_ty = body.locals()[0].ty;
@@ -48,7 +48,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_translation(tcx)).unwrap();
+    run_with_tcx!(args, test_translation).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
index 027b0e7d9e8..d7739770b70 100644
--- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
@@ -11,7 +11,6 @@
 #![feature(assert_matches)]
 #![feature(control_flow_enum)]
 
-extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
 extern crate rustc_driver;
@@ -19,7 +18,6 @@ extern crate rustc_interface;
 extern crate stable_mir;
 
 use std::collections::HashSet;
-use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::*;
 use stable_mir::mir::MirVisitor;
@@ -28,7 +26,7 @@ use std::ops::ControlFlow;
 
 const CRATE_NAME: &str = "input";
 
-fn test_visitor(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+fn test_visitor() -> ControlFlow<()> {
     let main_fn = stable_mir::entry_fn();
     let main_body = main_fn.unwrap().body();
     let main_visitor = TestVisitor::collect(&main_body);
@@ -116,7 +114,7 @@ fn main() {
         CRATE_NAME.to_string(),
         path.to_string(),
     ];
-    run!(args, tcx, test_visitor(tcx)).unwrap();
+    run!(args, test_visitor).unwrap();
 }
 
 fn generate_input(path: &str) -> std::io::Result<()> {
diff --git a/tests/ui/associated-inherent-types/issue-111404-1.rs b/tests/ui/associated-inherent-types/issue-111404-1.rs
index dd62e59f07d..74f9434b881 100644
--- a/tests/ui/associated-inherent-types/issue-111404-1.rs
+++ b/tests/ui/associated-inherent-types/issue-111404-1.rs
@@ -10,5 +10,6 @@ impl<'a> Foo<fn(&'a ())> {
 fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
 //~^ ERROR higher-ranked subtype error
 //~| ERROR higher-ranked subtype error
+//~| ERROR higher-ranked subtype error
 
 fn main() {}
diff --git a/tests/ui/associated-inherent-types/issue-111404-1.stderr b/tests/ui/associated-inherent-types/issue-111404-1.stderr
index cf4d4a5f19b..1613161a873 100644
--- a/tests/ui/associated-inherent-types/issue-111404-1.stderr
+++ b/tests/ui/associated-inherent-types/issue-111404-1.stderr
@@ -12,5 +12,13 @@ LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 2 previous errors
+error: higher-ranked subtype error
+  --> $DIR/issue-111404-1.rs:10:1
+   |
+LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
index e667b72aee5..f8ff9186842 100644
--- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
+++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
@@ -1,9 +1,10 @@
 // edition:2018
+// check-pass
+
 #![feature(async_closure)]
 fn foo() -> Box<dyn std::future::Future<Output = u32>> {
     let x = 0u32;
     Box::new((async || x)())
-    //~^ ERROR E0373
 }
 
 fn main() {
diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
deleted file mode 100644
index 1d8d1c67bae..00000000000
--- a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
-  --> $DIR/async-borrowck-escaping-closure-error.rs:5:15
-   |
-LL |     Box::new((async || x)())
-   |               ^^^^^^^^ - `x` is borrowed here
-   |               |
-   |               may outlive borrowed value `x`
-   |
-note: closure is returned here
-  --> $DIR/async-borrowck-escaping-closure-error.rs:5:5
-   |
-LL |     Box::new((async || x)())
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
-   |
-LL |     Box::new((async move || x)())
-   |                     ++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0373`.
diff --git a/tests/ui/async-await/inference_var_self_argument.rs b/tests/ui/async-await/inference_var_self_argument.rs
new file mode 100644
index 00000000000..fd8482f86b4
--- /dev/null
+++ b/tests/ui/async-await/inference_var_self_argument.rs
@@ -0,0 +1,12 @@
+//! This is a regression test for an ICE.
+// edition: 2021
+
+trait Foo {
+    async fn foo(self: &dyn Foo) {
+        //~^ ERROR: `Foo` cannot be made into an object
+        //~| ERROR invalid `self` parameter type: &dyn Foo
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr
new file mode 100644
index 00000000000..8a8c1ea03f1
--- /dev/null
+++ b/tests/ui/async-await/inference_var_self_argument.stderr
@@ -0,0 +1,28 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/inference_var_self_argument.rs:5:5
+   |
+LL |     async fn foo(self: &dyn Foo) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/inference_var_self_argument.rs:5:14
+   |
+LL | trait Foo {
+   |       --- this trait cannot be made into an object...
+LL |     async fn foo(self: &dyn Foo) {
+   |              ^^^ ...because method `foo` is `async`
+   = help: consider moving `foo` to another trait
+
+error[E0307]: invalid `self` parameter type: &dyn Foo
+  --> $DIR/inference_var_self_argument.rs:5:24
+   |
+LL |     async fn foo(self: &dyn Foo) {
+   |                        ^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0038, E0307.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/async-await/no-params-non-move-async-closure.rs b/tests/ui/async-await/no-params-non-move-async-closure.rs
index 3b15f35c260..1440d918c50 100644
--- a/tests/ui/async-await/no-params-non-move-async-closure.rs
+++ b/tests/ui/async-await/no-params-non-move-async-closure.rs
@@ -1,8 +1,8 @@
 // edition:2018
+// check-pass
 
 #![feature(async_closure)]
 
 fn main() {
     let _ = async |x: u8| {};
-    //~^ ERROR `async` non-`move` closures with parameters are not currently supported
 }
diff --git a/tests/ui/async-await/no-params-non-move-async-closure.stderr b/tests/ui/async-await/no-params-non-move-async-closure.stderr
deleted file mode 100644
index d2659553699..00000000000
--- a/tests/ui/async-await/no-params-non-move-async-closure.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0708]: `async` non-`move` closures with parameters are not currently supported
-  --> $DIR/no-params-non-move-async-closure.rs:6:13
-   |
-LL |     let _ = async |x: u8| {};
-   |             ^^^^^^^^^^^^^
-   |
-   = help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0708`.
diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr
index 9a308429484..aed4fd2a8c0 100644
--- a/tests/ui/check-cfg/cargo-feature.none.stderr
+++ b/tests/ui/check-cfg/cargo-feature.none.stderr
@@ -1,34 +1,36 @@
-warning: unexpected `cfg` condition name: `feature`
-  --> $DIR/cargo-feature.rs:13:7
+warning: unexpected `cfg` condition value: `serde`
+  --> $DIR/cargo-feature.rs:14:7
    |
 LL | #[cfg(feature = "serde")]
-   |       ^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^^^^^ help: remove the condition
    |
-   = help: consider defining some features in `Cargo.toml`
+   = note: no expected values for `feature`
+   = help: consider adding `serde` as a feature in `Cargo.toml`
    = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
-warning: unexpected `cfg` condition name: `feature`
+warning: unexpected `cfg` condition value: (none)
   --> $DIR/cargo-feature.rs:18:7
    |
 LL | #[cfg(feature)]
-   |       ^^^^^^^
+   |       ^^^^^^^ help: remove the condition
    |
+   = note: no expected values for `feature`
    = help: consider defining some features in `Cargo.toml`
    = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `tokio_unstable`
-  --> $DIR/cargo-feature.rs:23:7
+  --> $DIR/cargo-feature.rs:22:7
    |
 LL | #[cfg(tokio_unstable)]
    |       ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
    = help: consider using a Cargo feature instead or adding `println!("cargo:rustc-check-cfg=cfg(tokio_unstable)");` to the top of a `build.rs`
    = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `CONFIG_NVME`
-  --> $DIR/cargo-feature.rs:27:7
+  --> $DIR/cargo-feature.rs:26:7
    |
 LL | #[cfg(CONFIG_NVME = "m")]
    |       ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/cargo-feature.rs b/tests/ui/check-cfg/cargo-feature.rs
index f2fd0fd6420..8542174d0c0 100644
--- a/tests/ui/check-cfg/cargo-feature.rs
+++ b/tests/ui/check-cfg/cargo-feature.rs
@@ -5,19 +5,18 @@
 // check-pass
 // revisions: some none
 // rustc-env:CARGO=/usr/bin/cargo
-// compile-flags: --check-cfg=cfg() -Z unstable-options
+// compile-flags: -Z unstable-options
+// [none]compile-flags: --check-cfg=cfg(feature,values())
 // [some]compile-flags: --check-cfg=cfg(feature,values("bitcode"))
 // [some]compile-flags: --check-cfg=cfg(CONFIG_NVME,values("y"))
 // [none]error-pattern:Cargo.toml
 
 #[cfg(feature = "serde")]
-//[none]~^ WARNING unexpected `cfg` condition name
-//[some]~^^ WARNING unexpected `cfg` condition value
+//~^ WARNING unexpected `cfg` condition value
 fn ser() {}
 
 #[cfg(feature)]
-//[none]~^ WARNING unexpected `cfg` condition name
-//[some]~^^ WARNING unexpected `cfg` condition value
+//~^ WARNING unexpected `cfg` condition value
 fn feat() {}
 
 #[cfg(tokio_unstable)]
diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr
index fc6951b5617..74d65e550bb 100644
--- a/tests/ui/check-cfg/cargo-feature.some.stderr
+++ b/tests/ui/check-cfg/cargo-feature.some.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `serde`
-  --> $DIR/cargo-feature.rs:13:7
+  --> $DIR/cargo-feature.rs:14:7
    |
 LL | #[cfg(feature = "serde")]
    |       ^^^^^^^^^^^^^^^^^
@@ -16,10 +16,11 @@ LL | #[cfg(feature)]
    |       ^^^^^^^- help: specify a config value: `= "bitcode"`
    |
    = note: expected values for `feature` are: `bitcode`
+   = help: consider defining some features in `Cargo.toml`
    = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `tokio_unstable`
-  --> $DIR/cargo-feature.rs:23:7
+  --> $DIR/cargo-feature.rs:22:7
    |
 LL | #[cfg(tokio_unstable)]
    |       ^^^^^^^^^^^^^^
@@ -29,7 +30,7 @@ LL | #[cfg(tokio_unstable)]
    = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `m`
-  --> $DIR/cargo-feature.rs:27:7
+  --> $DIR/cargo-feature.rs:26:7
    |
 LL | #[cfg(CONFIG_NVME = "m")]
    |       ^^^^^^^^^^^^^^---
diff --git a/tests/ui/check-cfg/concat-values.rs b/tests/ui/check-cfg/concat-values.rs
index 0f9178ce6a5..ad922f8c908 100644
--- a/tests/ui/check-cfg/concat-values.rs
+++ b/tests/ui/check-cfg/concat-values.rs
@@ -1,6 +1,7 @@
 // check-pass
 // compile-flags: -Z unstable-options
 // compile-flags: --check-cfg=cfg(my_cfg,values("foo")) --check-cfg=cfg(my_cfg,values("bar"))
+// compile-flags: --check-cfg=cfg(my_cfg,values())
 
 #[cfg(my_cfg)]
 //~^ WARNING unexpected `cfg` condition value
@@ -10,4 +11,7 @@ fn my_cfg() {}
 //~^ WARNING unexpected `cfg` condition value
 fn my_cfg() {}
 
+#[cfg(any(my_cfg = "foo", my_cfg = "bar"))]
+fn foo_and_bar() {}
+
 fn main() {}
diff --git a/tests/ui/check-cfg/concat-values.stderr b/tests/ui/check-cfg/concat-values.stderr
index dec43f5bda3..6fe9f2baa09 100644
--- a/tests/ui/check-cfg/concat-values.stderr
+++ b/tests/ui/check-cfg/concat-values.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: (none)
-  --> $DIR/concat-values.rs:5:7
+  --> $DIR/concat-values.rs:6:7
    |
 LL | #[cfg(my_cfg)]
    |       ^^^^^^
@@ -10,7 +10,7 @@ LL | #[cfg(my_cfg)]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `unk`
-  --> $DIR/concat-values.rs:9:7
+  --> $DIR/concat-values.rs:10:7
    |
 LL | #[cfg(my_cfg = "unk")]
    |       ^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/empty-values.rs b/tests/ui/check-cfg/empty-values.rs
new file mode 100644
index 00000000000..7e6ba6ae84a
--- /dev/null
+++ b/tests/ui/check-cfg/empty-values.rs
@@ -0,0 +1,14 @@
+// Check that we detect unexpected value when none are allowed
+//
+// check-pass
+// compile-flags: --check-cfg=cfg(foo,values()) -Zunstable-options
+
+#[cfg(foo = "foo")]
+//~^ WARNING unexpected `cfg` condition value
+fn do_foo() {}
+
+#[cfg(foo)]
+//~^ WARNING unexpected `cfg` condition value
+fn do_foo() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/empty-values.stderr b/tests/ui/check-cfg/empty-values.stderr
new file mode 100644
index 00000000000..e7b0b05d561
--- /dev/null
+++ b/tests/ui/check-cfg/empty-values.stderr
@@ -0,0 +1,23 @@
+warning: unexpected `cfg` condition value: `foo`
+  --> $DIR/empty-values.rs:6:7
+   |
+LL | #[cfg(foo = "foo")]
+   |       ^^^^^^^^^^^ help: remove the condition
+   |
+   = note: no expected values for `foo`
+   = help: to expect this configuration use `--check-cfg=cfg(foo, values("foo"))`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition value: (none)
+  --> $DIR/empty-values.rs:10:7
+   |
+LL | #[cfg(foo)]
+   |       ^^^ help: remove the condition
+   |
+   = note: no expected values for `foo`
+   = help: to expect this configuration use `--check-cfg=cfg(foo)`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
index 1a13255429f..02d75ff1228 100644
--- a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
+++ b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
@@ -9,7 +9,7 @@ LL |         let c1 : () = c;
    |                  expected due to this
    |
    = note: expected unit type `()`
-                found closure `{mod1::f<T>::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}`
+                found closure `{mod1::f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}`
 help: use parentheses to call this closure
    |
 LL |         let c1 : () = c();
diff --git a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr
index 8553817247d..a5367688989 100644
--- a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr
+++ b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr
@@ -9,7 +9,7 @@ LL |         let c1 : () = c;
    |                  expected due to this
    |
    = note: expected unit type `()`
-                found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}`
+                found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}`
 help: use parentheses to call this closure
    |
 LL |         let c1 : () = c();
diff --git a/tests/ui/closures/print/closure-print-verbose.stderr b/tests/ui/closures/print/closure-print-verbose.stderr
index 3d0af5eb171..fca8f25792a 100644
--- a/tests/ui/closures/print/closure-print-verbose.stderr
+++ b/tests/ui/closures/print/closure-print-verbose.stderr
@@ -7,7 +7,7 @@ LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
    |              expected due to this
    |
    = note: expected fn pointer `fn(u8) -> u8`
-                 found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?6t]}`
+                 found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?4t]}`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-print-verbose.rs:10:39
    |
diff --git a/tests/ui/consts/const-eval/infinite_loop.rs b/tests/ui/consts/const-eval/infinite_loop.rs
index 21781490637..9bdb9929bec 100644
--- a/tests/ui/consts/const-eval/infinite_loop.rs
+++ b/tests/ui/consts/const-eval/infinite_loop.rs
@@ -1,7 +1,13 @@
+//! This test tests two things at once:
+//! 1. we error if a const evaluation hits the deny-by-default lint limit
+//! 2. we do not ICE on invalid follow-up code
+
+// compile-flags: -Z tiny-const-eval-limit
+
 fn main() {
     // Tests the Collatz conjecture with an incorrect base case (0 instead of 1).
     // The value of `n` will loop indefinitely (4 - 2 - 1 - 4).
-    let _ = [(); {
+    let s = [(); {
         let mut n = 113383; // #20 in https://oeis.org/A006884
         while n != 0 {
             //~^ ERROR is taking a long time
@@ -9,4 +15,6 @@ fn main() {
         }
         n
     }];
+
+    s.nonexistent_method();
 }
diff --git a/tests/ui/consts/const-eval/infinite_loop.stderr b/tests/ui/consts/const-eval/infinite_loop.stderr
index e7a0a96a1e6..37cd94bf7b7 100644
--- a/tests/ui/consts/const-eval/infinite_loop.stderr
+++ b/tests/ui/consts/const-eval/infinite_loop.stderr
@@ -1,5 +1,5 @@
 error: constant evaluation is taking a long time
-  --> $DIR/infinite_loop.rs:6:9
+  --> $DIR/infinite_loop.rs:12:9
    |
 LL | /         while n != 0 {
 LL | |
@@ -10,9 +10,9 @@ LL | |         }
    = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
            If your compilation actually takes a long time, you can safely allow the lint.
 help: the constant being evaluated
-  --> $DIR/infinite_loop.rs:4:18
+  --> $DIR/infinite_loop.rs:10:18
    |
-LL |       let _ = [(); {
+LL |       let s = [(); {
    |  __________________^
 LL | |         let mut n = 113383; // #20 in https://oeis.org/A006884
 LL | |         while n != 0 {
diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
index ad73b12feb5..ff265e576b9 100644
--- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
+++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
@@ -7,6 +7,8 @@ struct Bar;
 impl Foo<char> for Bar {
     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
         //~^ ERROR: the trait bound `impl Foo<u8>: Foo<char>` is not satisfied [E0277]
+        //~| ERROR: the trait bound `Bar: Foo<u8>` is not satisfied [E0277]
+        //~| ERROR: impl has stricter requirements than trait
         self
     }
 }
diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
index db587d069f8..638de01f913 100644
--- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
+++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
@@ -11,6 +11,28 @@ note: required by a bound in `Foo::{opaque#0}`
 LL |     fn foo<F2>(self) -> impl Foo<T>;
    |                              ^^^^^^ required by this bound in `Foo::{opaque#0}`
 
-error: aborting due to 1 previous error
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/return-dont-satisfy-bounds.rs:8:16
+   |
+LL |     fn foo<F2>(self) -> impl Foo<T>;
+   |     -------------------------------- definition of `foo` from trait
+...
+LL |     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
+   |                ^^^^^^^ impl has extra requirement `F2: Foo<u8>`
+
+error[E0277]: the trait bound `Bar: Foo<u8>` is not satisfied
+  --> $DIR/return-dont-satisfy-bounds.rs:8:34
+   |
+LL |     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
+   |                                  ^^^^^^^^^^^^ the trait `Foo<u8>` is not implemented for `Bar`
+...
+LL |         self
+   |         ---- return type was inferred to be `Bar` here
+   |
+   = help: the trait `Foo<char>` is implemented for `Bar`
+   = help: for that trait implementation, expected `char`, found `u8`
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0276, E0277.
+For more information about an error, try `rustc --explain E0276`.
diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs
new file mode 100644
index 00000000000..529913479ef
--- /dev/null
+++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs
@@ -0,0 +1,21 @@
+//! This is a regression test to avoid an ICE in diagnostics code.
+//! A typo in the compiler used to get the DefId of FnOnce, and
+//! use it where an associated item was expected.
+
+fn frob() -> impl Fn<P, Output = T> + '_ {}
+//~^ ERROR missing lifetime specifier
+//~| ERROR cannot find type `P`
+//~| ERROR cannot find type `T`
+//~| ERROR `Fn`-family traits' type parameters is subject to change
+
+fn open_parent<'path>() {
+    todo!()
+}
+
+fn main() {
+    let old_path = frob("hello");
+    //~^ ERROR function takes 0 arguments
+
+    open_parent(&old_path)
+    //~^ ERROR function takes 0 arguments
+}
diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
new file mode 100644
index 00000000000..b54b9f908b2
--- /dev/null
+++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
@@ -0,0 +1,78 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/opaque-used-in-extraneous-argument.rs:5:39
+   |
+LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
+   |                                       ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
+   |
+LL | fn frob() -> impl Fn<P, Output = T> + 'static {}
+   |                                       ~~~~~~~
+
+error[E0412]: cannot find type `P` in this scope
+  --> $DIR/opaque-used-in-extraneous-argument.rs:5:22
+   |
+LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
+   |                      ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | fn frob<P>() -> impl Fn<P, Output = T> + '_ {}
+   |        +++
+
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/opaque-used-in-extraneous-argument.rs:5:34
+   |
+LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
+   |                                  ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | fn frob<T>() -> impl Fn<P, Output = T> + '_ {}
+   |        +++
+
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
+  --> $DIR/opaque-used-in-extraneous-argument.rs:5:19
+   |
+LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
+   |                   ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(P) -> T`
+   |
+   = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
+   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0061]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/opaque-used-in-extraneous-argument.rs:16:20
+   |
+LL |     let old_path = frob("hello");
+   |                    ^^^^ -------
+   |                         |
+   |                         unexpected argument of type `&'static str`
+   |                         help: remove the extra argument
+   |
+note: function defined here
+  --> $DIR/opaque-used-in-extraneous-argument.rs:5:4
+   |
+LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
+   |    ^^^^
+
+error[E0061]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/opaque-used-in-extraneous-argument.rs:19:5
+   |
+LL |     open_parent(&old_path)
+   |     ^^^^^^^^^^^ ---------
+   |                 |
+   |                 unexpected argument of type `&impl FnOnce<{type error}, Output = {type error}> + Fn<{type error}> + 'static`
+   |                 help: remove the extra argument
+   |
+note: function defined here
+  --> $DIR/opaque-used-in-extraneous-argument.rs:11:4
+   |
+LL | fn open_parent<'path>() {
+   |    ^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0061, E0106, E0412, E0658.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/implied-bounds/auxiliary/bevy_ecs.rs b/tests/ui/implied-bounds/auxiliary/bevy_ecs.rs
deleted file mode 100644
index b373d39f4d9..00000000000
--- a/tests/ui/implied-bounds/auxiliary/bevy_ecs.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Related to Bevy regression #118553
-
-pub trait WorldQuery {}
-impl WorldQuery for &u8 {}
-
-pub struct Query<Q: WorldQuery>(Q);
-
-pub trait SystemParam {
-    type State;
-}
-impl<Q: WorldQuery + 'static> SystemParam for Query<Q> {
-    type State = ();
-    // `Q: 'static` is required because we need the TypeId of Q ...
-}
-
-pub struct ParamSet<T: SystemParam>(T)
-where
-    T::State: Sized;
diff --git a/tests/ui/implied-bounds/bevy_world_query.rs b/tests/ui/implied-bounds/bevy_world_query.rs
index f8e64632676..d5de0e9ef21 100644
--- a/tests/ui/implied-bounds/bevy_world_query.rs
+++ b/tests/ui/implied-bounds/bevy_world_query.rs
@@ -1,11 +1,26 @@
-// aux-crate:bevy_ecs=bevy_ecs.rs
 // check-pass
-// Related to Bevy regression #118553
 
-extern crate bevy_ecs;
+// We currently special case bevy from erroring on incorrect implied bounds
+// from normalization (issue #109628).
+// Otherwise, we would expect this to hit that error.
 
-use bevy_ecs::*;
+pub trait WorldQuery {}
+impl WorldQuery for &u8 {}
+
+pub struct Query<Q: WorldQuery>(Q);
+
+pub trait SystemParam {
+    type State;
+}
+impl<Q: WorldQuery + 'static> SystemParam for Query<Q> {
+    type State = ();
+    // `Q: 'static` is required because we need the TypeId of Q ...
+}
+
+pub struct ParamSet<T: SystemParam>(T) where T::State: Sized;
 
 fn handler<'a>(_: ParamSet<Query<&'a u8>>) {}
 
+fn ref_handler<'a>(_: &ParamSet<Query<&'a u8>>) {}
+
 fn main() {}
diff --git a/tests/ui/implied-bounds/from-trait-impl.rs b/tests/ui/implied-bounds/from-trait-impl.rs
index d13fddd9b8d..6e126575aa9 100644
--- a/tests/ui/implied-bounds/from-trait-impl.rs
+++ b/tests/ui/implied-bounds/from-trait-impl.rs
@@ -1,6 +1,3 @@
-// check-pass
-// known-bug: #109628
-
 trait Trait {
     type Assoc;
 }
@@ -14,11 +11,13 @@ where
     T::Assoc: Clone; // any predicate using `T::Assoc` works here
 
 fn func1(foo: Foo<(&str,)>) {
+    //~^ ERROR `&str` does not fulfill the required lifetime
     let _: &'static str = foo.0.0;
 }
 
 trait TestTrait {}
 
 impl<X> TestTrait for [Foo<(X,)>; 1] {}
+//~^ ERROR `X` may not live long enough
 
 fn main() {}
diff --git a/tests/ui/implied-bounds/from-trait-impl.stderr b/tests/ui/implied-bounds/from-trait-impl.stderr
new file mode 100644
index 00000000000..4151d206ae2
--- /dev/null
+++ b/tests/ui/implied-bounds/from-trait-impl.stderr
@@ -0,0 +1,26 @@
+error[E0477]: the type `&str` does not fulfill the required lifetime
+  --> $DIR/from-trait-impl.rs:13:15
+   |
+LL | fn func1(foo: Foo<(&str,)>) {
+   |               ^^^^^^^^^^^^
+   |
+   = note: type must satisfy the static lifetime
+
+error[E0310]: the parameter type `X` may not live long enough
+  --> $DIR/from-trait-impl.rs:20:23
+   |
+LL | impl<X> TestTrait for [Foo<(X,)>; 1] {}
+   |                       ^^^^^^^^^^^^^^
+   |                       |
+   |                       the parameter type `X` must be valid for the static lifetime...
+   |                       ...so that the type `X` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL | impl<X: 'static> TestTrait for [Foo<(X,)>; 1] {}
+   |       +++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0310, E0477.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/tests/ui/implied-bounds/gluon_salsa.rs b/tests/ui/implied-bounds/gluon_salsa.rs
index 98951af8ac2..cd5500cb458 100644
--- a/tests/ui/implied-bounds/gluon_salsa.rs
+++ b/tests/ui/implied-bounds/gluon_salsa.rs
@@ -1,5 +1,5 @@
 // check-pass
-// Related to Bevy regression #118553
+// Found in a crater run on #118553
 
 pub trait QueryBase {
     type Db;
@@ -17,8 +17,7 @@ pub struct QueryTable<'me, Q, DB> {
     _marker: Option<&'me ()>,
 }
 
-impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db>
-// projection is important
+impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db> // projection is important
 //   ^^^ removing 'me (and in QueryTable) gives a different error
 where
     Q: for<'f> AsyncQueryFunction<'f>,
diff --git a/tests/ui/implied-bounds/normalization-nested.lifetime.stderr b/tests/ui/implied-bounds/normalization-nested.lifetime.stderr
deleted file mode 100644
index e020230d86a..00000000000
--- a/tests/ui/implied-bounds/normalization-nested.lifetime.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0759]: `fn` parameter has lifetime `'x` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/normalization-nested.rs:35:28
-   |
-LL | pub fn test_wfcheck<'x>(_: Map<Vec<&'x ()>>) {}
-   |                            ^^^^^^^^^^^^^^^^
-   |                            |
-   |                            this data with lifetime `'x`...
-   |                            ...is used and required to live as long as `'static` here
-   |
-note: `'static` lifetime requirement introduced by this bound
-  --> $DIR/normalization-nested.rs:33:14
-   |
-LL |     I::Item: 'static;
-   |              ^^^^^^^
-
-error[E0759]: `fn` parameter has lifetime `'x` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/normalization-nested.rs:37:29
-   |
-LL | pub fn test_borrowck<'x>(_: Map<Vec<&'x ()>>, s: &'x str) -> &'static str {
-   |                             ^^^^^^^^^^^^^^^^
-   |                             |
-   |                             this data with lifetime `'x`...
-   |                             ...is used and required to live as long as `'static` here
-   |
-note: `'static` lifetime requirement introduced by this bound
-  --> $DIR/normalization-nested.rs:33:14
-   |
-LL |     I::Item: 'static;
-   |              ^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0759`.
diff --git a/tests/ui/implied-bounds/normalization-nested.rs b/tests/ui/implied-bounds/normalization-nested.rs
index 87903783a67..3f569aa1ace 100644
--- a/tests/ui/implied-bounds/normalization-nested.rs
+++ b/tests/ui/implied-bounds/normalization-nested.rs
@@ -1,11 +1,8 @@
 // Test for normalization of projections that appear in the item bounds
 // (versus those that appear directly in the input types).
-// Both revisions should pass. `lifetime` revision is a bug.
 //
 // revisions: param_ty lifetime
-// [param_ty] check-pass
-// [lifetime] check-fail
-// [lifetime] known-bug: #109799
+// check-pass
 
 pub trait Iter {
     type Item;
diff --git a/tests/ui/implied-bounds/sod_service_chain.rs b/tests/ui/implied-bounds/sod_service_chain.rs
index f45ced71f75..7443a29f30c 100644
--- a/tests/ui/implied-bounds/sod_service_chain.rs
+++ b/tests/ui/implied-bounds/sod_service_chain.rs
@@ -1,5 +1,4 @@
-// check-pass
-// Related to crater regressions on #118553
+// Found in a crater run on #118553
 
 pub trait Debug {}
 
@@ -30,6 +29,9 @@ impl<P: Service, S: Service<Input = P::Output>> ServiceChainBuilder<P, S> {
     pub fn next<NS: Service<Input = S::Output>>(
         self,
     ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> {
+        //~^ the associated type
+        //~| the associated type
+        //~| the associated type
         panic!();
     }
 }
diff --git a/tests/ui/implied-bounds/sod_service_chain.stderr b/tests/ui/implied-bounds/sod_service_chain.stderr
new file mode 100644
index 00000000000..1c0ef573e7d
--- /dev/null
+++ b/tests/ui/implied-bounds/sod_service_chain.stderr
@@ -0,0 +1,31 @@
+error[E0310]: the associated type `<P as Service>::Error` may not live long enough
+  --> $DIR/sod_service_chain.rs:31:10
+   |
+LL |     ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> {
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |          |
+   |          the associated type `<P as Service>::Error` must be valid for the static lifetime...
+   |          ...so that the type `<P as Service>::Error` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> where <P as Service>::Error: 'static {
+   |                                                      ++++++++++++++++++++++++++++++++++++
+
+error[E0310]: the associated type `<S as Service>::Error` may not live long enough
+  --> $DIR/sod_service_chain.rs:31:10
+   |
+LL |     ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> {
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |          |
+   |          the associated type `<S as Service>::Error` must be valid for the static lifetime...
+   |          ...so that the type `<S as Service>::Error` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> where <S as Service>::Error: 'static {
+   |                                                      ++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/inference/issue-80409.rs b/tests/ui/inference/issue-80409.rs
index 80cad6dfc46..d36688978e9 100644
--- a/tests/ui/inference/issue-80409.rs
+++ b/tests/ui/inference/issue-80409.rs
@@ -1,4 +1,12 @@
-// check-pass
+// This should not pass, because `usize: Fsm` does not hold. However, it currently ICEs.
+
+// check-fail
+// known-bug: #80409
+// failure-status: 101
+// normalize-stderr-test "note: .*\n\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
+// rustc-env:RUST_BACKTRACE=0
 
 #![allow(unreachable_code, unused)]
 
diff --git a/tests/ui/inference/issue-80409.stderr b/tests/ui/inference/issue-80409.stderr
new file mode 100644
index 00000000000..7bb4786db3a
--- /dev/null
+++ b/tests/ui/inference/issue-80409.stderr
@@ -0,0 +1,6 @@
+error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ImpliedOutlivesBounds { ty: &'?2 mut StateContext<'?3, usize> } }
+   |
+   = query stack during panic:
+end of query stack
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/object-safety/erroneous_signature.rs b/tests/ui/object-safety/erroneous_signature.rs
new file mode 100644
index 00000000000..cc1841cc4b2
--- /dev/null
+++ b/tests/ui/object-safety/erroneous_signature.rs
@@ -0,0 +1,17 @@
+trait Foo {
+    fn err(&self) -> MissingType;
+    //~^ ERROR cannot find type `MissingType` in this scope
+}
+
+impl Foo for i32 {
+    fn err(&self) -> MissingType {
+        //~^ ERROR cannot find type `MissingType` in this scope
+        0
+    }
+}
+
+fn coerce(x: &i32) -> &dyn Foo {
+    x
+}
+
+fn main() {}
diff --git a/tests/ui/object-safety/erroneous_signature.stderr b/tests/ui/object-safety/erroneous_signature.stderr
new file mode 100644
index 00000000000..f3b14ffe34c
--- /dev/null
+++ b/tests/ui/object-safety/erroneous_signature.stderr
@@ -0,0 +1,15 @@
+error[E0412]: cannot find type `MissingType` in this scope
+  --> $DIR/erroneous_signature.rs:2:22
+   |
+LL |     fn err(&self) -> MissingType;
+   |                      ^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `MissingType` in this scope
+  --> $DIR/erroneous_signature.rs:7:22
+   |
+LL |     fn err(&self) -> MissingType {
+   |                      ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
index 5210a694201..e5b9493b3ce 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
@@ -7,6 +7,16 @@ LL | impl<T: Default> A for T {
 LL | impl<T: Default + ~const Sup> const A for T {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
 
-error: aborting due to 1 previous error
+error[E0308]: mismatched types
+  --> $DIR/specializing-constness-2.rs:27:5
+   |
+LL |     <T as A>::a();
+   |     ^^^^^^^^^^^^^ expected `host`, found `true`
+   |
+   = note: expected constant `host`
+              found constant `true`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0119`.
+Some errors have detailed explanations: E0119, E0308.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs
index e20ca50b88f..2f9ca09f3a5 100644
--- a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs
Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr
index ff9006f6f97..a05dea3ff07 100644
--- a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr
Binary files differdiff --git a/tests/ui/type-alias-impl-trait/closure_infer.rs b/tests/ui/type-alias-impl-trait/closure_infer.rs
new file mode 100644
index 00000000000..04e2323ec4a
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/closure_infer.rs
@@ -0,0 +1,35 @@
+// check-pass
+
+// Regression test for an ICE: https://github.com/rust-lang/rust/issues/119916
+
+#![feature(impl_trait_in_assoc_type)]
+#![feature(type_alias_impl_trait)]
+
+// `impl_trait_in_assoc_type` example from the bug report.
+pub trait StreamConsumer {
+    type BarrierStream;
+    fn execute() -> Self::BarrierStream;
+}
+
+pub struct DispatchExecutor;
+
+impl StreamConsumer for DispatchExecutor {
+    type BarrierStream = impl Sized;
+    fn execute() -> Self::BarrierStream {
+        || -> _ {}
+    }
+}
+
+// Functions that constrain TAITs can contain closures with an `_` in the return type.
+type Foo = impl Sized;
+fn foo() -> Foo {
+    || -> _ {}
+}
+
+// The `_` in the closure return type can also be the TAIT itself.
+type Bar = impl Sized;
+fn bar() -> impl FnOnce() -> Bar {
+    || -> _ {}
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/issue-77179.rs b/tests/ui/type-alias-impl-trait/issue-77179.rs
index 093aeb4b279..3d6c826d6ac 100644
--- a/tests/ui/type-alias-impl-trait/issue-77179.rs
+++ b/tests/ui/type-alias-impl-trait/issue-77179.rs
@@ -12,3 +12,8 @@ fn test() -> Pointer<_> {
 fn main() {
     test();
 }
+
+extern "Rust" {
+    fn bar() -> Pointer<_>;
+    //~^ ERROR: the placeholder `_` is not allowed within types
+}
diff --git a/tests/ui/type-alias-impl-trait/issue-77179.stderr b/tests/ui/type-alias-impl-trait/issue-77179.stderr
index 68dd6570d00..c5cacfd3cd3 100644
--- a/tests/ui/type-alias-impl-trait/issue-77179.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-77179.stderr
@@ -7,6 +7,15 @@ LL | fn test() -> Pointer<_> {
    |              |       not allowed in type signatures
    |              help: replace with the correct return type: `Pointer<i32>`
 
-error: aborting due to 1 previous error
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/issue-77179.rs:17:25
+   |
+LL |     fn bar() -> Pointer<_>;
+   |                         ^
+   |                         |
+   |                         not allowed in type signatures
+   |                         help: use type parameters instead: `T`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0121`.
diff --git a/triagebot.toml b/triagebot.toml
index 2b818c0a990..bd14640e280 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -631,7 +631,7 @@ cc = ["@nnethercote"]
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
-users_on_vacation = ["jyn514", "spastorino"]
+users_on_vacation = ["jyn514"]
 
 [assign.adhoc_groups]
 compiler-team = [