about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_attr/messages.ftl3
-rw-r--r--compiler/rustc_attr/src/builtin.rs106
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs7
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs6
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs206
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs27
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs29
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs6
-rw-r--r--compiler/rustc_driver_impl/messages.ftl1
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs60
-rw-r--r--compiler/rustc_driver_impl/src/session_diagnostics.rs4
-rw-r--r--compiler/rustc_expand/src/config.rs11
-rw-r--r--compiler/rustc_feature/src/unstable.rs1
-rw-r--r--compiler/rustc_hir/src/hir.rs52
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl41
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs291
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs172
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs70
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs84
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs21
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs6
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs15
-rw-r--r--compiler/rustc_infer/src/infer/generalize.rs20
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs87
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs4
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs10
-rw-r--r--compiler/rustc_interface/src/interface.rs8
-rw-r--r--compiler/rustc_interface/src/passes.rs13
-rw-r--r--compiler/rustc_interface/src/queries.rs8
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_interface/src/util.rs4
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs80
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs40
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/thir.rs22
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs7
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs8
-rw-r--r--compiler/rustc_middle/src/ty/context.rs32
-rw-r--r--compiler/rustc_middle/src/ty/error.rs8
-rw-r--r--compiler/rustc_middle/src/ty/list.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs117
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs104
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs123
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs41
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs34
-rw-r--r--compiler/rustc_mir_build/messages.ftl1
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs26
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs164
-rw-r--r--compiler/rustc_mir_build/src/errors.rs5
-rw-r--r--compiler/rustc_mir_build/src/lib.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs32
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs46
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs9
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs190
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs6
-rw-r--r--compiler/rustc_passes/messages.ftl5
-rw-r--r--compiler/rustc_passes/src/errors.rs10
-rw-r--r--compiler/rustc_passes/src/stability.rs64
-rw-r--r--compiler/rustc_privacy/src/lib.rs24
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs21
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs58
-rw-r--r--compiler/rustc_session/src/config.rs39
-rw-r--r--compiler/rustc_session/src/options.rs13
-rw-r--r--compiler/rustc_session/src/session.rs14
-rw-r--r--compiler/rustc_smir/Cargo.toml1
-rw-r--r--compiler/rustc_smir/src/lib.rs1
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs22
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs61
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs411
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/csky.rs38
-rw-r--r--compiler/rustc_trait_selection/messages.ftl5
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs301
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs57
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs84
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs4
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs2
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs74
-rw-r--r--compiler/rustc_ty_utils/src/sig_types.rs129
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs169
-rw-r--r--compiler/rustc_type_ir/src/codec.rs6
-rw-r--r--compiler/rustc_type_ir/src/const_kind.rs17
-rw-r--r--compiler/rustc_type_ir/src/debug.rs77
-rw-r--r--compiler/rustc_type_ir/src/interner.rs17
-rw-r--r--compiler/rustc_type_ir/src/lib.rs6
-rw-r--r--compiler/rustc_type_ir/src/macros.rs2
-rw-r--r--compiler/rustc_type_ir/src/predicate_kind.rs626
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs19
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs24
-rw-r--r--compiler/stable_mir/src/fold.rs245
-rw-r--r--compiler/stable_mir/src/lib.rs59
-rw-r--r--compiler/stable_mir/src/mir/body.rs62
-rw-r--r--compiler/stable_mir/src/ty.rs63
-rw-r--r--compiler/stable_mir/src/visitor.rs4
-rw-r--r--library/core/src/ffi/mod.rs2
-rw-r--r--library/core/src/iter/traits/iterator.rs1
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/net/socket_addr.rs51
-rw-r--r--library/core/src/num/mod.rs2
-rw-r--r--library/core/src/ops/coroutine.rs2
-rw-r--r--library/core/tests/net/socket_addr.rs11
-rw-r--r--library/std/src/io/mod.rs8
-rw-r--r--library/std/src/sys/unix/stack_overflow.rs14
-rw-r--r--src/bootstrap/Cargo.lock10
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/bootstrap_test.py1
-rw-r--r--src/bootstrap/src/bin/rustc.rs7
-rw-r--r--src/bootstrap/src/bin/rustdoc.rs2
-rw-r--r--src/bootstrap/src/core/builder.rs50
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md10
-rw-r--r--src/doc/unstable-book/src/compiler-flags/check-cfg.md2
-rw-r--r--src/doc/unstable-book/src/language-features/coroutines.md2
-rw-r--r--src/librustdoc/clean/types.rs6
-rw-r--r--src/librustdoc/core.rs3
-rw-r--r--src/librustdoc/doctest.rs1
-rw-r--r--src/librustdoc/html/render/mod.rs31
-rw-r--r--src/librustdoc/lib.rs16
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs30
-rw-r--r--src/tools/clippy/src/driver.rs8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr14
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs4
-rw-r--r--src/tools/compiletest/src/runtest.rs2
-rwxr-xr-xsrc/tools/miri/ci.sh2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs11
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs12
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs279
-rw-r--r--src/tools/miri/src/concurrency/weak_memory.rs44
-rw-r--r--src/tools/miri/src/diagnostics.rs13
-rw-r--r--src/tools/miri/src/intptrcast.rs13
-rw-r--r--src/tools/miri/src/shims/time.rs12
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read.rs25
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read.stderr20
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_write.rs25
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_write.stderr20
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race1.rs27
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race1.stderr20
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race2.rs27
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race2.stderr20
-rw-r--r--src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs4
-rw-r--r--src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr14
-rw-r--r--src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs4
-rw-r--r--src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr14
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs26
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-misc.rs2
-rw-r--r--src/tools/miri/tests/pass/concurrency/simple.rs18
-rw-r--r--src/tools/miri/tests/pass/intrinsics-math.rs5
-rw-r--r--src/tools/miri/tests/pass/weak_memory/extra_cpp_unsafe.rs40
-rw-r--r--src/tools/opt-dist/src/tests.rs7
-rw-r--r--tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff9
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff12
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff12
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.rs2
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff7
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff7
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff7
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff7
-rw-r--r--tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff13
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff226
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff226
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.rs25
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.rs4
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff (renamed from tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff)45
-rw-r--r--tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff112
-rw-r--r--tests/mir-opt/dataflow-const-prop/tuple.rs3
-rw-r--r--tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-abort.diff22
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff22
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-abort.diff19
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff19
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-abort.diff19
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff19
-rw-r--r--tests/mir-opt/inline/inline_compatibility.rs64
-rw-r--r--tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff19
-rw-r--r--tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff15
-rw-r--r--tests/mir-opt/instsimplify/casts.rs6
-rw-r--r--tests/run-make-fulldeps/issue-19371/foo.rs1
-rw-r--r--tests/run-make/issue-96498/Makefile8
-rw-r--r--tests/run-make/windows-safeseh/Makefile19
-rw-r--r--tests/run-make/windows-safeseh/bar.rs1
-rw-r--r--tests/run-make/windows-safeseh/baz.rs4
-rw-r--r--tests/run-make/windows-safeseh/foo.rs (renamed from tests/run-make/issue-96498/foo.rs)0
-rw-r--r--tests/rustdoc/deprecated-future-staged-api.rs6
-rw-r--r--tests/rustdoc/html-no-source.rs12
-rw-r--r--tests/rustdoc/implementor-stable-version.rs16
-rw-r--r--tests/rustdoc/source-version-separator.rs10
-rw-r--r--tests/rustdoc/version-separator-without-source.rs12
-rw-r--r--tests/ui-fulldeps/stable-mir/check_instance.rs35
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs95
-rw-r--r--tests/ui-fulldeps/stable-mir/smir_internal.rs64
-rw-r--r--tests/ui/abi/compatibility.rs1
-rw-r--r--tests/ui/associated-consts/issue-105330.rs1
-rw-r--r--tests/ui/associated-consts/issue-105330.stderr12
-rw-r--r--tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr14
-rw-r--r--tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr2
-rw-r--r--tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr2
-rw-r--r--tests/ui/associated-inherent-types/generic-associated-types-bad.rs1
-rw-r--r--tests/ui/associated-types/associated-types-no-suitable-supertrait.rs1
-rw-r--r--tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr14
-rw-r--r--tests/ui/async-await/async-await-let-else.stderr4
-rw-r--r--tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr2
-rw-r--r--tests/ui/async-await/async-unsafe-fn-call-in-safe.rs8
-rw-r--r--tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr18
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr4
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-extra.rs1
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-manual.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared-manual.stderr2
-rw-r--r--tests/ui/async-await/in-trait/async-example-desugared.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-example.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-generics-and-bounds.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-generics-and-bounds.stderr4
-rw-r--r--tests/ui/async-await/in-trait/async-generics.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-generics.stderr4
-rw-r--r--tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-lifetimes.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive-generic.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive-generic.stderr2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-recursive.stderr2
-rw-r--r--tests/ui/async-await/in-trait/coherence-constrained.rs26
-rw-r--r--tests/ui/async-await/in-trait/coherence-constrained.stderr25
-rw-r--r--tests/ui/async-await/in-trait/early-bound-1.rs2
-rw-r--r--tests/ui/async-await/issue-68112.stderr2
-rw-r--r--tests/ui/async-await/issue-70935-complex-spans.stderr2
-rw-r--r--tests/ui/async-await/issues/issue-67893.stderr2
-rw-r--r--tests/ui/async-await/partial-drop-partial-reinit.rs2
-rw-r--r--tests/ui/async-await/partial-drop-partial-reinit.stderr2
-rw-r--r--tests/ui/attributes/const-stability-on-macro.rs2
-rw-r--r--tests/ui/attributes/const-stability-on-macro.stderr4
-rw-r--r--tests/ui/attributes/statement-attribute-validation.rs39
-rw-r--r--tests/ui/attributes/statement-attribute-validation.stderr56
-rw-r--r--tests/ui/cast/ptr-to-ptr-different-regions.rs24
-rw-r--r--tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs1
-rw-r--r--tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr13
-rw-r--r--tests/ui/coherence/coherence-negative-outlives-lifetimes.rs2
-rw-r--r--tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr11
-rw-r--r--tests/ui/coherence/coherence-overlap-trait-alias.rs4
-rw-r--r--tests/ui/coherence/coherence-overlap-trait-alias.stderr16
-rw-r--r--tests/ui/coherence/coherence-overlap-with-regions.rs8
-rw-r--r--tests/ui/coherence/coherence-overlap-with-regions.stderr11
-rw-r--r--tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr12
-rw-r--r--tests/ui/coherence/negative-coherence-considering-regions.rs29
-rw-r--r--tests/ui/coherence/negative-coherence-considering-regions.static_lt.stderr12
-rw-r--r--tests/ui/const-generics/const-arg-in-const-arg.rs2
-rw-r--r--tests/ui/const-generics/defaults/default-annotation.rs6
-rw-r--r--tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr7
-rw-r--r--tests/ui/const-generics/generic_const_exprs/type_mismatch.rs13
-rw-r--r--tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr12
-rw-r--r--tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs1
-rw-r--r--tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr10
-rw-r--r--tests/ui/consts/const-unsized.rs4
-rw-r--r--tests/ui/consts/const-unsized.stderr44
-rw-r--r--tests/ui/deprecation/staged-deprecation-in-future.rs6
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs8
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr77
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs10
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr36
-rw-r--r--tests/ui/feature-gates/feature-gate-staged_api.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-staged_api.stderr8
-rw-r--r--tests/ui/generic-associated-types/issue-84931.rs3
-rw-r--r--tests/ui/generic-associated-types/issue-84931.stderr24
-rw-r--r--tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs1
-rw-r--r--tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr34
-rw-r--r--tests/ui/impl-trait/in-trait/deep-match.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/deep-match.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/default-body-type-err.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/doesnt-satisfy.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr4
-rw-r--r--tests/ui/impl-trait/in-trait/generics-mismatch.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/generics-mismatch.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102140.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102140.stderr6
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102571.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102571.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/object-safety.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/object-safety.stderr16
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr2
-rw-r--r--tests/ui/impl-trait/negative-reasoning.stderr2
-rw-r--r--tests/ui/impl-unused-tps.rs5
-rw-r--r--tests/ui/impl-unused-tps.stderr37
-rw-r--r--tests/ui/imports/issue-56125.stderr12
-rw-r--r--tests/ui/inline-const/expr-unsafe.thir.stderr3
-rw-r--r--tests/ui/inline-const/pat-unsafe-err.rs14
-rw-r--r--tests/ui/inline-const/pat-unsafe-err.thir.stderr19
-rw-r--r--tests/ui/inline-const/pat-unsafe.rs15
-rw-r--r--tests/ui/inline-const/pat-unsafe.thir.stderr20
-rw-r--r--tests/ui/instrument-coverage/bad-value.bad.stderr2
-rw-r--r--tests/ui/instrument-coverage/bad-value.blank.stderr2
-rw-r--r--tests/ui/instrument-coverage/except-unused-functions.rs3
-rw-r--r--tests/ui/instrument-coverage/except-unused-functions.stderr2
-rw-r--r--tests/ui/instrument-coverage/except-unused-generics.rs3
-rw-r--r--tests/ui/instrument-coverage/except-unused-generics.stderr2
-rw-r--r--tests/ui/instrument-coverage/unstable.branch.stderr2
-rw-r--r--tests/ui/instrument-coverage/unstable.except-unused-functions.stderr2
-rw-r--r--tests/ui/instrument-coverage/unstable.except-unused-generics.stderr2
-rw-r--r--tests/ui/instrument-coverage/unstable.rs6
-rw-r--r--tests/ui/issues/issue-19380.rs1
-rw-r--r--tests/ui/issues/issue-19380.stderr25
-rw-r--r--tests/ui/issues/issue-24446.rs2
-rw-r--r--tests/ui/issues/issue-24446.stderr37
-rw-r--r--tests/ui/issues/issue-77919.rs1
-rw-r--r--tests/ui/issues/issue-77919.stderr14
-rw-r--r--tests/ui/layout/issue-84108.rs2
-rw-r--r--tests/ui/layout/issue-84108.stderr24
-rw-r--r--tests/ui/lifetimes/issue-26638.stderr4
-rw-r--r--tests/ui/mismatched_types/async-unwrap-suggestion.rs22
-rw-r--r--tests/ui/mismatched_types/async-unwrap-suggestion.stderr25
-rw-r--r--tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs23
-rw-r--r--tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr55
-rw-r--r--tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed31
-rw-r--r--tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs31
-rw-r--r--tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr93
-rw-r--r--tests/ui/noexporttypeexe.stderr4
-rw-r--r--tests/ui/pattern/non-structural-match-types.mir.stderr14
-rw-r--r--tests/ui/pattern/non-structural-match-types.rs3
-rw-r--r--tests/ui/pattern/non-structural-match-types.stderr14
-rw-r--r--tests/ui/pattern/non-structural-match-types.thir.stderr14
-rw-r--r--tests/ui/privacy/associated-item-privacy-trait.rs2
-rw-r--r--tests/ui/privacy/associated-item-privacy-trait.stderr4
-rw-r--r--tests/ui/privacy/private-in-public.rs8
-rw-r--r--tests/ui/privacy/private-in-public.stderr20
-rw-r--r--tests/ui/proc-macro/bad-projection.rs2
-rw-r--r--tests/ui/proc-macro/bad-projection.stderr30
-rw-r--r--tests/ui/reachable/reachable-unnameable-type-alias.rs4
-rw-r--r--tests/ui/repr/16-bit-repr-c-enum.rs6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs2
-rw-r--r--tests/ui/simd/array-trait.rs1
-rw-r--r--tests/ui/simd/array-trait.stderr9
-rw-r--r--tests/ui/span/lint-unused-unsafe-thir.rs61
-rw-r--r--tests/ui/span/lint-unused-unsafe-thir.stderr50
-rw-r--r--tests/ui/span/lint-unused-unsafe.mir.stderr376
-rw-r--r--tests/ui/span/lint-unused-unsafe.rs8
-rw-r--r--tests/ui/span/lint-unused-unsafe.thir.stderr1402
-rw-r--r--tests/ui/specialization/min_specialization/issue-79224.rs1
-rw-r--r--tests/ui/specialization/min_specialization/issue-79224.stderr14
-rw-r--r--tests/ui/stability-attribute/stability-attribute-issue-43027.rs8
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity-4.rs4
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity.rs20
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity.stderr37
-rw-r--r--tests/ui/stability-attribute/stability-attribute-trait-impl.rs4
-rw-r--r--tests/ui/stability-attribute/stability-attribute-trait-impl.stderr2
-rw-r--r--tests/ui/target-feature/gate.rs1
-rw-r--r--tests/ui/target-feature/gate.stderr2
-rw-r--r--tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs43
-rw-r--r--tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr109
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-static.rs2
-rw-r--r--tests/ui/traits/bound/on-structs-and-enums-static.stderr19
-rw-r--r--tests/ui/traits/new-solver/specialization-transmute.rs2
-rw-r--r--tests/ui/traits/new-solver/specialization-transmute.stderr11
-rw-r--r--tests/ui/type-alias-impl-trait/generic_underconstrained.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/generic_underconstrained.stderr23
-rw-r--r--tests/ui/type-alias-impl-trait/generic_underconstrained2.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr48
-rw-r--r--tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-fn-tait.rs17
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr14
-rw-r--r--tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr4
-rw-r--r--tests/ui/ufcs/ufcs-explicit-self-bad.rs1
-rw-r--r--tests/ui/ufcs/ufcs-explicit-self-bad.stderr31
-rw-r--r--tests/ui/union/issue-81199.rs1
-rw-r--r--tests/ui/union/issue-81199.stderr19
-rw-r--r--tests/ui/union/union-unsized.mirunsafeck.stderr31
-rw-r--r--tests/ui/union/union-unsized.rs2
-rw-r--r--tests/ui/union/union-unsized.thirunsafeck.stderr31
-rw-r--r--tests/ui/unresolved/auxiliary/library.rs1
-rw-r--r--tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs31
-rw-r--r--tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr25
-rw-r--r--tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed19
-rw-r--r--tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs19
-rw-r--r--tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr14
-rw-r--r--tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr6
-rw-r--r--tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr6
-rw-r--r--tests/ui/unsized/unsized-trait-impl-self-type.rs1
-rw-r--r--tests/ui/unsized/unsized-trait-impl-self-type.stderr14
-rw-r--r--tests/ui/unsized/unsized-trait-impl-trait-arg.rs1
-rw-r--r--tests/ui/unsized/unsized-trait-impl-trait-arg.stderr14
-rw-r--r--tests/ui/unsized/unsized7.rs1
-rw-r--r--tests/ui/unsized/unsized7.stderr14
-rw-r--r--tests/ui/wf/hir-wf-check-erase-regions.rs1
-rw-r--r--tests/ui/wf/hir-wf-check-erase-regions.stderr16
-rw-r--r--tests/ui/wf/issue-110157.rs1
-rw-r--r--tests/ui/wf/issue-110157.stderr25
-rw-r--r--tests/ui/wf/wf-const-type.rs1
-rw-r--r--tests/ui/wf/wf-const-type.stderr20
-rw-r--r--tests/ui/wf/wf-static-type.rs1
-rw-r--r--tests/ui/wf/wf-static-type.stderr20
449 files changed, 8530 insertions, 3500 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4421e526d10..ff21d5f8c08 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4525,6 +4525,7 @@ dependencies = [
  "rustc_middle",
  "rustc_span",
  "rustc_target",
+ "scoped-tls",
  "stable_mir",
  "tracing",
 ]
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 4f1b13870fd..b82f878ea87 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -188,7 +188,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     e.id,
                     None,
                     e.span,
-                    hir::AsyncCoroutineKind::Block,
+                    hir::CoroutineSource::Block,
                     |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
                 ),
                 ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
@@ -598,7 +598,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         closure_node_id: NodeId,
         ret_ty: Option<hir::FnRetTy<'hir>>,
         span: Span,
-        async_gen_kind: hir::AsyncCoroutineKind,
+        async_gen_kind: hir::CoroutineSource,
         body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
     ) -> hir::ExprKind<'hir> {
         let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
@@ -1005,7 +1005,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     inner_closure_id,
                     async_ret_ty,
                     body.span,
-                    hir::AsyncCoroutineKind::Closure,
+                    hir::CoroutineSource::Closure,
                     |this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
                 );
                 let hir_id = this.lower_node_id(inner_closure_id);
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 3c165f87dbf..ca851bd4d35 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1206,7 +1206,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 closure_id,
                 None,
                 body.span,
-                hir::AsyncCoroutineKind::Fn,
+                hir::CoroutineSource::Fn,
                 |this| {
                     // Create a block from the user's function body:
                     let user_body = this.lower_block_expr(body);
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index e6cbbaf3704..7281282fec3 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -58,6 +58,9 @@ attr_invalid_repr_hint_no_paren =
 attr_invalid_repr_hint_no_value =
     invalid representation hint: `{$name}` does not take a value
 
+attr_invalid_since =
+    'since' must be a Rust version number, such as "1.31.0"
+
 attr_missing_feature =
     missing 'feature'
 
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 60eacde1c72..bd85483885e 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -3,6 +3,7 @@
 use rustc_ast::{self as ast, attr};
 use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
 use rustc_ast_pretty::pprust;
+use rustc_errors::ErrorGuaranteed;
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
 use rustc_macros::HashStable_Generic;
 use rustc_session::config::ExpectedValues;
@@ -12,6 +13,7 @@ use rustc_session::parse::{feature_err, ParseSess};
 use rustc_session::Session;
 use rustc_span::hygiene::Transparency;
 use rustc_span::{symbol::sym, symbol::Symbol, Span};
+use std::fmt::{self, Display};
 use std::num::NonZeroU32;
 
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -22,9 +24,10 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
 /// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
 pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
 
+pub const CURRENT_RUSTC_VERSION: &str = env!("CFG_RELEASE");
+
 pub fn rust_version_symbol() -> Symbol {
-    let version = option_env!("CFG_RELEASE").unwrap_or("<current>");
-    Symbol::intern(&version)
+    Symbol::intern(CURRENT_RUSTC_VERSION)
 }
 
 pub fn is_builtin_attr(attr: &Attribute) -> bool {
@@ -143,13 +146,24 @@ pub enum StabilityLevel {
     /// `#[stable]`
     Stable {
         /// Rust release which stabilized this feature.
-        since: Symbol,
+        since: Since,
         /// Is this item allowed to be referred to on stable, despite being contained in unstable
         /// modules?
         allowed_through_unstable_modules: bool,
     },
 }
 
+/// Rust release in which a feature is stabilized.
+#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
+#[derive(HashStable_Generic)]
+pub enum Since {
+    Version(Version),
+    /// Stabilized in the upcoming version, whatever number that is.
+    Current,
+    /// Failed to parse a stabilization version.
+    Err,
+}
+
 impl StabilityLevel {
     pub fn is_unstable(&self) -> bool {
         matches!(self, StabilityLevel::Unstable { .. })
@@ -361,25 +375,34 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
         }
     }
 
-    if let Some(s) = since
-        && s.as_str() == VERSION_PLACEHOLDER
-    {
-        since = Some(rust_version_symbol());
-    }
+    let feature = match feature {
+        Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
+        Some(_bad_feature) => {
+            Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
+        }
+        None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
+    };
+
+    let since = if let Some(since) = since {
+        if since.as_str() == VERSION_PLACEHOLDER {
+            Since::Current
+        } else if let Some(version) = parse_version(since.as_str(), false) {
+            Since::Version(version)
+        } else {
+            sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
+            Since::Err
+        }
+    } else {
+        sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
+        Since::Err
+    };
 
-    match (feature, since) {
-        (Some(feature), Some(since)) => {
+    match feature {
+        Ok(feature) => {
             let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
             Some((feature, level))
         }
-        (None, _) => {
-            sess.emit_err(session_diagnostics::MissingFeature { span: attr.span });
-            None
-        }
-        _ => {
-            sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
-            None
-        }
+        Err(ErrorGuaranteed { .. }) => None,
     }
 }
 
@@ -451,12 +474,19 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
         }
     }
 
-    match (feature, reason, issue) {
-        (Some(feature), reason, Some(_)) => {
-            if !rustc_lexer::is_ident(feature.as_str()) {
-                sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span });
-                return None;
-            }
+    let feature = match feature {
+        Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
+        Some(_bad_feature) => {
+            Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
+        }
+        None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
+    };
+
+    let issue =
+        issue.ok_or_else(|| sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }));
+
+    match (feature, issue) {
+        (Ok(feature), Ok(_)) => {
             let level = StabilityLevel::Unstable {
                 reason: UnstableReason::from_opt_reason(reason),
                 issue: issue_num,
@@ -465,14 +495,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
             };
             Some((feature, level))
         }
-        (None, _, _) => {
-            sess.emit_err(session_diagnostics::MissingFeature { span: attr.span });
-            return None;
-        }
-        _ => {
-            sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
-            return None;
-        }
+        (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
     }
 }
 
@@ -548,11 +571,12 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-struct Version {
-    major: u16,
-    minor: u16,
-    patch: u16,
+#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(HashStable_Generic)]
+pub struct Version {
+    pub major: u16,
+    pub minor: u16,
+    pub patch: u16,
 }
 
 fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
@@ -568,6 +592,12 @@ fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
     Some(Version { major, minor, patch })
 }
 
+impl Display for Version {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
+    }
+}
+
 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
 /// evaluate individual items.
 pub fn eval_condition(
@@ -601,7 +631,7 @@ pub fn eval_condition(
                 sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
                 return false;
             };
-            let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
+            let rustc_version = parse_version(CURRENT_RUSTC_VERSION, true).unwrap();
 
             // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
             if sess.assume_incomplete_release {
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 86f27254db2..ca9bbd28b95 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -371,6 +371,13 @@ pub(crate) struct ExpectsFeatures {
 }
 
 #[derive(Diagnostic)]
+#[diag(attr_invalid_since)]
+pub(crate) struct InvalidSince {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(attr_soft_no_args)]
 pub(crate) struct SoftNoArgs {
     #[primary_span]
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b5ad02dc688..928c25d1061 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -8,7 +8,7 @@ use rustc_errors::{
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
-use rustc_hir::{AsyncCoroutineKind, CoroutineKind, LangItem};
+use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::tcx::PlaceTy;
@@ -2506,8 +2506,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let kind = match use_span.coroutine_kind() {
             Some(coroutine_kind) => match coroutine_kind {
                 CoroutineKind::Async(async_kind) => match async_kind {
-                    AsyncCoroutineKind::Block => "async block",
-                    AsyncCoroutineKind::Closure => "async closure",
+                    CoroutineSource::Block => "async block",
+                    CoroutineSource::Closure => "async closure",
                     _ => bug!("async block/closure expected, but async function found."),
                 },
                 CoroutineKind::Coroutine => "coroutine",
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index de9ece3faba..e630ac7c4fa 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -682,9 +682,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 };
                 let mir_description = match hir.body(body).coroutine_kind {
                     Some(hir::CoroutineKind::Async(gen)) => match gen {
-                        hir::AsyncCoroutineKind::Block => " of async block",
-                        hir::AsyncCoroutineKind::Closure => " of async closure",
-                        hir::AsyncCoroutineKind::Fn => {
+                        hir::CoroutineSource::Block => " of async block",
+                        hir::CoroutineSource::Closure => " of async closure",
+                        hir::CoroutineSource::Fn => {
                             let parent_item =
                                 hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
                             let output = &parent_item
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 5d6f5cc8967..ec0131c5349 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -81,6 +81,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
+        if matches!(ty_context, TyContext::ReturnTy(_)) {
+            // We will renumber the return ty when called again with `TyContext::LocalDecl`
+            return;
+        }
         *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context));
 
         debug!(?ty);
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 7252658d460..aa1ce1b929d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -37,8 +37,9 @@
 //! following snippet
 //!
 //! ```rust
-//! # #![allow(dead_code)]
-//! struct A { x : i32 }
+//! struct A {
+//!     x: i32,
+//! }
 //!
 //! struct B(i32);
 //!
@@ -74,6 +75,7 @@
 //! trait PartialEq {
 //!     fn eq(&self, other: &Self) -> bool;
 //! }
+//!
 //! impl PartialEq for i32 {
 //!     fn eq(&self, other: &i32) -> bool {
 //!         *self == *other
@@ -90,22 +92,22 @@
 //!
 //! ```text
 //! Struct(vec![FieldInfo {
-//!            span: <span of x>
-//!            name: Some(<ident of x>),
-//!            self_: <expr for &self.x>,
-//!            other: vec![<expr for &other.x]
-//!          }])
+//!     span: <span of x>,
+//!     name: Some(<ident of x>),
+//!     self_: <expr for &self.x>,
+//!     other: vec![<expr for &other.x>],
+//! }])
 //! ```
 //!
 //! For the `B` impl, called with `B(a)` and `B(b)`,
 //!
 //! ```text
 //! Struct(vec![FieldInfo {
-//!           span: <span of `i32`>,
-//!           name: None,
-//!           self_: <expr for &a>
-//!           other: vec![<expr for &b>]
-//!          }])
+//!     span: <span of i32>,
+//!     name: None,
+//!     self_: <expr for &a>,
+//!     other: vec![<expr for &b>],
+//! }])
 //! ```
 //!
 //! ## Enums
@@ -114,33 +116,42 @@
 //! == C0(b)`, the SubstructureFields is
 //!
 //! ```text
-//! EnumMatching(0, <ast::Variant for C0>,
-//!              vec![FieldInfo {
-//!                 span: <span of i32>
-//!                 name: None,
-//!                 self_: <expr for &a>,
-//!                 other: vec![<expr for &b>]
-//!               }])
+//! EnumMatching(
+//!     0,
+//!     <ast::Variant for C0>,
+//!     vec![FieldInfo {
+//!         span: <span of i32>,
+//!         name: None,
+//!         self_: <expr for &a>,
+//!         other: vec![<expr for &b>],
+//!     }],
+//! )
 //! ```
 //!
 //! For `C1 {x}` and `C1 {x}`,
 //!
 //! ```text
-//! EnumMatching(1, <ast::Variant for C1>,
-//!              vec![FieldInfo {
-//!                 span: <span of x>
-//!                 name: Some(<ident of x>),
-//!                 self_: <expr for &self.x>,
-//!                 other: vec![<expr for &other.x>]
-//!                }])
+//! EnumMatching(
+//!     1,
+//!     <ast::Variant for C1>,
+//!     vec![FieldInfo {
+//!         span: <span of x>,
+//!         name: Some(<ident of x>),
+//!         self_: <expr for &self.x>,
+//!         other: vec![<expr for &other.x>],
+//!     }],
+//! )
 //! ```
 //!
 //! For the tags,
 //!
 //! ```text
 //! EnumTag(
-//!     &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
+//!     &[<ident of self tag>, <ident of other tag>],
+//!     <expr to combine with>,
+//! )
 //! ```
+//!
 //! Note that this setup doesn't allow for the brute-force "match every variant
 //! against every other variant" approach, which is bad because it produces a
 //! quadratic amount of code (see #15375).
@@ -154,9 +165,13 @@
 //!
 //! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
 //!
-//! StaticEnum(<ast::EnumDef of C>,
-//!            vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
-//!                 (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
+//! StaticEnum(
+//!     <ast::EnumDef of C>,
+//!     vec![
+//!         (<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
+//!         (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)])),
+//!     ],
+//! )
 //! ```
 
 pub use StaticFields::*;
@@ -522,7 +537,10 @@ impl<'a> TraitDef<'a> {
     /// Given that we are deriving a trait `DerivedTrait` for a type like:
     ///
     /// ```ignore (only-for-syntax-highlight)
-    /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
+    /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
+    /// where
+    ///     C: WhereTrait,
+    /// {
     ///     a: A,
     ///     b: B::Item,
     ///     b1: <B as DeclaredTrait>::Item,
@@ -535,12 +553,13 @@ impl<'a> TraitDef<'a> {
     /// create an impl like:
     ///
     /// ```ignore (only-for-syntax-highlight)
-    /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
-    ///     C:                       WhereTrait,
+    /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
+    /// where
+    ///     C: WhereTrait,
     ///     A: DerivedTrait + B1 + ... + BN,
     ///     B: DerivedTrait + B1 + ... + BN,
     ///     C: DerivedTrait + B1 + ... + BN,
-    ///     B::Item:                 DerivedTrait + B1 + ... + BN,
+    ///     B::Item: DerivedTrait + B1 + ... + BN,
     ///     <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
     ///     ...
     /// {
@@ -676,65 +695,59 @@ impl<'a> TraitDef<'a> {
             }
         }));
 
-        {
-            // Extra scope required here so ty_params goes out of scope before params is moved
-
-            let mut ty_params = params
-                .iter()
-                .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
-                .peekable();
-
-            if ty_params.peek().is_some() {
-                let ty_param_names: Vec<Symbol> =
-                    ty_params.map(|ty_param| ty_param.ident.name).collect();
-
-                for field_ty in field_tys {
-                    let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
-
-                    for field_ty_param in field_ty_params {
-                        // if we have already handled this type, skip it
-                        if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
-                            && let [sole_segment] = &*p.segments
-                            && ty_param_names.contains(&sole_segment.ident.name)
-                        {
-                            continue;
-                        }
-                        let mut bounds: Vec<_> = self
-                            .additional_bounds
-                            .iter()
-                            .map(|p| {
-                                cx.trait_bound(
-                                    p.to_path(cx, self.span, type_ident, generics),
-                                    self.is_const,
-                                )
-                            })
-                            .collect();
-
-                        // Require the current trait.
-                        if !self.skip_path_as_bound {
-                            bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
-                        }
+        let ty_param_names: Vec<Symbol> = params
+            .iter()
+            .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
+            .map(|ty_param| ty_param.ident.name)
+            .collect();
 
-                        // Add a `Copy` bound if required.
-                        if is_packed && self.needs_copy_as_bound_if_packed {
-                            let p = deriving::path_std!(marker::Copy);
-                            bounds.push(cx.trait_bound(
+        if !ty_param_names.is_empty() {
+            for field_ty in field_tys {
+                let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
+
+                for field_ty_param in field_ty_params {
+                    // if we have already handled this type, skip it
+                    if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
+                        && let [sole_segment] = &*p.segments
+                        && ty_param_names.contains(&sole_segment.ident.name)
+                    {
+                        continue;
+                    }
+                    let mut bounds: Vec<_> = self
+                        .additional_bounds
+                        .iter()
+                        .map(|p| {
+                            cx.trait_bound(
                                 p.to_path(cx, self.span, type_ident, generics),
                                 self.is_const,
-                            ));
-                        }
+                            )
+                        })
+                        .collect();
 
-                        if !bounds.is_empty() {
-                            let predicate = ast::WhereBoundPredicate {
-                                span: self.span,
-                                bound_generic_params: field_ty_param.bound_generic_params,
-                                bounded_ty: field_ty_param.ty,
-                                bounds,
-                            };
+                    // Require the current trait.
+                    if !self.skip_path_as_bound {
+                        bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
+                    }
 
-                            let predicate = ast::WherePredicate::BoundPredicate(predicate);
-                            where_clause.predicates.push(predicate);
-                        }
+                    // Add a `Copy` bound if required.
+                    if is_packed && self.needs_copy_as_bound_if_packed {
+                        let p = deriving::path_std!(marker::Copy);
+                        bounds.push(cx.trait_bound(
+                            p.to_path(cx, self.span, type_ident, generics),
+                            self.is_const,
+                        ));
+                    }
+
+                    if !bounds.is_empty() {
+                        let predicate = ast::WhereBoundPredicate {
+                            span: self.span,
+                            bound_generic_params: field_ty_param.bound_generic_params,
+                            bounded_ty: field_ty_param.ty,
+                            bounds,
+                        };
+
+                        let predicate = ast::WherePredicate::BoundPredicate(predicate);
+                        where_clause.predicates.push(predicate);
                     }
                 }
             }
@@ -1026,6 +1039,7 @@ impl<'a> MethodDef<'a> {
     }
 
     /// The normal case uses field access.
+    ///
     /// ```
     /// #[derive(PartialEq)]
     /// # struct Dummy;
@@ -1038,10 +1052,12 @@ impl<'a> MethodDef<'a> {
     ///     }
     /// }
     /// ```
+    ///
     /// But if the struct is `repr(packed)`, we can't use something like
     /// `&self.x` because that might cause an unaligned ref. So for any trait
     /// method that takes a reference, we use a local block to force a copy.
     /// This requires that the field impl `Copy`.
+    ///
     /// ```rust,ignore (example)
     /// # struct A { x: u8, y: u8 }
     /// impl PartialEq for A {
@@ -1053,7 +1069,7 @@ impl<'a> MethodDef<'a> {
     /// impl Hash for A {
     ///     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
     ///         ::core::hash::Hash::hash(&{ self.x }, state);
-    ///         ::core::hash::Hash::hash(&{ self.y }, state)
+    ///         ::core::hash::Hash::hash(&{ self.y }, state);
     ///     }
     /// }
     /// ```
@@ -1107,7 +1123,9 @@ impl<'a> MethodDef<'a> {
     ///     A2(i32)
     /// }
     /// ```
+    ///
     /// is equivalent to:
+    ///
     /// ```
     /// #![feature(core_intrinsics)]
     /// enum A {
@@ -1119,15 +1137,15 @@ impl<'a> MethodDef<'a> {
     ///     fn eq(&self, other: &A) -> bool {
     ///         let __self_tag = ::core::intrinsics::discriminant_value(self);
     ///         let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-    ///         __self_tag == __arg1_tag &&
-    ///             match (self, other) {
-    ///                 (A::A2(__self_0), A::A2(__arg1_0)) =>
-    ///                     *__self_0 == *__arg1_0,
+    ///         __self_tag == __arg1_tag
+    ///             && match (self, other) {
+    ///                 (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
     ///                 _ => true,
     ///             }
     ///     }
     /// }
     /// ```
+    ///
     /// Creates a tag check combined with a match for a tuple of all
     /// `selflike_args`, with an arm for each variant with fields, possibly an
     /// arm for each fieldless variant (if `unify_fieldless_variants` is not
@@ -1349,7 +1367,7 @@ impl<'a> MethodDef<'a> {
         //          (Variant1, Variant1, ...) => Body1
         //          (Variant2, Variant2, ...) => Body2,
         //          ...
-        //          _ => ::core::intrinsics::unreachable()
+        //          _ => ::core::intrinsics::unreachable(),
         //      }
         let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| {
             let match_arg = if selflike_args.len() == 1 {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index f16fe372a92..c0f6e7cb7b0 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1889,37 +1889,14 @@ fn add_linked_symbol_object(
         return;
     };
 
-    // NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
-    // so add an empty section.
     if file.format() == object::BinaryFormat::Coff {
+        // NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
+        // so add an empty section.
         file.add_section(Vec::new(), ".text".into(), object::SectionKind::Text);
 
         // We handle the name decoration of COFF targets in `symbol_export.rs`, so disable the
         // default mangler in `object` crate.
         file.set_mangling(object::write::Mangling::None);
-
-        // Add feature flags to the object file. On MSVC this is optional but LLD will complain if
-        // not present.
-        let mut feature = 0;
-
-        if file.architecture() == object::Architecture::I386 {
-            // Indicate that all SEH handlers are registered in .sxdata section.
-            // We don't have generate any code, so we don't need .sxdata section but LLD still
-            // expects us to set this bit (see #96498).
-            // Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
-            feature |= 1;
-        }
-
-        file.add_symbol(object::write::Symbol {
-            name: "@feat.00".into(),
-            value: feature,
-            size: 0,
-            kind: object::SymbolKind::Data,
-            scope: object::SymbolScope::Compilation,
-            weak: false,
-            section: object::write::SymbolSection::Absolute,
-            flags: object::SymbolFlags::None,
-        });
     }
 
     for (sym, kind) in symbols.iter() {
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index c6f4bd35e29..cb60ed729c1 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -228,6 +228,35 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
     if sess.target.is_like_osx {
         file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
     }
+    if binary_format == BinaryFormat::Coff {
+        // Disable the default mangler to avoid mangling the special "@feat.00" symbol name.
+        let original_mangling = file.mangling();
+        file.set_mangling(object::write::Mangling::None);
+
+        let mut feature = 0;
+
+        if file.architecture() == object::Architecture::I386 {
+            // When linking with /SAFESEH on x86, lld requires that all linker inputs be marked as
+            // safe exception handling compatible. Metadata files masquerade as regular COFF
+            // objects and are treated as linker inputs, despite containing no actual code. Thus,
+            // they still need to be marked as safe exception handling compatible. See #96498.
+            // Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+            feature |= 1;
+        }
+
+        file.add_symbol(object::write::Symbol {
+            name: "@feat.00".into(),
+            value: feature,
+            size: 0,
+            kind: object::SymbolKind::Data,
+            scope: object::SymbolScope::Compilation,
+            weak: false,
+            section: object::write::SymbolSection::Absolute,
+            flags: object::SymbolFlags::None,
+        });
+
+        file.set_mangling(original_mangling);
+    }
     let e_flags = match architecture {
         Architecture::Mips => {
             let arch = match sess.target.options.cpu.as_ref() {
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index e401f6bbcbf..5900c764073 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
-use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Mutability};
+use rustc_hir::{CoroutineKind, CoroutineSource, Mutability};
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
 use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
@@ -560,9 +560,9 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &
 
 fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
     match coroutine_kind {
-        Some(CoroutineKind::Async(AsyncCoroutineKind::Block)) => "async_block",
-        Some(CoroutineKind::Async(AsyncCoroutineKind::Closure)) => "async_closure",
-        Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) => "async_fn",
+        Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block",
+        Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure",
+        Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn",
         Some(CoroutineKind::Coroutine) => "coroutine",
         None => "closure",
     }
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index baf6b19d3f9..13a3f432b03 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -342,6 +342,19 @@ const CSKY_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("hard-float-abi", Some(sym::csky_target_feature)),
     // tidy-alphabetical-end
 ];
+
+const LOONGARCH_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    // tidy-alphabetical-start
+    ("d", Some(sym::loongarch_target_feature)),
+    ("f", Some(sym::loongarch_target_feature)),
+    ("lasx", Some(sym::loongarch_target_feature)),
+    ("lbt", Some(sym::loongarch_target_feature)),
+    ("lsx", Some(sym::loongarch_target_feature)),
+    ("lvz", Some(sym::loongarch_target_feature)),
+    ("ual", Some(sym::loongarch_target_feature)),
+    // tidy-alphabetical-end
+];
+
 /// When rustdoc is running, provide a list of all known features so that all their respective
 /// primitives may be documented.
 ///
@@ -358,6 +371,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol
         .chain(WASM_ALLOWED_FEATURES.iter())
         .chain(BPF_ALLOWED_FEATURES.iter())
         .chain(CSKY_ALLOWED_FEATURES)
+        .chain(LOONGARCH_ALLOWED_FEATURES)
         .cloned()
 }
 
@@ -373,6 +387,7 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
         "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
         "bpf" => BPF_ALLOWED_FEATURES,
         "csky" => CSKY_ALLOWED_FEATURES,
+        "loongarch64" => LOONGARCH_ALLOWED_FEATURES,
         _ => &[],
     }
 }
@@ -445,6 +460,7 @@ pub fn from_target_feature(
                 Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
                 Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
                 Some(sym::csky_target_feature) => rust_features.csky_target_feature,
+                Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 1202b0030ca..ec0af79459c 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1010,7 +1010,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // Just make this an efficient immediate.
             // Note that not calling `layout_of` here does have one real consequence:
             // if the type is too big, we'll only notice this when the local is actually initialized,
-            // which is a bit too late -- we should ideally notice this alreayd here, when the memory
+            // which is a bit too late -- we should ideally notice this already here, when the memory
             // is conceptually allocated. But given how rare that error is and that this is a hot function,
             // we accept this downside for now.
             Operand::Immediate(Immediate::Uninit)
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 616fab8fe7d..40183baccf8 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -360,7 +360,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
 pub struct Coroutine(pub hir::CoroutineKind);
 impl<'tcx> NonConstOp<'tcx> for Coroutine {
     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
-        if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 {
+        if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 {
             Status::Unstable(sym::const_async_blocks)
         } else {
             Status::Forbidden
@@ -372,8 +372,8 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind());
-        if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 {
+        let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
+        if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 {
             ccx.tcx.sess.create_feature_err(
                 errors::UnallowedOpInConstContext { span, msg },
                 sym::const_async_blocks,
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index d3bd3244a52..39462112dc2 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -1,5 +1,6 @@
 driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
 driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
+driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly
 driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
 
 driver_impl_ice_flags = compiler flags: {$flags}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 7e4a7d93210..331843ab051 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -60,7 +60,7 @@ use std::path::PathBuf;
 use std::process::{self, Command, Stdio};
 use std::str;
 use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::OnceLock;
+use std::sync::{Arc, OnceLock};
 use std::time::{Instant, SystemTime};
 use time::OffsetDateTime;
 
@@ -223,11 +223,18 @@ pub struct RunCompiler<'a, 'b> {
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
     make_codegen_backend:
         Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
+    using_internal_features: Arc<std::sync::atomic::AtomicBool>,
 }
 
 impl<'a, 'b> RunCompiler<'a, 'b> {
     pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
-        Self { at_args, callbacks, file_loader: None, make_codegen_backend: None }
+        Self {
+            at_args,
+            callbacks,
+            file_loader: None,
+            make_codegen_backend: None,
+            using_internal_features: Arc::default(),
+        }
     }
 
     /// Set a custom codegen backend.
@@ -259,9 +266,23 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
         self
     }
 
+    /// Set the session-global flag that checks whether internal features have been used,
+    /// suppressing the message about submitting an issue in ICEs when enabled.
+    #[must_use]
+    pub fn set_using_internal_features(mut self, using_internal_features: Arc<AtomicBool>) -> Self {
+        self.using_internal_features = using_internal_features;
+        self
+    }
+
     /// Parse args and run the compiler.
     pub fn run(self) -> interface::Result<()> {
-        run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend)
+        run_compiler(
+            self.at_args,
+            self.callbacks,
+            self.file_loader,
+            self.make_codegen_backend,
+            self.using_internal_features,
+        )
     }
 }
 
@@ -272,6 +293,7 @@ fn run_compiler(
     make_codegen_backend: Option<
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
+    using_internal_features: Arc<std::sync::atomic::AtomicBool>,
 ) -> interface::Result<()> {
     let mut early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
 
@@ -316,6 +338,7 @@ fn run_compiler(
         override_queries: None,
         make_codegen_backend,
         registry: diagnostics_registry(),
+        using_internal_features,
         expanded_args: args,
     };
 
@@ -1333,8 +1356,12 @@ fn ice_path() -> &'static Option<PathBuf> {
 /// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
 /// extra_info.
 ///
+/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to
+/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering
+/// internal features.
+///
 /// A custom rustc driver can skip calling this to set up a custom ICE hook.
-pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) {
+pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) -> Arc<AtomicBool> {
     // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
     // full backtraces. When a compiler ICE happens, we want to gather
     // as much information as possible to present in the issue opened
@@ -1345,6 +1372,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
         std::env::set_var("RUST_BACKTRACE", "full");
     }
 
+    let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
+    let using_internal_features_hook = using_internal_features.clone();
     panic::update_hook(Box::new(
         move |default_hook: &(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static),
               info: &PanicInfo<'_>| {
@@ -1394,9 +1423,11 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
             }
 
             // Print the ICE message
-            report_ice(info, bug_report_url, extra_info);
+            report_ice(info, bug_report_url, extra_info, &using_internal_features_hook);
         },
     ));
+
+    using_internal_features
 }
 
 /// Prints the ICE message, including query stack, but without backtrace.
@@ -1405,7 +1436,12 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
 ///
 /// When `install_ice_hook` is called, this function will be called as the panic
 /// hook.
-fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) {
+fn report_ice(
+    info: &panic::PanicInfo<'_>,
+    bug_report_url: &str,
+    extra_info: fn(&Handler),
+    using_internal_features: &AtomicBool,
+) {
     let fallback_bundle =
         rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
     let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
@@ -1422,7 +1458,11 @@ fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(
         handler.emit_err(session_diagnostics::Ice);
     }
 
-    handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
+    if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) {
+        handler.emit_note(session_diagnostics::IceBugReportInternalFeature);
+    } else {
+        handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
+    }
 
     let version = util::version_str!().unwrap_or("unknown_version");
     let triple = config::host_triple();
@@ -1506,7 +1546,7 @@ pub fn main() -> ! {
     init_rustc_env_logger(&handler);
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
-    install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
+    let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
     let exit_code = catch_with_exit_code(|| {
         let args = env::args_os()
             .enumerate()
@@ -1516,7 +1556,9 @@ pub fn main() -> ! {
                 })
             })
             .collect::<Vec<_>>();
-        RunCompiler::new(&args, &mut callbacks).run()
+        RunCompiler::new(&args, &mut callbacks)
+            .set_using_internal_features(using_internal_features)
+            .run()
     });
 
     if let Some(format) = callbacks.time_passes {
diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs
index 442989f8de8..2b31fdd77cc 100644
--- a/compiler/rustc_driver_impl/src/session_diagnostics.rs
+++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs
@@ -43,6 +43,10 @@ pub(crate) struct IceBugReport<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(driver_impl_ice_bug_report_internal_feature)]
+pub(crate) struct IceBugReportInternalFeature;
+
+#[derive(Diagnostic)]
 #[diag(driver_impl_ice_version)]
 pub(crate) struct IceVersion<'a> {
     pub version: &'a str,
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index b73c7593381..bef48765937 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -35,7 +35,7 @@ pub struct StripUnconfigured<'a> {
     pub lint_node_id: NodeId,
 }
 
-pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
+pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features {
     fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> {
         if attr.has_name(sym::feature)
             && let Some(list) = attr.meta_item_list()
@@ -167,6 +167,15 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
             // If the declared feature is unstable, record it.
             if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) {
                 (f.set_enabled)(&mut features);
+                // When the ICE comes from core, alloc or std (approximation of the standard library), there's a chance
+                // that the person hitting the ICE may be using -Zbuild-std or similar with an untested target.
+                // The bug is probably in the standard library and not the compiler in that case, but that doesn't
+                // really matter - we want a bug report.
+                if features.internal(name)
+                    && ![sym::core, sym::alloc, sym::std].contains(&crate_name)
+                {
+                    sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
+                }
                 features.set_declared_lang_feature(name, mi.span(), None);
                 continue;
             }
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 8185a8a3e43..695de54eefa 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -288,6 +288,7 @@ declare_features! (
     (unstable, csky_target_feature, "1.73.0", Some(44839), None),
     (unstable, ermsb_target_feature, "1.49.0", Some(44839), None),
     (unstable, hexagon_target_feature, "1.27.0", Some(44839), None),
+    (unstable, loongarch_target_feature, "1.73.0", Some(44839), None),
     (unstable, mips_target_feature, "1.27.0", Some(44839), None),
     (unstable, powerpc_target_feature, "1.27.0", Some(44839), None),
     (unstable, riscv_target_feature, "1.45.0", Some(44839), None),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index f8d55192a37..259af4f565b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1511,7 +1511,7 @@ impl<'hir> Body<'hir> {
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum CoroutineKind {
     /// An explicit `async` block or the body of an async function.
-    Async(AsyncCoroutineKind),
+    Async(CoroutineSource),
 
     /// A coroutine literal created via a `yield` inside a closure.
     Coroutine,
@@ -1520,56 +1520,45 @@ pub enum CoroutineKind {
 impl fmt::Display for CoroutineKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            CoroutineKind::Async(k) => fmt::Display::fmt(k, f),
+            CoroutineKind::Async(k) => {
+                if f.alternate() {
+                    f.write_str("`async` ")?;
+                } else {
+                    f.write_str("async ")?
+                }
+                k.fmt(f)
+            }
             CoroutineKind::Coroutine => f.write_str("coroutine"),
         }
     }
 }
 
-impl CoroutineKind {
-    pub fn descr(&self) -> &'static str {
-        match self {
-            CoroutineKind::Async(ask) => ask.descr(),
-            CoroutineKind::Coroutine => "coroutine",
-        }
-    }
-}
-
-/// In the case of a coroutine created as part of an async construct,
-/// which kind of async construct caused it to be created?
+/// In the case of a coroutine created as part of an async/gen construct,
+/// which kind of async/gen construct caused it to be created?
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
 #[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
-pub enum AsyncCoroutineKind {
-    /// An explicit `async` block written by the user.
+pub enum CoroutineSource {
+    /// An explicit `async`/`gen` block written by the user.
     Block,
 
-    /// An explicit `async` closure written by the user.
+    /// An explicit `async`/`gen` closure written by the user.
     Closure,
 
-    /// The `async` block generated as the body of an async function.
+    /// The `async`/`gen` block generated as the body of an async/gen function.
     Fn,
 }
 
-impl fmt::Display for AsyncCoroutineKind {
+impl fmt::Display for CoroutineSource {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match self {
-            AsyncCoroutineKind::Block => "async block",
-            AsyncCoroutineKind::Closure => "async closure body",
-            AsyncCoroutineKind::Fn => "async fn body",
-        })
-    }
-}
-
-impl AsyncCoroutineKind {
-    pub fn descr(&self) -> &'static str {
         match self {
-            AsyncCoroutineKind::Block => "`async` block",
-            AsyncCoroutineKind::Closure => "`async` closure body",
-            AsyncCoroutineKind::Fn => "`async fn` body",
+            CoroutineSource::Block => "block",
+            CoroutineSource::Closure => "closure body",
+            CoroutineSource::Fn => "fn body",
         }
+        .fmt(f)
     }
 }
 
@@ -3781,6 +3770,7 @@ impl<'hir> Node<'hir> {
                 ItemKind::TyAlias(ty, _)
                 | ItemKind::Static(ty, _, _)
                 | ItemKind::Const(ty, _, _) => Some(ty),
+                ItemKind::Impl(impl_item) => Some(&impl_item.self_ty),
                 _ => None,
             },
             Node::TraitItem(it) => match it.kind {
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index cdfc67d5740..c8ac95e2994 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -210,6 +210,7 @@ language_item_table! {
 
     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
 
+    Iterator,                sym::iterator,            iterator_trait,             Target::Trait,          GenericRequirement::Exact(0);
     Future,                  sym::future_trait,        future_trait,               Target::Trait,          GenericRequirement::Exact(0);
     CoroutineState,          sym::coroutine_state,     gen_state,                  Target::Enum,           GenericRequirement::None;
     Coroutine,               sym::coroutine,           gen_trait,                  Target::Trait,          GenericRequirement::Minimum(1);
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 6bf6650986a..e8d9918be22 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -72,6 +72,12 @@ hir_analysis_copy_impl_on_type_with_dtor =
     the trait `Copy` cannot be implemented for this type; the type has a destructor
     .label = `Copy` not allowed on types with destructors
 
+hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type, not `{$self_ty}`
+    .label = can't implement cross-crate trait with a default impl for non-struct/enum type
+
+hir_analysis_cross_crate_traits_defined = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type defined in the current crate
+    .label = can't implement cross-crate trait for type in another crate
+
 hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions
     .note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
     .coercions_note = currently, {$number} fields need coercions: {$coercions}
@@ -237,6 +243,28 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
 
 hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
 
+hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
+
+hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
+
+hir_analysis_only_current_traits_label = impl doesn't use only types from inside the current crate
+
+hir_analysis_only_current_traits_name = this is not defined in the current crate because {$name} are always foreign
+
+hir_analysis_only_current_traits_note = define and implement a trait or new type instead
+
+hir_analysis_only_current_traits_opaque = type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
+
+hir_analysis_only_current_traits_outside = only traits defined in the current crate can be implemented for types defined outside of the crate
+
+hir_analysis_only_current_traits_pointer = `{$pointer}` is not defined in the current crate because raw pointers are always foreign
+
+hir_analysis_only_current_traits_pointer_sugg = consider introducing a new wrapper type
+
+hir_analysis_only_current_traits_primitive = only traits defined in the current crate can be implemented for primitive types
+
+hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
+
 hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
     .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
 
@@ -326,6 +354,9 @@ hir_analysis_trait_object_declared_with_no_traits =
     at least one trait is required for an object type
     .alias_span = this alias does not contain a trait
 
+hir_analysis_traits_with_defualt_impl = traits with a default impl, like `{$traits}`, cannot be implemented for {$problematic_kind} `{$self_ty}`
+    .note = a trait object implements `{$traits}` if and only if `{$traits}` is one of the trait object's trait bounds
+
 hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number}
     .label = needs exactly one variant, but has {$number}
     .many_label = too many variants in `{$path}`
@@ -339,6 +370,16 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de
     .label = needs at most one field with non-trivial size or alignment, but has {$field_count}
     .labels = this field has non-zero size or requires alignment
 
+hir_analysis_ty_param_first_local = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
+    .label = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
+    .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
+    .case_note = in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
+
+hir_analysis_ty_param_some = type parameter `{$param_ty}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param_ty}>`)
+    .label = type parameter `{$param_ty}` must be used as the type parameter for some local type
+    .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
+    .only_note = only traits defined in the current crate can be implemented for a type parameter
+
 hir_analysis_type_of = {$type_of}
 
 hir_analysis_typeof_reserved_keyword_used =
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 360d31b863c..e61ca232de6 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -128,7 +128,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
 
         let param_env = tcx.param_env(item_def_id);
         for field in &def.non_enum_variant().fields {
-            let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, args));
+            let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args))
+            else {
+                tcx.sess.delay_span_bug(span, "could not normalize field type");
+                continue;
+            };
 
             if !allowed_union_field(field_ty, tcx, param_env) {
                 let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index faddb0c3829..7eeb7837467 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -2,8 +2,7 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, DelayDm};
-use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_errors::{DelayDm, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_middle::ty::util::CheckRegions;
 use rustc_middle::ty::GenericArgs;
@@ -17,6 +16,8 @@ use rustc_span::Span;
 use rustc_trait_selection::traits;
 use std::ops::ControlFlow;
 
+use crate::errors;
+
 #[instrument(skip(tcx), level = "debug")]
 pub(crate) fn orphan_check_impl(
     tcx: TyCtxt<'_>,
@@ -259,49 +260,30 @@ fn do_orphan_check_impl<'tcx>(
             match local_impl {
                 LocalImpl::Allow => {}
                 LocalImpl::Disallow { problematic_kind } => {
-                    let msg = format!(
-                        "traits with a default impl, like `{trait}`, \
-                                cannot be implemented for {problematic_kind} `{self_ty}`",
-                        trait = tcx.def_path_str(trait_def_id),
-                    );
-                    let label = format!(
-                        "a trait object implements `{trait}` if and only if `{trait}` \
-                                is one of the trait object's trait bounds",
-                        trait = tcx.def_path_str(trait_def_id),
-                    );
-                    let sp = tcx.def_span(def_id);
-                    let reported =
-                        struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
-                    return Err(reported);
+                    return Err(tcx.sess.emit_err(errors::TraitsWithDefaultImpl {
+                        span: tcx.def_span(def_id),
+                        traits: tcx.def_path_str(trait_def_id),
+                        problematic_kind,
+                        self_ty,
+                    }));
                 }
             }
         } else {
-            if let Some((msg, label)) = match nonlocal_impl {
-                NonlocalImpl::Allow => None,
-                NonlocalImpl::DisallowBecauseNonlocal => Some((
-                    format!(
-                        "cross-crate traits with a default impl, like `{}`, \
-                                can only be implemented for a struct/enum type \
-                                defined in the current crate",
-                        tcx.def_path_str(trait_def_id)
-                    ),
-                    "can't implement cross-crate trait for type in another crate",
-                )),
-                NonlocalImpl::DisallowOther => Some((
-                    format!(
-                        "cross-crate traits with a default impl, like `{}`, can \
-                                only be implemented for a struct/enum type, not `{}`",
-                        tcx.def_path_str(trait_def_id),
-                        self_ty
-                    ),
-                    "can't implement cross-crate trait with a default impl for \
-                            non-struct/enum type",
-                )),
-            } {
-                let sp = tcx.def_span(def_id);
-                let reported =
-                    struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
-                return Err(reported);
+            match nonlocal_impl {
+                NonlocalImpl::Allow => {}
+                NonlocalImpl::DisallowBecauseNonlocal => {
+                    return Err(tcx.sess.emit_err(errors::CrossCrateTraitsDefined {
+                        span: tcx.def_span(def_id),
+                        traits: tcx.def_path_str(trait_def_id),
+                    }));
+                }
+                NonlocalImpl::DisallowOther => {
+                    return Err(tcx.sess.emit_err(errors::CrossCrateTraits {
+                        span: tcx.def_span(def_id),
+                        traits: tcx.def_path_str(trait_def_id),
+                        self_ty,
+                    }));
+                }
             }
         }
     }
@@ -322,19 +304,18 @@ fn emit_orphan_check_error<'tcx>(
     let self_ty = trait_ref.self_ty();
     Err(match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
-            let msg = match self_ty.kind() {
-                ty::Adt(..) => "can be implemented for types defined outside of the crate",
-                _ if self_ty.is_primitive() => "can be implemented for primitive types",
-                _ => "can be implemented for arbitrary types",
-            };
-            let mut err = struct_span_err!(
-                tcx.sess,
-                sp,
-                E0117,
-                "only traits defined in the current crate {msg}"
-            );
-            err.span_label(sp, "impl doesn't use only types from inside the current crate");
+            let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) =
+                (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
+            let mut sugg = None;
             for &(mut ty, is_target_ty) in &tys {
+                let span = if is_target_ty {
+                    // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
+                    self_ty_span
+                } else {
+                    // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
+                    trait_span
+                };
+
                 ty = tcx.erase_regions(ty);
                 ty = match ty.kind() {
                     // Remove the type arguments from the output, as they are not relevant.
@@ -345,50 +326,103 @@ fn emit_orphan_check_error<'tcx>(
                     ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
                     _ => ty,
                 };
-                let msg = |ty: &str, postfix: &str| {
-                    format!("{ty} is not defined in the current crate{postfix}")
-                };
 
-                let this = |name: &str| {
-                    if !trait_ref.def_id.is_local() && !is_target_ty {
-                        msg("this", " because this is a foreign trait")
+                fn push_to_foreign_or_name<'tcx>(
+                    is_foreign: bool,
+                    foreign: &mut Vec<errors::OnlyCurrentTraitsForeign>,
+                    name: &mut Vec<errors::OnlyCurrentTraitsName<'tcx>>,
+                    span: Span,
+                    sname: &'tcx str,
+                ) {
+                    if is_foreign {
+                        foreign.push(errors::OnlyCurrentTraitsForeign { span })
                     } else {
-                        msg("this", &format!(" because {name} are always foreign"))
+                        name.push(errors::OnlyCurrentTraitsName { span, name: sname });
+                    }
+                }
+
+                let is_foreign = !trait_ref.def_id.is_local() && !is_target_ty;
+
+                match &ty.kind() {
+                    ty::Slice(_) => {
+                        push_to_foreign_or_name(
+                            is_foreign,
+                            &mut foreign,
+                            &mut name,
+                            span,
+                            "slices",
+                        );
+                    }
+                    ty::Array(..) => {
+                        push_to_foreign_or_name(
+                            is_foreign,
+                            &mut foreign,
+                            &mut name,
+                            span,
+                            "arrays",
+                        );
+                    }
+                    ty::Tuple(..) => {
+                        push_to_foreign_or_name(
+                            is_foreign,
+                            &mut foreign,
+                            &mut name,
+                            span,
+                            "tuples",
+                        );
                     }
-                };
-                let msg = match &ty.kind() {
-                    ty::Slice(_) => this("slices"),
-                    ty::Array(..) => this("arrays"),
-                    ty::Tuple(..) => this("tuples"),
                     ty::Alias(ty::Opaque, ..) => {
-                        "type alias impl trait is treated as if it were foreign, \
-                        because its hidden type could be from a foreign crate"
-                            .to_string()
+                        opaque.push(errors::OnlyCurrentTraitsOpaque { span })
                     }
                     ty::RawPtr(ptr_ty) => {
-                        emit_newtype_suggestion_for_raw_ptr(
-                            full_impl_span,
-                            self_ty,
-                            self_ty_span,
-                            ptr_ty,
-                            &mut err,
-                        );
-
-                        msg(&format!("`{ty}`"), " because raw pointers are always foreign")
+                        if !self_ty.has_param() {
+                            let mut_key = ptr_ty.mutbl.prefix_str();
+                            sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
+                                wrapper_span: self_ty_span,
+                                struct_span: full_impl_span.shrink_to_lo(),
+                                mut_key,
+                                ptr_ty: ptr_ty.ty,
+                            });
+                        }
+                        pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
                     }
-                    _ => msg(&format!("`{ty}`"), ""),
-                };
-
-                if is_target_ty {
-                    // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
-                    err.span_label(self_ty_span, msg);
-                } else {
-                    // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
-                    err.span_label(trait_span, msg);
+                    _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }),
                 }
             }
-            err.note("define and implement a trait or new type instead");
-            err.emit()
+
+            let err_struct = match self_ty.kind() {
+                ty::Adt(..) => errors::OnlyCurrentTraits::Outside {
+                    span: sp,
+                    note: (),
+                    opaque,
+                    foreign,
+                    name,
+                    pointer,
+                    ty: ty_diag,
+                    sugg,
+                },
+                _ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive {
+                    span: sp,
+                    note: (),
+                    opaque,
+                    foreign,
+                    name,
+                    pointer,
+                    ty: ty_diag,
+                    sugg,
+                },
+                _ => errors::OnlyCurrentTraits::Arbitrary {
+                    span: sp,
+                    note: (),
+                    opaque,
+                    foreign,
+                    name,
+                    pointer,
+                    ty: ty_diag,
+                    sugg,
+                },
+            };
+            tcx.sess.emit_err(err_struct)
         }
         traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
             let mut sp = sp;
@@ -399,85 +433,18 @@ fn emit_orphan_check_error<'tcx>(
             }
 
             match local_type {
-                Some(local_type) => struct_span_err!(
-                    tcx.sess,
-                    sp,
-                    E0210,
-                    "type parameter `{}` must be covered by another type \
-                    when it appears before the first local type (`{}`)",
-                    param_ty,
-                    local_type
-                )
-                .span_label(
-                    sp,
-                    format!(
-                        "type parameter `{param_ty}` must be covered by another type \
-                    when it appears before the first local type (`{local_type}`)"
-                    ),
-                )
-                .note(
-                    "implementing a foreign trait is only possible if at \
-                        least one of the types for which it is implemented is local, \
-                        and no uncovered type parameters appear before that first \
-                        local type",
-                )
-                .note(
-                    "in this case, 'before' refers to the following order: \
-                        `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
-                        where `T0` is the first and `Tn` is the last",
-                )
-                .emit(),
-                None => struct_span_err!(
-                    tcx.sess,
-                    sp,
-                    E0210,
-                    "type parameter `{}` must be used as the type parameter for some \
-                    local type (e.g., `MyStruct<{}>`)",
+                Some(local_type) => tcx.sess.emit_err(errors::TyParamFirstLocal {
+                    span: sp,
+                    note: (),
                     param_ty,
-                    param_ty
-                )
-                .span_label(
-                    sp,
-                    format!(
-                        "type parameter `{param_ty}` must be used as the type parameter for some \
-                    local type",
-                    ),
-                )
-                .note(
-                    "implementing a foreign trait is only possible if at \
-                        least one of the types for which it is implemented is local",
-                )
-                .note(
-                    "only traits defined in the current crate can be \
-                        implemented for a type parameter",
-                )
-                .emit(),
+                    local_type,
+                }),
+                None => tcx.sess.emit_err(errors::TyParamSome { span: sp, note: (), param_ty }),
             }
         }
     })
 }
 
-fn emit_newtype_suggestion_for_raw_ptr(
-    full_impl_span: Span,
-    self_ty: Ty<'_>,
-    self_ty_span: Span,
-    ptr_ty: &ty::TypeAndMut<'_>,
-    diag: &mut Diagnostic,
-) {
-    if !self_ty.has_param() {
-        let mut_key = ptr_ty.mutbl.prefix_str();
-        let msg_sugg = "consider introducing a new wrapper type".to_owned();
-        let sugg = vec![
-            (
-                full_impl_span.shrink_to_lo(),
-                format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
-            ),
-            (self_ty_span, "WrapperType".to_owned()),
-        ];
-        diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
-    }
-}
-
 /// Lint impls of auto traits if they are likely to have
 /// unsound or surprising effects on auto impls.
 fn lint_auto_trait_impl<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 189564d4e33..6a2db1d0627 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -683,7 +683,6 @@ pub(crate) struct SIMDFFIHighlyExperimental {
 }
 
 #[derive(Diagnostic)]
-
 pub enum ImplNotMarkedDefault {
     #[diag(hir_analysis_impl_not_marked_default, code = "E0520")]
     #[note]
@@ -1159,3 +1158,174 @@ pub struct ImplForTyRequires {
     pub trait_name: String,
     pub ty: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_traits_with_defualt_impl, code = "E0321")]
+#[note]
+pub struct TraitsWithDefaultImpl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub traits: String,
+    pub problematic_kind: &'a str,
+    pub self_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cross_crate_traits, code = "E0321")]
+pub struct CrossCrateTraits<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub traits: String,
+    pub self_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cross_crate_traits_defined, code = "E0321")]
+pub struct CrossCrateTraitsDefined {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub traits: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_ty_param_first_local, code = "E0210")]
+#[note]
+pub struct TyParamFirstLocal<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(hir_analysis_case_note)]
+    pub note: (),
+    pub param_ty: Ty<'a>,
+    pub local_type: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_ty_param_some, code = "E0210")]
+#[note]
+pub struct TyParamSome<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(hir_analysis_only_note)]
+    pub note: (),
+    pub param_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+pub enum OnlyCurrentTraits<'a> {
+    #[diag(hir_analysis_only_current_traits_outside, code = "E0117")]
+    Outside {
+        #[primary_span]
+        #[label(hir_analysis_only_current_traits_label)]
+        span: Span,
+        #[note(hir_analysis_only_current_traits_note)]
+        note: (),
+        #[subdiagnostic]
+        opaque: Vec<OnlyCurrentTraitsOpaque>,
+        #[subdiagnostic]
+        foreign: Vec<OnlyCurrentTraitsForeign>,
+        #[subdiagnostic]
+        name: Vec<OnlyCurrentTraitsName<'a>>,
+        #[subdiagnostic]
+        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+        #[subdiagnostic]
+        ty: Vec<OnlyCurrentTraitsTy<'a>>,
+        #[subdiagnostic]
+        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+    },
+    #[diag(hir_analysis_only_current_traits_primitive, code = "E0117")]
+    Primitive {
+        #[primary_span]
+        #[label(hir_analysis_only_current_traits_label)]
+        span: Span,
+        #[note(hir_analysis_only_current_traits_note)]
+        note: (),
+        #[subdiagnostic]
+        opaque: Vec<OnlyCurrentTraitsOpaque>,
+        #[subdiagnostic]
+        foreign: Vec<OnlyCurrentTraitsForeign>,
+        #[subdiagnostic]
+        name: Vec<OnlyCurrentTraitsName<'a>>,
+        #[subdiagnostic]
+        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+        #[subdiagnostic]
+        ty: Vec<OnlyCurrentTraitsTy<'a>>,
+        #[subdiagnostic]
+        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+    },
+    #[diag(hir_analysis_only_current_traits_arbitrary, code = "E0117")]
+    Arbitrary {
+        #[primary_span]
+        #[label(hir_analysis_only_current_traits_label)]
+        span: Span,
+        #[note(hir_analysis_only_current_traits_note)]
+        note: (),
+        #[subdiagnostic]
+        opaque: Vec<OnlyCurrentTraitsOpaque>,
+        #[subdiagnostic]
+        foreign: Vec<OnlyCurrentTraitsForeign>,
+        #[subdiagnostic]
+        name: Vec<OnlyCurrentTraitsName<'a>>,
+        #[subdiagnostic]
+        pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
+        #[subdiagnostic]
+        ty: Vec<OnlyCurrentTraitsTy<'a>>,
+        #[subdiagnostic]
+        sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_opaque)]
+pub struct OnlyCurrentTraitsOpaque {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_foreign)]
+pub struct OnlyCurrentTraitsForeign {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_name)]
+pub struct OnlyCurrentTraitsName<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_pointer)]
+pub struct OnlyCurrentTraitsPointer<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub pointer: Ty<'a>,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_only_current_traits_ty)]
+pub struct OnlyCurrentTraitsTy<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'a>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    hir_analysis_only_current_traits_pointer_sugg,
+    applicability = "maybe-incorrect"
+)]
+pub struct OnlyCurrentTraitsPointerSugg<'a> {
+    #[suggestion_part(code = "WrapperType")]
+    pub wrapper_span: Span,
+    #[suggestion_part(code = "struct WrapperType(*{mut_key}{ptr_ty});\n\n")]
+    pub struct_span: Span,
+    pub mut_key: &'a str,
+    pub ptr_ty: Ty<'a>,
+}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 0622aa2ee80..2b8219c01c7 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -182,13 +182,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
     }
 
     tcx.sess.track_errors(|| {
-        tcx.sess.time("impl_wf_inference", || {
-            tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module))
-        });
-    })?;
-
-    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));
+
             for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
                 tcx.ensure().coherent_trait(trait_def_id);
             }
@@ -205,15 +202,19 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
         })?;
     }
 
-    tcx.sess.time("wf_checking", || {
+    let errs = tcx.sess.time("wf_checking", || {
         tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
-    })?;
+    });
 
     // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
     tcx.sess.time("item_types_checking", || {
         tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
     });
 
+    // HACK: `check_mod_type_wf` may spuriously emit errors due to `delay_span_bug`, even if those errors
+    // only actually get emitted in `check_mod_item_types`.
+    errs?;
+
     if tcx.features().rustc_attrs {
         tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?;
     }
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 2b5f6fd214c..76bd370a641 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         if self.missing_lifetimes() { "lifetime" } else { "generic" }
     }
 
+    /// Returns true if the generic type is a trait
+    /// and is being referred to from one of its trait impls
+    fn is_in_trait_impl(&self) -> bool {
+        if self.tcx.is_trait(self.def_id) {
+            // Here we check if the reference to the generic type
+            // is from the 'of_trait' field of the enclosing impl
+
+            let parent = self.tcx.hir().get_parent(self.path_segment.hir_id);
+            let parent_item = self
+                .tcx
+                .hir()
+                .get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id);
+
+            // Get the HIR id of the trait ref
+            let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else {
+                return false;
+            };
+
+            // Get the HIR id of the 'of_trait' field of the impl
+            let hir::Node::Item(hir::Item {
+                kind:
+                    hir::ItemKind::Impl(hir::Impl {
+                        of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
+                        ..
+                    }),
+                ..
+            }) = parent_item
+            else {
+                return false;
+            };
+
+            // Check that trait is referred to from the of_trait field of impl
+            trait_ref_id == id_in_of_trait
+        } else {
+            false
+        }
+    }
+
     fn num_provided_args(&self) -> usize {
         if self.missing_lifetimes() {
             self.num_provided_lifetime_args()
@@ -955,20 +993,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         // If there is a single unbound associated type and a single excess generic param
         // suggest replacing the generic param with the associated type bound
         if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
-            let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
-            let suggestions = iter::zip(unused_generics, &unbound_types)
-                .map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = ")))
-                .collect::<Vec<_>>();
+            // Don't suggest if we're in a trait impl as
+            // that would result in invalid syntax (fixes #116464)
+            if !self.is_in_trait_impl() {
+                let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
+                let suggestions = iter::zip(unused_generics, &unbound_types)
+                    .map(|(potential, name)| {
+                        (potential.span().shrink_to_lo(), format!("{name} = "))
+                    })
+                    .collect::<Vec<_>>();
 
-            if !suggestions.is_empty() {
-                err.multipart_suggestion_verbose(
-                    format!(
-                        "replace the generic bound{s} with the associated type{s}",
-                        s = pluralize!(unbound_types.len())
-                    ),
-                    suggestions,
-                    Applicability::MaybeIncorrect,
-                );
+                if !suggestions.is_empty() {
+                    err.multipart_suggestion_verbose(
+                        format!(
+                            "replace the generic bound{s} with the associated type{s}",
+                            s = pluralize!(unbound_types.len())
+                        ),
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
         } else if remove_entire_generics {
             let span = self
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 5eb68cf6b28..6b6d1574b2b 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -305,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ) = (parent_node, callee_node)
         {
             let fn_decl_span = if hir.body(body).coroutine_kind
-                == Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure))
+                == Some(hir::CoroutineKind::Async(hir::CoroutineSource::Closure))
             {
                 // Actually need to unwrap one more layer of HIR to get to
                 // the _real_ closure...
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index a834ea15047..ee23f47c271 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -660,9 +660,21 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         } else {
             match self.try_coercion_cast(fcx) {
                 Ok(()) => {
-                    self.trivial_cast_lint(fcx);
-                    debug!(" -> CoercionCast");
-                    fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
+                    if self.expr_ty.is_unsafe_ptr() && self.cast_ty.is_unsafe_ptr() {
+                        // When casting a raw pointer to another raw pointer, we cannot convert the cast into
+                        // a coercion because the pointee types might only differ in regions, which HIR typeck
+                        // cannot distinguish. This would cause us to erroneously discard a cast which will
+                        // lead to a borrowck error like #113257.
+                        // We still did a coercion above to unify inference variables for `ptr as _` casts.
+                        // This does cause us to miss some trivial casts in the trival cast lint.
+                        debug!(" -> PointerCast");
+                    } else {
+                        self.trivial_cast_lint(fcx);
+                        debug!(" -> CoercionCast");
+                        fcx.typeck_results
+                            .borrow_mut()
+                            .set_coercion_cast(self.expr.hir_id.local_id);
+                    }
                 }
                 Err(_) => {
                     match self.do_check(fcx) {
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index cf8a4cafbb6..47bde21ceb2 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -636,7 +636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // In the case of the async block that we create for a function body,
                 // we expect the return type of the block to match that of the enclosing
                 // function.
-                Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn)) => {
+                Some(hir::CoroutineKind::Async(hir::CoroutineSource::Fn)) => {
                     debug!("closure is async fn body");
                     let def_id = self.tcx.hir().body_owner_def_id(body.id());
                     self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else(
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 65ec2f232ae..f379e8477e3 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -58,7 +58,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             || self.suggest_into(err, expr, expr_ty, expected)
             || self.suggest_floating_point_literal(err, expr, expected)
             || self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
-            || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty);
+            || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty)
+            || self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty);
 
         if !suggested {
             self.note_source_of_type_mismatch_constraint(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index afa5a3b9379..b5a07f0d3e9 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -26,7 +26,7 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
+    self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType,
 };
 use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
 use rustc_session::lint;
@@ -207,6 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) {
         debug!("fcx {}", self.tag());
 
+        // FIXME: is_identity being on `UserType` and not `Canonical<UserType>` is awkward
         if !canonical_user_type_annotation.is_identity() {
             self.typeck_results
                 .borrow_mut()
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 04220397872..ca7dc298de6 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -6,11 +6,12 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::Res;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    AsyncCoroutineKind, CoroutineKind, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath,
-    Stmt, StmtKind, TyKind, WherePredicate,
+    CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, Stmt,
+    StmtKind, TyKind, WherePredicate,
 };
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::traits::{self, StatementAsExpression};
@@ -535,7 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ty::Coroutine(def_id, ..)
                     if matches!(
                         self.tcx.coroutine_kind(def_id),
-                        Some(CoroutineKind::Async(AsyncCoroutineKind::Closure))
+                        Some(CoroutineKind::Async(CoroutineSource::Closure))
                     ) =>
                 {
                     errors::SuggestBoxing::AsyncBody
@@ -1738,4 +1739,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // If the field is hygienic it must come from the same syntax context.
             && self.tcx.def_ident_span(field.did).unwrap().normalize_to_macros_2_0().eq_ctxt(span)
     }
+
+    pub(crate) fn suggest_missing_unwrap_expect(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let ty::Adt(adt, args) = found.kind() else {
+            return false;
+        };
+        let ret_ty_matches = |diagnostic_item| {
+            let Some(sig) = self.body_fn_sig() else {
+                return false;
+            };
+            let ty::Adt(kind, _) = sig.output().kind() else {
+                return false;
+            };
+            self.tcx.is_diagnostic_item(diagnostic_item, kind.did())
+        };
+
+        // don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`,
+        // `None.unwrap()` etc.
+        let is_ctor = matches!(
+            expr.kind,
+            hir::ExprKind::Call(
+                hir::Expr {
+                    kind: hir::ExprKind::Path(hir::QPath::Resolved(
+                        None,
+                        hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
+                    )),
+                    ..
+                },
+                ..,
+            ) | hir::ExprKind::Path(hir::QPath::Resolved(
+                None,
+                hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
+            )),
+        );
+
+        let (article, kind, variant, sugg_operator) =
+            if self.tcx.is_diagnostic_item(sym::Result, adt.did()) {
+                ("a", "Result", "Err", ret_ty_matches(sym::Result))
+            } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) {
+                ("an", "Option", "None", ret_ty_matches(sym::Option))
+            } else {
+                return false;
+            };
+        if is_ctor || !self.can_coerce(args.type_at(0), expected) {
+            return false;
+        }
+
+        let (msg, sugg) = if sugg_operator {
+            (
+                format!(
+                    "use the `?` operator to extract the `{found}` value, propagating \
+                            {article} `{kind}::{variant}` value to the caller"
+                ),
+                "?",
+            )
+        } else {
+            (
+                format!(
+                    "consider using `{kind}::expect` to unwrap the `{found}` value, \
+                                panicking if the value is {article} `{kind}::{variant}`"
+                ),
+                ".expect(\"REASON\")",
+            )
+        };
+        err.span_suggestion_verbose(
+            expr.span.shrink_to_hi(),
+            msg,
+            sugg,
+            Applicability::HasPlaceholders,
+        );
+        return true;
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 41787ee2942..280dcae3451 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -152,7 +152,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 )
                 .into(),
             CanonicalVarKind::Effect => {
-                let vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+                let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
                 ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
                     .into()
             }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index ee13eb0271e..2a9e20b9f8f 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -320,7 +320,7 @@ impl<'tcx> InferCtxt<'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn unify_const_variable(
         &self,
-        target_vid: ty::ConstVid<'tcx>,
+        target_vid: ty::ConstVid,
         ct: ty::Const<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
@@ -381,7 +381,7 @@ impl<'tcx> InferCtxt<'tcx> {
     fn unify_effect_variable(
         &self,
         vid_is_expected: bool,
-        vid: ty::EffectVid<'tcx>,
+        vid: ty::EffectVid,
         val: EffectVarValue<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         self.inner
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index ba118f8110f..e4be435fded 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1584,14 +1584,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 target: &str,
                 types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
             ) {
-                for (key, values) in types.iter() {
+                for (kind, values) in types.iter() {
                     let count = values.len();
-                    let kind = key.descr();
                     for &sp in values {
                         err.span_label(
                             sp,
                             format!(
-                                "{}{} {}{}",
+                                "{}{} {:#}{}",
                                 if count == 1 { "the " } else { "one of the " },
                                 target,
                                 kind,
@@ -2952,17 +2951,19 @@ pub enum TyCategory {
     Foreign,
 }
 
-impl TyCategory {
-    fn descr(&self) -> &'static str {
+impl fmt::Display for TyCategory {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self::Closure => "closure",
-            Self::Opaque => "opaque type",
-            Self::OpaqueFuture => "future",
-            Self::Coroutine(gk) => gk.descr(),
-            Self::Foreign => "foreign type",
+            Self::Closure => "closure".fmt(f),
+            Self::Opaque => "opaque type".fmt(f),
+            Self::OpaqueFuture => "future".fmt(f),
+            Self::Coroutine(gk) => gk.fmt(f),
+            Self::Foreign => "foreign type".fmt(f),
         }
     }
+}
 
+impl TyCategory {
     pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
         match *ty.kind() {
             ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 0596ce373cf..35204478c54 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -42,7 +42,7 @@ pub struct TypeFreshener<'a, 'tcx> {
     ty_freshen_count: u32,
     const_freshen_count: u32,
     ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
-    const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
+    const_freshen_map: FxHashMap<ty::InferConst, ty::Const<'tcx>>,
 }
 
 impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
@@ -79,12 +79,12 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
     fn freshen_const<F>(
         &mut self,
         opt_ct: Option<ty::Const<'tcx>>,
-        key: ty::InferConst<'tcx>,
+        key: ty::InferConst,
         freshener: F,
         ty: Ty<'tcx>,
     ) -> ty::Const<'tcx>
     where
-        F: FnOnce(u32) -> ty::InferConst<'tcx>,
+        F: FnOnce(u32) -> ty::InferConst,
     {
         if let Some(ct) = opt_ct {
             return ct.fold_with(self);
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 2f371c4fe31..7e878ac06c7 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -1,3 +1,4 @@
+use rustc_middle::infer::unify_key::ConstVidKey;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
 
@@ -23,14 +24,14 @@ where
 }
 
 fn const_vars_since_snapshot<'tcx>(
-    table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>,
+    table: &mut UnificationTable<'_, 'tcx, ConstVidKey<'tcx>>,
     snapshot_var_len: usize,
-) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) {
+) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
     let range = vars_since_snapshot(table, snapshot_var_len);
     (
-        range.start..range.end,
-        (range.start.index..range.end.index)
-            .map(|index| table.probe_value(ConstVid::from_index(index)).origin)
+        range.start.vid..range.end.vid,
+        (range.start.index()..range.end.index())
+            .map(|index| table.probe_value(ConstVid::from_u32(index)).origin)
             .collect(),
     )
 }
@@ -172,7 +173,7 @@ pub struct InferenceFudger<'a, 'tcx> {
     int_vars: Range<IntVid>,
     float_vars: Range<FloatVid>,
     region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
-    const_vars: (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>),
+    const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
 }
 
 impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
@@ -235,7 +236,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
             if self.const_vars.0.contains(&vid) {
                 // This variable was created during the fudging.
                 // Recreate it with a fresh variable here.
-                let idx = (vid.index - self.const_vars.0.start.index) as usize;
+                let idx = (vid.index() - self.const_vars.0.start.index()) as usize;
                 let origin = self.const_vars.1[idx];
                 self.infcx.next_const_var(ct.ty(), origin)
             } else {
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
index c1e65ffe0a6..17fe3aa7b44 100644
--- a/compiler/rustc_infer/src/infer/generalize.rs
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -17,7 +17,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
     infcx: &InferCtxt<'tcx>,
     delegate: &mut D,
     term: T,
-    for_vid: impl Into<ty::TermVid<'tcx>>,
+    for_vid: impl Into<ty::TermVid>,
     ambient_variance: ty::Variance,
 ) -> RelateResult<'tcx, Generalization<T>> {
     let (for_universe, root_vid) = match for_vid.into() {
@@ -27,7 +27,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
         ),
         ty::TermVid::Const(ct_vid) => (
             infcx.probe_const_var(ct_vid).unwrap_err(),
-            ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)),
+            ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
         ),
     };
 
@@ -127,7 +127,7 @@ struct Generalizer<'me, 'tcx, D> {
     /// The vid of the type variable that is in the process of being
     /// instantiated. If we find this within the value we are folding,
     /// that means we would have created a cyclic value.
-    root_vid: ty::TermVid<'tcx>,
+    root_vid: ty::TermVid,
 
     /// The universe of the type variable that is in the process of being
     /// instantiated. If we find anything that this universe cannot name,
@@ -376,7 +376,7 @@ where
                 // `vid` are related and we'd be inferring an infinitely
                 // deep const.
                 if ty::TermVid::Const(
-                    self.infcx.inner.borrow_mut().const_unification_table().find(vid),
+                    self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid,
                 ) == self.root_vid
                 {
                     return Err(self.cyclic_term_error());
@@ -394,10 +394,14 @@ where
                         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 },
-                            });
+                            let new_var_id = variable_table
+                                .new_key(ConstVarValue {
+                                    origin: var_value.origin,
+                                    val: ConstVariableValue::Unknown {
+                                        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/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 8ffcf1fce9c..4ee897ffe98 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -6,7 +6,9 @@ pub use self::RegionVariableOrigin::*;
 pub use self::SubregionOrigin::*;
 pub use self::ValuePairs::*;
 pub use combine::ObligationEmittingRelation;
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
 
 use self::opaque_types::OpaqueTypeStorage;
 pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
@@ -40,7 +42,6 @@ use rustc_span::{Span, DUMMY_SP};
 
 use std::cell::{Cell, RefCell};
 use std::fmt;
-use std::marker::PhantomData;
 
 use self::combine::CombineFields;
 use self::error_reporting::TypeErrCtxt;
@@ -85,7 +86,7 @@ pub struct InferOk<'tcx, T> {
 pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
 
 pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
-pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
+pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
 
 pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
     ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>,
@@ -108,7 +109,7 @@ pub struct InferCtxtInner<'tcx> {
     type_variable_storage: type_variable::TypeVariableStorage<'tcx>,
 
     /// Map from const parameter variable to the kind of const it represents.
-    const_unification_storage: ut::UnificationTableStorage<ty::ConstVid<'tcx>>,
+    const_unification_storage: ut::UnificationTableStorage<ConstVidKey<'tcx>>,
 
     /// Map from integral variable to the kind of integer it represents.
     int_unification_storage: ut::UnificationTableStorage<ty::IntVid>,
@@ -117,7 +118,7 @@ pub struct InferCtxtInner<'tcx> {
     float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
 
     /// Map from effect variable to the effect param it represents.
-    effect_unification_storage: ut::UnificationTableStorage<ty::EffectVid<'tcx>>,
+    effect_unification_storage: ut::UnificationTableStorage<EffectVidKey<'tcx>>,
 
     /// Tracks the set of region variables and the constraints between them.
     ///
@@ -224,11 +225,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 
     #[inline]
-    fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::ConstVid<'tcx>> {
+    fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ConstVidKey<'tcx>> {
         self.const_unification_storage.with_log(&mut self.undo_log)
     }
 
-    fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::EffectVid<'tcx>> {
+    fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> {
         self.effect_unification_storage.with_log(&mut self.undo_log)
     }
 
@@ -341,7 +342,9 @@ pub struct InferCtxt<'tcx> {
     next_trait_solver: bool,
 }
 
-impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
+impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
+    type Interner = TyCtxt<'tcx>;
+
     fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> {
         use InferTy::*;
         match ty {
@@ -357,7 +360,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
         }
     }
 
-    fn universe_of_ct(&self, ct: ty::InferConst<'tcx>) -> Option<ty::UniverseIndex> {
+    fn universe_of_ct(&self, ct: ty::InferConst) -> Option<ty::UniverseIndex> {
         use ty::InferConst::*;
         match ct {
             // Same issue as with `universe_of_ty`
@@ -546,11 +549,11 @@ pub enum NllRegionVariableOrigin {
 
 // FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`.
 #[derive(Copy, Clone, Debug)]
-pub enum FixupError<'tcx> {
+pub enum FixupError {
     UnresolvedIntTy(IntVid),
     UnresolvedFloatTy(FloatVid),
     UnresolvedTy(TyVid),
-    UnresolvedConst(ConstVid<'tcx>),
+    UnresolvedConst(ConstVid),
 }
 
 /// See the `region_obligations` field for more information.
@@ -561,7 +564,7 @@ pub struct RegionObligation<'tcx> {
     pub origin: SubregionOrigin<'tcx>,
 }
 
-impl<'tcx> fmt::Display for FixupError<'tcx> {
+impl fmt::Display for FixupError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use self::FixupError::*;
 
@@ -792,7 +795,7 @@ impl<'tcx> InferCtxt<'tcx> {
         let mut table = inner.effect_unification_table();
 
         (0..table.len())
-            .map(|i| ty::EffectVid { index: i as u32, phantom: PhantomData })
+            .map(|i| ty::EffectVid::from_usize(i))
             .filter(|&vid| table.probe_value(vid).is_none())
             .map(|v| {
                 ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
@@ -1070,15 +1073,20 @@ impl<'tcx> InferCtxt<'tcx> {
             .inner
             .borrow_mut()
             .const_unification_table()
-            .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } });
+            .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } })
+            .vid;
         ty::Const::new_var(self.tcx, vid, ty)
     }
 
-    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
-        self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
-            origin,
-            val: ConstVariableValue::Unknown { universe: self.universe() },
-        })
+    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid {
+        self.inner
+            .borrow_mut()
+            .const_unification_table()
+            .new_key(ConstVarValue {
+                origin,
+                val: ConstVariableValue::Unknown { universe: self.universe() },
+            })
+            .vid
     }
 
     fn next_int_var_id(&self) -> IntVid {
@@ -1192,11 +1200,15 @@ impl<'tcx> InferCtxt<'tcx> {
                     ),
                     span,
                 };
-                let const_var_id =
-                    self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
+                let const_var_id = self
+                    .inner
+                    .borrow_mut()
+                    .const_unification_table()
+                    .new_key(ConstVarValue {
                         origin,
                         val: ConstVariableValue::Unknown { universe: self.universe() },
-                    });
+                    })
+                    .vid;
                 ty::Const::new_var(
                     self.tcx,
                     const_var_id,
@@ -1211,7 +1223,7 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
-        let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
+        let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
         let ty = self
             .tcx
             .type_of(param.def_id)
@@ -1331,12 +1343,12 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow_mut().type_variables().root_var(var)
     }
 
-    pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> {
-        self.inner.borrow_mut().const_unification_table().find(var)
+    pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
+        self.inner.borrow_mut().const_unification_table().find(var).vid
     }
 
-    pub fn root_effect_var(&self, var: ty::EffectVid<'tcx>) -> ty::EffectVid<'tcx> {
-        self.inner.borrow_mut().effect_unification_table().find(var)
+    pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid {
+        self.inner.borrow_mut().effect_unification_table().find(var).vid
     }
 
     /// Resolves an int var to a rigid int type, if it was constrained to one,
@@ -1400,17 +1412,14 @@ impl<'tcx> InferCtxt<'tcx> {
         value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value()
     }
 
-    pub fn probe_const_var(
-        &self,
-        vid: ty::ConstVid<'tcx>,
-    ) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
+    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 {
             ConstVariableValue::Known { value } => Ok(value),
             ConstVariableValue::Unknown { universe } => Err(universe),
         }
     }
 
-    pub fn probe_effect_var(&self, vid: EffectVid<'tcx>) -> Option<EffectVarValue<'tcx>> {
+    pub fn probe_effect_var(&self, vid: EffectVid) -> Option<EffectVarValue<'tcx>> {
         self.inner.borrow_mut().effect_unification_table().probe_value(vid)
     }
 
@@ -1421,7 +1430,7 @@ impl<'tcx> InferCtxt<'tcx> {
     ///
     /// This method is idempotent, but it not typically not invoked
     /// except during the writeback phase.
-    pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> {
+    pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<T> {
         match resolve::fully_resolve(self, value) {
             Ok(value) => {
                 if value.has_non_region_infer() {
@@ -1645,11 +1654,11 @@ impl<'tcx> InferCtxt<'tcx> {
     #[inline]
     pub fn is_ty_infer_var_definitely_unchanged<'a>(
         &'a self,
-    ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) {
+    ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'tcx> + 'a) {
         // This hoists the borrow/release out of the loop body.
         let inner = self.inner.try_borrow();
 
-        return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) {
+        return move |infer_var: TyOrConstInferVar| match (infer_var, &inner) {
             (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
                 use self::type_variable::TypeVariableValue;
 
@@ -1672,7 +1681,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// inference variables), and it handles both `Ty` and `ty::Const` without
     /// having to resort to storing full `GenericArg`s in `stalled_on`.
     #[inline(always)]
-    pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool {
+    pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> bool {
         match infer_var {
             TyOrConstInferVar::Ty(v) => {
                 use self::type_variable::TypeVariableValue;
@@ -1779,7 +1788,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 /// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently
 /// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
 #[derive(Copy, Clone, Debug)]
-pub enum TyOrConstInferVar<'tcx> {
+pub enum TyOrConstInferVar {
     /// Equivalent to `ty::Infer(ty::TyVar(_))`.
     Ty(TyVid),
     /// Equivalent to `ty::Infer(ty::IntVar(_))`.
@@ -1788,12 +1797,12 @@ pub enum TyOrConstInferVar<'tcx> {
     TyFloat(FloatVid),
 
     /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
-    Const(ConstVid<'tcx>),
+    Const(ConstVid),
     /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
-    Effect(EffectVid<'tcx>),
+    Effect(EffectVid),
 }
 
-impl<'tcx> TyOrConstInferVar<'tcx> {
+impl<'tcx> TyOrConstInferVar {
     /// Tries to extract an inference variable from a type or a constant, returns `None`
     /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and
     /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 3c41e8b3783..18a9cb6b44b 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -192,7 +192,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tc
 /// Full type resolution replaces all type and region variables with
 /// their concrete results. If any variable cannot be replaced (never unified, etc)
 /// then an `Err` result is returned.
-pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T>
+pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<T>
 where
     T: TypeFoldable<TyCtxt<'tcx>>,
 {
@@ -206,7 +206,7 @@ struct FullTypeResolver<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
-    type Error = FixupError<'tcx>;
+    type Error = FixupError;
 
     fn interner(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 79144b3e643..5655730518e 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -3,7 +3,7 @@ use std::marker::PhantomData;
 use rustc_data_structures::snapshot_vec as sv;
 use rustc_data_structures::undo_log::{Rollback, UndoLogs};
 use rustc_data_structures::unify as ut;
-use rustc_middle::infer::unify_key::RegionVidKey;
+use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey};
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
 
 use crate::{
@@ -21,10 +21,10 @@ pub struct Snapshot<'tcx> {
 pub(crate) enum UndoLog<'tcx> {
     OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
     TypeVariables(type_variable::UndoLog<'tcx>),
-    ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
+    ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
-    EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
+    EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
     RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
@@ -56,9 +56,9 @@ impl_from! {
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
 
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
-    EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
+    EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
 
-    ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
+    ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
 
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index d2ce77ad535..87badcbdf15 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -24,6 +24,7 @@ use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
 use std::path::PathBuf;
 use std::result;
+use std::sync::Arc;
 
 pub type Result<T> = result::Result<T, ErrorGuaranteed>;
 
@@ -410,6 +411,12 @@ pub struct Config {
     /// Registry of diagnostics codes.
     pub registry: Registry,
 
+    /// The inner atomic value is set to true when a feature marked as `internal` is
+    /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
+    /// internal features are wontfix, and they are usually the cause of the ICEs.
+    /// None signifies that this is not tracked.
+    pub using_internal_features: Arc<std::sync::atomic::AtomicBool>,
+
     /// All commandline args used to invoke the compiler, with @file args fully expanded.
     /// This will only be used within debug info, e.g. in the pdb file on windows
     /// This is mainly useful for other tools that reads that debuginfo to figure out
@@ -453,6 +460,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 config.make_codegen_backend,
                 registry.clone(),
                 config.ice_file,
+                config.using_internal_features,
                 config.expanded_args,
             );
 
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 7a7e9024bd8..884afae23d8 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -775,12 +775,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     rustc_hir_analysis::check_crate(tcx)?;
 
     sess.time("MIR_borrow_checking", || {
-        tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
+        tcx.hir().par_body_owners(|def_id| {
+            // Run THIR unsafety check because it's responsible for stealing
+            // and deallocating THIR when enabled.
+            tcx.ensure().thir_check_unsafety(def_id);
+            tcx.ensure().mir_borrowck(def_id)
+        });
     });
 
     sess.time("MIR_effect_checking", || {
         for def_id in tcx.hir().body_owners() {
-            tcx.ensure().thir_check_unsafety(def_id);
             if !tcx.sess.opts.unstable_opts.thir_unsafeck {
                 rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
             }
@@ -852,6 +856,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
         // This check has to be run after all lints are done processing. We don't
         // define a lint filter, as all lint checks should have finished at this point.
         sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None));
+
+        // This query is only invoked normally if a diagnostic is emitted that needs any
+        // diagnostic item. If the crate compiles without checking any diagnostic items,
+        // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
+        let _ = tcx.all_diagnostic_items(());
     });
 
     if sess.opts.unstable_opts.print_vtable_sizes {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index fe253febfc7..4fb295da640 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -181,9 +181,11 @@ impl<'tcx> Queries<'tcx> {
                 feed.crate_name(crate_name);
 
                 let feed = tcx.feed_unit_query();
-                feed.features_query(
-                    tcx.arena.alloc(rustc_expand::config::features(sess, &pre_configured_attrs)),
-                );
+                feed.features_query(tcx.arena.alloc(rustc_expand::config::features(
+                    sess,
+                    &pre_configured_attrs,
+                    crate_name,
+                )));
                 feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
             });
             Ok(qcx)
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index ec4fd78994e..750d49a1c2d 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -35,6 +35,7 @@ use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtecto
 use std::collections::{BTreeMap, BTreeSet};
 use std::num::NonZeroUsize;
 use std::path::{Path, PathBuf};
+use std::sync::Arc;
 
 type CfgSpecs = FxHashSet<(String, Option<String>)>;
 
@@ -69,6 +70,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
         None,
         "",
         None,
+        Arc::default(),
         Default::default(),
     );
     (sess, cfg)
@@ -789,7 +791,6 @@ fn test_unstable_options_tracking_hash() {
     tracked!(inline_mir, Some(true));
     tracked!(inline_mir_hint_threshold, Some(123));
     tracked!(inline_mir_threshold, Some(123));
-    tracked!(instrument_coverage, Some(InstrumentCoverage::All));
     tracked!(instrument_mcount, true);
     tracked!(instrument_xray, Some(InstrumentXRay::default()));
     tracked!(link_directives, false);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0634e44c562..d2455a036cc 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -26,7 +26,7 @@ use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::mem;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::OnceLock;
+use std::sync::{Arc, OnceLock};
 use std::thread;
 
 /// Function pointer type that constructs a new CodegenBackend.
@@ -71,6 +71,7 @@ pub fn create_session(
     >,
     descriptions: Registry,
     ice_file: Option<PathBuf>,
+    using_internal_features: Arc<AtomicBool>,
     expanded_args: Vec<String>,
 ) -> (Session, Box<dyn CodegenBackend>) {
     let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
@@ -114,6 +115,7 @@ pub fn create_session(
         target_override,
         rustc_version_str().unwrap_or("unknown"),
         ice_file,
+        using_internal_features,
         expanded_args,
     );
 
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index c8f3c2a20a6..0b5426c3bb1 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -21,35 +21,17 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
-use crate::infer::MemberConstraint;
-use crate::mir::ConstraintCategory;
-use crate::ty::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 use rustc_macros::HashStable;
+use rustc_type_ir::Canonical as IrCanonical;
 use smallvec::SmallVec;
-use std::fmt::Display;
 use std::ops::Index;
 
-/// A "canonicalized" type `V` is one where all free inference
-/// variables have been rewritten to "canonical vars". These are
-/// numbered starting from 0 in order of first appearance.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub struct Canonical<'tcx, V> {
-    pub value: V,
-    pub max_universe: ty::UniverseIndex,
-    pub variables: CanonicalVarInfos<'tcx>,
-}
+use crate::infer::MemberConstraint;
+use crate::mir::ConstraintCategory;
+use crate::ty::GenericArg;
+use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 
-impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(
-            f,
-            "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
-            self.value, self.max_universe, self.variables
-        )
-    }
-}
+pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>;
 
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 
@@ -379,56 +361,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> {
     }
 }
 
-impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
-    pub fn is_proven(&self) -> bool {
-        self.value.is_proven()
-    }
-
-    pub fn is_ambiguous(&self) -> bool {
-        !self.is_proven()
-    }
-}
-
-impl<'tcx, V> Canonical<'tcx, V> {
-    /// Allows you to map the `value` of a canonical while keeping the
-    /// same set of bound variables.
-    ///
-    /// **WARNING:** This function is very easy to mis-use, hence the
-    /// name!  In particular, the new value `W` must use all **the
-    /// same type/region variables** in **precisely the same order**
-    /// as the original! (The ordering is defined by the
-    /// `TypeFoldable` implementation of the type in question.)
-    ///
-    /// An example of a **correct** use of this:
-    ///
-    /// ```rust,ignore (not real code)
-    /// let a: Canonical<'_, T> = ...;
-    /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
-    /// ```
-    ///
-    /// An example of an **incorrect** use of this:
-    ///
-    /// ```rust,ignore (not real code)
-    /// let a: Canonical<'tcx, T> = ...;
-    /// let ty: Ty<'tcx> = ...;
-    /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
-    /// ```
-    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
-        let Canonical { max_universe, variables, value } = self;
-        Canonical { max_universe, variables, value: map_op(value) }
-    }
-
-    /// Allows you to map the `value` of a canonical while keeping the same set of
-    /// bound variables.
-    ///
-    /// **WARNING:** This function is very easy to mis-use, hence the name! See
-    /// the comment of [Canonical::unchecked_map] for more details.
-    pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
-        let Canonical { max_universe, variables, value: _ } = self;
-        Canonical { max_universe, variables, value }
-    }
-}
-
 pub type QueryOutlivesConstraint<'tcx> =
     (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
 
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 7ca9647590a..041a63776d1 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -141,18 +141,30 @@ pub struct ConstVarValue<'tcx> {
     pub val: ConstVariableValue<'tcx>,
 }
 
-impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct ConstVidKey<'tcx> {
+    pub vid: ty::ConstVid,
+    pub phantom: PhantomData<ty::Const<'tcx>>,
+}
+
+impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> {
+    fn from(vid: ty::ConstVid) -> Self {
+        ConstVidKey { vid, phantom: PhantomData }
+    }
+}
+
+impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
     type Value = ConstVarValue<'tcx>;
     #[inline]
     fn index(&self) -> u32 {
-        self.index
+        self.vid.as_u32()
     }
     #[inline]
     fn from_index(i: u32) -> Self {
-        ty::ConstVid { index: i, phantom: PhantomData }
+        ConstVidKey::from(ty::ConstVid::from_u32(i))
     }
     fn tag() -> &'static str {
-        "ConstVid"
+        "ConstVidKey"
     }
 }
 
@@ -224,17 +236,29 @@ impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
     }
 }
 
-impl<'tcx> UnifyKey for ty::EffectVid<'tcx> {
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct EffectVidKey<'tcx> {
+    pub vid: ty::EffectVid,
+    pub phantom: PhantomData<EffectVarValue<'tcx>>,
+}
+
+impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> {
+    fn from(vid: ty::EffectVid) -> Self {
+        EffectVidKey { vid, phantom: PhantomData }
+    }
+}
+
+impl<'tcx> UnifyKey for EffectVidKey<'tcx> {
     type Value = Option<EffectVarValue<'tcx>>;
     #[inline]
     fn index(&self) -> u32 {
-        self.index
+        self.vid.as_u32()
     }
     #[inline]
     fn from_index(i: u32) -> Self {
-        ty::EffectVid { index: i, phantom: PhantomData }
+        EffectVidKey::from(ty::EffectVid::from_u32(i))
     }
     fn tag() -> &'static str {
-        "EffectVid"
+        "EffectVidKey"
     }
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 23d77a1ebe4..0c2241f8729 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -341,7 +341,7 @@ rustc_queries! {
 
     query opaque_types_defined_by(
         key: LocalDefId
-    ) -> &'tcx [LocalDefId] {
+    ) -> &'tcx ty::List<LocalDefId> {
         desc {
             |tcx| "computing the opaque types defined by `{}`",
             tcx.def_path_str(key.to_def_id())
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 20e3349073d..f1747356139 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -636,7 +636,8 @@ impl<'tcx> Pat<'tcx> {
             Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {}
             AscribeUserType { subpattern, .. }
             | Binding { subpattern: Some(subpattern), .. }
-            | Deref { subpattern } => subpattern.walk_(it),
+            | Deref { subpattern }
+            | InlineConstant { subpattern, .. } => subpattern.walk_(it),
             Leaf { subpatterns } | Variant { subpatterns, .. } => {
                 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
             }
@@ -764,6 +765,22 @@ pub enum PatKind<'tcx> {
         value: mir::Const<'tcx>,
     },
 
+    /// Inline constant found while lowering a pattern.
+    InlineConstant {
+        /// [LocalDefId] of the constant, we need this so that we have a
+        /// reference that can be used by unsafety checking to visit nested
+        /// unevaluated constants.
+        def: LocalDefId,
+        /// If the inline constant is used in a range pattern, this subpattern
+        /// represents the range (if both ends are inline constants, there will
+        /// be multiple InlineConstant wrappers).
+        ///
+        /// Otherwise, the actual pattern that the constant lowered to. As with
+        /// other constants, inline constants are matched structurally where
+        /// possible.
+        subpattern: Box<Pat<'tcx>>,
+    },
+
     Range(Box<PatRange<'tcx>>),
 
     /// Matches against a slice, checking the length and extracting elements.
@@ -924,6 +941,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 write!(f, "{subpattern}")
             }
             PatKind::Constant { value } => write!(f, "{value}"),
+            PatKind::InlineConstant { def: _, ref subpattern } => {
+                write!(f, "{} (from inline const)", subpattern)
+            }
             PatKind::Range(box PatRange { lo, hi, end }) => {
                 write!(f, "{lo}")?;
                 write!(f, "{end}")?;
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index afb58438519..d03d92c3a4b 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -233,16 +233,17 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
             }
         }
         Constant { value: _ } => {}
+        InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
             for subpattern in prefix.iter() {
-                visitor.visit_pat(&subpattern);
+                visitor.visit_pat(subpattern);
             }
             if let Some(pat) = slice {
-                visitor.visit_pat(&pat);
+                visitor.visit_pat(pat);
             }
             for subpattern in suffix.iter() {
-                visitor.visit_pat(&subpattern);
+                visitor.visit_pat(subpattern);
             }
         }
         Or { pats } => {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index e4069e11df2..d52a717b6b0 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -230,9 +230,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
                 assert!(pos >= SHORTHAND_OFFSET);
                 let shorthand = pos - SHORTHAND_OFFSET;
 
-                decoder.with_position(shorthand, ty::PredicateKind::decode)
+                decoder.with_position(shorthand, <ty::PredicateKind<'tcx> as Decodable<D>>::decode)
             } else {
-                ty::PredicateKind::decode(decoder)
+                <ty::PredicateKind<'tcx> as Decodable<D>>::decode(decoder)
             },
             bound_vars,
         )
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 2518f0cf2e9..cfacccd2679 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -57,7 +57,7 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
+    pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid, ty: Ty<'tcx>) -> Const<'tcx> {
         Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty)
     }
 
@@ -67,7 +67,7 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
+    pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Const<'tcx> {
         Const::new(tcx, ty::ConstKind::Infer(infer), ty)
     }
 
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 749b54ca0be..4af841fcf9a 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -80,19 +80,19 @@ static_assert_size!(super::ConstKind<'_>, 32);
 
 /// An inference variable for a const, for use in const generics.
 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
-pub enum InferConst<'tcx> {
+pub enum InferConst {
     /// Infer the value of the const.
-    Var(ty::ConstVid<'tcx>),
+    Var(ty::ConstVid),
     /// Infer the value of the effect.
     ///
     /// For why this is separate from the `Var` variant above, see the
     /// documentation on `EffectVid`.
-    EffectVar(ty::EffectVid<'tcx>),
+    EffectVar(ty::EffectVid),
     /// A fresh const variable. See `infer::freshen` for more details.
     Fresh(u32),
 }
 
-impl<CTX> HashStable<CTX> for InferConst<'_> {
+impl<CTX> HashStable<CTX> for InferConst {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         match self {
             InferConst::Var(_) | InferConst::EffectVar(_) => {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 561699d3170..a669ff8d961 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -6,7 +6,7 @@ pub mod tls;
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
-use crate::infer::canonical::CanonicalVarInfo;
+use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::struct_lint_level;
 use crate::metadata::ModChild;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -84,10 +84,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type AdtDef = ty::AdtDef<'tcx>;
     type GenericArgs = ty::GenericArgsRef<'tcx>;
     type GenericArg = ty::GenericArg<'tcx>;
+    type Term = ty::Term<'tcx>;
+
     type Binder<T> = Binder<'tcx, T>;
-    type Predicate = Predicate<'tcx>;
-    type PredicateKind = ty::PredicateKind<'tcx>;
     type TypeAndMut = TypeAndMut<'tcx>;
+    type CanonicalVars = CanonicalVarInfos<'tcx>;
+
     type Ty = Ty<'tcx>;
     type Tys = &'tcx List<Ty<'tcx>>;
     type AliasTy = ty::AliasTy<'tcx>;
@@ -95,18 +97,21 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type BoundTy = ty::BoundTy;
     type PlaceholderTy = ty::PlaceholderType;
     type InferTy = InferTy;
+
     type ErrorGuaranteed = ErrorGuaranteed;
     type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
     type PolyFnSig = PolyFnSig<'tcx>;
     type AllocId = crate::mir::interpret::AllocId;
+
     type Const = ty::Const<'tcx>;
-    type InferConst = ty::InferConst<'tcx>;
+    type InferConst = ty::InferConst;
     type AliasConst = ty::UnevaluatedConst<'tcx>;
     type PlaceholderConst = ty::PlaceholderConst<'tcx>;
     type ParamConst = ty::ParamConst;
     type BoundConst = ty::BoundVar;
     type ValueConst = ty::ValTree<'tcx>;
     type ExprConst = ty::Expr<'tcx>;
+
     type Region = Region<'tcx>;
     type EarlyBoundRegion = ty::EarlyBoundRegion;
     type BoundRegion = ty::BoundRegion;
@@ -114,6 +119,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type InferRegion = ty::RegionVid;
     type PlaceholderRegion = ty::PlaceholderRegion;
 
+    type Predicate = Predicate<'tcx>;
+    type TraitPredicate = ty::TraitPredicate<'tcx>;
+    type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
+    type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
+    type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
+    type SubtypePredicate = ty::SubtypePredicate<'tcx>;
+    type CoercePredicate = ty::CoercePredicate<'tcx>;
+    type ClosureKind = ty::ClosureKind;
+
     fn ty_and_mut_to_parts(
         TypeAndMut { ty, mutbl }: TypeAndMut<'tcx>,
     ) -> (Self::Ty, ty::Mutability) {
@@ -148,6 +162,7 @@ pub struct CtxtInterners<'tcx> {
     external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
     predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
     fields: InternedSet<'tcx, List<FieldIdx>>,
+    local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -173,6 +188,7 @@ impl<'tcx> CtxtInterners<'tcx> {
             external_constraints: Default::default(),
             predefined_opaques_in_body: Default::default(),
             fields: Default::default(),
+            local_def_ids: Default::default(),
         }
     }
 
@@ -1559,6 +1575,7 @@ slice_interners!(
     place_elems: pub mk_place_elems(PlaceElem<'tcx>),
     bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
     fields: pub mk_fields(FieldIdx),
+    local_def_ids: intern_local_def_ids(LocalDefId),
 );
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -1788,6 +1805,13 @@ impl<'tcx> TyCtxt<'tcx> {
         self.intern_clauses(clauses)
     }
 
+    pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List<LocalDefId> {
+        // FIXME consider asking the input slice to be sorted to avoid
+        // re-interning permutations, in which case that would be asserted
+        // here.
+        self.intern_local_def_ids(clauses)
+    }
+
     pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 184a70ed4cb..738bb5e8b19 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -241,7 +241,9 @@ impl<'tcx> Ty<'tcx> {
             }
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
-            ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(),
+            ty::Coroutine(def_id, ..) => {
+                format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
+            }
             ty::CoroutineWitness(..) => "coroutine witness".into(),
             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
             ty::Infer(ty::IntVar(_)) => "integer".into(),
@@ -299,7 +301,9 @@ impl<'tcx> Ty<'tcx> {
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
-            ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(),
+            ty::Coroutine(def_id, ..) => {
+                format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
+            }
             ty::CoroutineWitness(..) => "coroutine witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Placeholder(..) => "higher-ranked type".into(),
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 7a32cfb1085..4f9c9d85763 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -1,7 +1,7 @@
 use crate::arena::Arena;
 use rustc_data_structures::aligned::{align_of, Aligned};
 use rustc_serialize::{Encodable, Encoder};
-use rustc_type_ir::{InferCtxtLike, OptWithInfcx};
+use rustc_type_ir::{InferCtxtLike, WithInfcx};
 use std::alloc::Layout;
 use std::cmp::Ordering;
 use std::fmt;
@@ -121,8 +121,8 @@ impl<T: fmt::Debug> fmt::Debug for List<T> {
     }
 }
 impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         fmt::Debug::fmt(&this.map(|this| this.as_slice()), f)
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9b0ceb23e3e..739d4fa886e 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -54,7 +54,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ExpnId, ExpnKind, Span};
 use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
 pub use rustc_target::abi::{ReprFlags, ReprOptions};
-pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
+pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
 pub use vtable::*;
 
 use std::fmt::Debug;
@@ -97,17 +97,17 @@ pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::BoundRegionKind::*;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
-    BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
-    CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate,
+    BoundVariableKind, CanonicalPolyFnSig, ClauseKind, ClosureArgs, ClosureArgsParts, ConstKind,
+    ConstVid, CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate,
     ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, InlineConstArgs,
     InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
-    PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
-    TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
+    PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, PredicateKind, Region,
+    RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
-    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults,
-    UserType, UserTypeAnnotationIndex,
+    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
+    TypeckResults, UserType, UserTypeAnnotationIndex,
 };
 
 pub mod _match;
@@ -233,6 +233,7 @@ impl MainDefinition {
 #[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct ImplHeader<'tcx> {
     pub impl_def_id: DefId,
+    pub impl_args: ty::GenericArgsRef<'tcx>,
     pub self_ty: Ty<'tcx>,
     pub trait_ref: Option<TraitRef<'tcx>>,
     pub predicates: Vec<Predicate<'tcx>>,
@@ -626,98 +627,6 @@ impl<'tcx> Clause<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-/// A clause is something that can appear in where bounds or be inferred
-/// by implied bounds.
-pub enum ClauseKind<'tcx> {
-    /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
-    /// the `Self` type of the trait reference and `A`, `B`, and `C`
-    /// would be the type parameters.
-    Trait(TraitPredicate<'tcx>),
-
-    /// `where 'a: 'b`
-    RegionOutlives(RegionOutlivesPredicate<'tcx>),
-
-    /// `where T: 'a`
-    TypeOutlives(TypeOutlivesPredicate<'tcx>),
-
-    /// `where <T as TraitRef>::Name == X`, approximately.
-    /// See the `ProjectionPredicate` struct for details.
-    Projection(ProjectionPredicate<'tcx>),
-
-    /// Ensures that a const generic argument to a parameter `const N: u8`
-    /// is of type `u8`.
-    ConstArgHasType(Const<'tcx>, Ty<'tcx>),
-
-    /// No syntax: `T` well-formed.
-    WellFormed(GenericArg<'tcx>),
-
-    /// Constant initializer must evaluate successfully.
-    ConstEvaluatable(ty::Const<'tcx>),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub enum PredicateKind<'tcx> {
-    /// Prove a clause
-    Clause(ClauseKind<'tcx>),
-
-    /// Trait must be object-safe.
-    ObjectSafe(DefId),
-
-    /// No direct syntax. May be thought of as `where T: FnFoo<...>`
-    /// for some generic args `...` and `T` being a closure type.
-    /// Satisfied (or refuted) once we know the closure's kind.
-    ClosureKind(DefId, GenericArgsRef<'tcx>, ClosureKind),
-
-    /// `T1 <: T2`
-    ///
-    /// This obligation is created most often when we have two
-    /// unresolved type variables and hence don't have enough
-    /// information to process the subtyping obligation yet.
-    Subtype(SubtypePredicate<'tcx>),
-
-    /// `T1` coerced to `T2`
-    ///
-    /// Like a subtyping obligation, this is created most often
-    /// when we have two unresolved type variables and hence
-    /// don't have enough information to process the coercion
-    /// obligation yet. At the moment, we actually process coercions
-    /// very much like subtyping and don't handle the full coercion
-    /// logic.
-    Coerce(CoercePredicate<'tcx>),
-
-    /// Constants must be equal. The first component is the const that is expected.
-    ConstEquate(Const<'tcx>, Const<'tcx>),
-
-    /// A marker predicate that is always ambiguous.
-    /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
-    Ambiguous,
-
-    /// Separate from `ClauseKind::Projection` which is used for normalization in new solver.
-    /// This predicate requires two terms to be equal to eachother.
-    ///
-    /// Only used for new solver
-    AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, Debug)]
-pub enum AliasRelationDirection {
-    Equate,
-    Subtype,
-}
-
-impl std::fmt::Display for AliasRelationDirection {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            AliasRelationDirection::Equate => write!(f, "=="),
-            AliasRelationDirection::Subtype => write!(f, "<:"),
-        }
-    }
-}
-
 /// The crate outlives map is computed during typeck and contains the
 /// outlives of every item in the local crate. You should not use it
 /// directly, because to do so will make your pass dependent on the
@@ -1084,19 +993,19 @@ impl ParamTerm {
 }
 
 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
-pub enum TermVid<'tcx> {
+pub enum TermVid {
     Ty(ty::TyVid),
-    Const(ty::ConstVid<'tcx>),
+    Const(ty::ConstVid),
 }
 
-impl From<ty::TyVid> for TermVid<'_> {
+impl From<ty::TyVid> for TermVid {
     fn from(value: ty::TyVid) -> Self {
         TermVid::Ty(value)
     }
 }
 
-impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> {
-    fn from(value: ty::ConstVid<'tcx>) -> Self {
+impl From<ty::ConstVid> for TermVid {
+    fn from(value: ty::ConstVid) -> Self {
         TermVid::Const(value)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 316370977a4..433ac33f1b8 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1194,7 +1194,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         None
     }
 
-    fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<Symbol> {
+    fn const_infer_name(&self, _: ty::ConstVid) -> Option<Symbol> {
         None
     }
 
@@ -1742,7 +1742,7 @@ pub struct FmtPrinterData<'a, 'tcx> {
     pub region_highlight_mode: RegionHighlightMode<'tcx>,
 
     pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>,
-    pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<Symbol> + 'a>>,
+    pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid) -> Option<Symbol> + 'a>>,
 }
 
 impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> {
@@ -2082,7 +2082,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
         self.printed_type_count = 0;
     }
 
-    fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<Symbol> {
+    fn const_infer_name(&self, id: ty::ConstVid) -> Option<Symbol> {
         self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id))
     }
 
@@ -2650,6 +2650,13 @@ macro_rules! forward_display_to_print {
 
 macro_rules! define_print_and_forward_display {
     (($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
+        define_print!(($self, $cx): $($ty $print)*);
+        forward_display_to_print!($($ty),+);
+    };
+}
+
+macro_rules! define_print {
+    (($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
         $(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty {
             fn print(&$self, $cx: &mut P) -> Result<(), PrintError> {
                 #[allow(unused_mut)]
@@ -2660,8 +2667,6 @@ macro_rules! define_print_and_forward_display {
                 Ok(())
             }
         })+
-
-        forward_display_to_print!($($ty),+);
     };
 }
 
@@ -2759,6 +2764,51 @@ forward_display_to_print! {
     ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
 }
 
+define_print! {
+    (self, cx):
+
+    ty::ClauseKind<'tcx> {
+        match *self {
+            ty::ClauseKind::Trait(ref data) => {
+                p!(print(data))
+            }
+            ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
+            ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
+            ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
+            ty::ClauseKind::ConstArgHasType(ct, ty) => {
+                p!("the constant `", print(ct), "` has type `", print(ty), "`")
+            },
+            ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
+            ty::ClauseKind::ConstEvaluatable(ct) => {
+                p!("the constant `", print(ct), "` can be evaluated")
+            }
+        }
+    }
+
+    ty::PredicateKind<'tcx> {
+        match *self {
+            ty::PredicateKind::Clause(data) => {
+                p!(print(data))
+            }
+            ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
+            ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
+            ty::PredicateKind::ObjectSafe(trait_def_id) => {
+                p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
+            }
+            ty::PredicateKind::ClosureKind(closure_def_id, _closure_args, kind) => p!(
+                "the closure `",
+                print_value_path(closure_def_id, &[]),
+                write("` implements the trait `{}`", kind)
+            ),
+            ty::PredicateKind::ConstEquate(c1, c2) => {
+                p!("the constant `", print(c1), "` equals `", print(c2), "`")
+            }
+            ty::PredicateKind::Ambiguous => p!("ambiguous"),
+            ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
+        }
+    }
+}
+
 define_print_and_forward_display! {
     (self, cx):
 
@@ -2887,55 +2937,13 @@ define_print_and_forward_display! {
     }
 
     ty::Predicate<'tcx> {
-        let binder = self.kind();
-        p!(print(binder))
+        p!(print(self.kind()))
     }
 
     ty::Clause<'tcx> {
         p!(print(self.kind()))
     }
 
-    ty::ClauseKind<'tcx> {
-        match *self {
-            ty::ClauseKind::Trait(ref data) => {
-                p!(print(data))
-            }
-            ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
-            ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
-            ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
-            ty::ClauseKind::ConstArgHasType(ct, ty) => {
-                p!("the constant `", print(ct), "` has type `", print(ty), "`")
-            },
-            ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
-            ty::ClauseKind::ConstEvaluatable(ct) => {
-                p!("the constant `", print(ct), "` can be evaluated")
-            }
-        }
-    }
-
-    ty::PredicateKind<'tcx> {
-        match *self {
-            ty::PredicateKind::Clause(data) => {
-                p!(print(data))
-            }
-            ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
-            ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
-            ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
-            }
-            ty::PredicateKind::ClosureKind(closure_def_id, _closure_args, kind) => p!(
-                "the closure `",
-                print_value_path(closure_def_id, &[]),
-                write("` implements the trait `{}`", kind)
-            ),
-            ty::PredicateKind::ConstEquate(c1, c2) => {
-                p!("the constant `", print(c1), "` equals `", print(c2), "`")
-            }
-            ty::PredicateKind::Ambiguous => p!("ambiguous"),
-            ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
-        }
-    }
-
     GenericArg<'tcx> {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => p!(print(lt)),
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index bf2e61b23b2..6af68bc5dba 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -10,7 +10,7 @@ use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_hir::def::Namespace;
 use rustc_target::abi::TyAndLayout;
-use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
+use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx};
 
 use std::fmt::{self, Debug};
 use std::ops::ControlFlow;
@@ -87,12 +87,12 @@ impl fmt::Debug for ty::FreeRegion {
 
 impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         let sig = this.data;
@@ -128,18 +128,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "?{}c", self.index)
-    }
-}
-
-impl fmt::Debug for ty::EffectVid<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "?{}e", self.index)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         with_no_trimmed_paths!(fmt::Display::fmt(self, f))
@@ -147,8 +135,8 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
 }
 
 impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         this.data.fmt(f)
@@ -197,51 +185,14 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ty::ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"),
-            ty::ClauseKind::Trait(ref a) => a.fmt(f),
-            ty::ClauseKind::RegionOutlives(ref pair) => pair.fmt(f),
-            ty::ClauseKind::TypeOutlives(ref pair) => pair.fmt(f),
-            ty::ClauseKind::Projection(ref pair) => pair.fmt(f),
-            ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({data:?})"),
-            ty::ClauseKind::ConstEvaluatable(ct) => {
-                write!(f, "ConstEvaluatable({ct:?})")
-            }
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ty::PredicateKind::Clause(ref a) => a.fmt(f),
-            ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
-            ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
-            ty::PredicateKind::ObjectSafe(trait_def_id) => {
-                write!(f, "ObjectSafe({trait_def_id:?})")
-            }
-            ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
-                write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})")
-            }
-            ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"),
-            ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
-            ty::PredicateKind::AliasRelate(t1, t2, dir) => {
-                write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
-            }
-        }
-    }
-}
-
 impl<'tcx> fmt::Debug for AliasTy<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         f.debug_struct("AliasTy")
@@ -251,7 +202,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
+impl fmt::Debug for ty::InferConst {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             InferConst::Var(var) => write!(f, "{var:?}"),
@@ -260,17 +211,17 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
         }
     }
 }
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst {
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         use ty::InferConst::*;
-        match this.infcx.and_then(|infcx| infcx.universe_of_ct(*this.data)) {
+        match this.infcx.universe_of_ct(*this.data) {
             None => write!(f, "{:?}", this.data),
             Some(universe) => match *this.data {
-                Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
-                EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()),
+                Var(vid) => write!(f, "?{}_{}c", vid.index(), universe.index()),
+                EffectVar(vid) => write!(f, "?{}_{}e", vid.index(), universe.index()),
                 Fresh(_) => {
                     unreachable!()
                 }
@@ -281,12 +232,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         match this.data {
@@ -314,12 +265,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         f.debug_struct("UnevaluatedConst")
@@ -331,12 +282,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::Const<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         // If this is a value, we spend some effort to make it look nice.
@@ -392,8 +343,8 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> {
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         match this.data.unpack() {
@@ -410,8 +361,8 @@ impl<'tcx> fmt::Debug for Region<'tcx> {
     }
 }
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         write!(f, "{:?}", &this.map(|data| data.kind()))
@@ -419,11 +370,11 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
 }
 
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
-        match this.infcx.and_then(|infcx| infcx.universe_of_lt(*this.data)) {
+        match this.infcx.universe_of_lt(*this.data) {
             Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
             None => write!(f, "{:?}", this.data),
         }
@@ -431,8 +382,8 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
 }
 
 impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
-    fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
-        this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         f.debug_tuple("Binder")
@@ -498,7 +449,6 @@ TrivialTypeTraversalImpls! {
     crate::ty::IntVarValue,
     crate::ty::adjustment::PointerCoercion,
     crate::ty::RegionVid,
-    crate::ty::UniverseIndex,
     crate::ty::Variance,
     ::rustc_span::Span,
     ::rustc_span::symbol::Ident,
@@ -515,7 +465,6 @@ TrivialTypeTraversalAndLiftImpls! {
     ::rustc_hir::Mutability,
     ::rustc_hir::Unsafety,
     ::rustc_target::spec::abi::Abi,
-    crate::ty::AliasRelationDirection,
     crate::ty::ClosureKind,
     crate::ty::ParamConst,
     crate::ty::ParamTy,
@@ -862,7 +811,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> {
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst {
     fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
         self,
         _folder: &mut F,
@@ -871,7 +820,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> {
     }
 }
 
-impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst<'tcx> {
+impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst {
     fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
         &self,
         _visitor: &mut V,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 46aa5d950cb..44592b10d55 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -29,14 +29,15 @@ use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::fmt;
-use std::marker::PhantomData;
 use std::ops::{ControlFlow, Deref, Range};
 use ty::util::IntTypeExt;
 
+use rustc_type_ir::ClauseKind as IrClauseKind;
 use rustc_type_ir::CollectAndApply;
 use rustc_type_ir::ConstKind as IrConstKind;
 use rustc_type_ir::DebugWithInfcx;
 use rustc_type_ir::DynKind;
+use rustc_type_ir::PredicateKind as IrPredicateKind;
 use rustc_type_ir::RegionKind as IrRegionKind;
 use rustc_type_ir::TyKind as IrTyKind;
 use rustc_type_ir::TyKind::*;
@@ -48,6 +49,8 @@ use super::GenericParamDefKind;
 pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
 pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
 pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
+pub type PredicateKind<'tcx> = IrPredicateKind<TyCtxt<'tcx>>;
+pub type ClauseKind<'tcx> = IrClauseKind<TyCtxt<'tcx>>;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
@@ -683,8 +686,8 @@ pub enum ExistentialPredicate<'tcx> {
 }
 
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> {
-    fn fmt<InfCtx: rustc_type_ir::InferCtxtLike<TyCtxt<'tcx>>>(
-        this: rustc_type_ir::OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
+    fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         fmt::Debug::fmt(&this.data, f)
@@ -1583,26 +1586,22 @@ impl fmt::Debug for EarlyBoundRegion {
     }
 }
 
-/// A **`const`** **v**ariable **ID**.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[derive(HashStable, TyEncodable, TyDecodable)]
-pub struct ConstVid<'tcx> {
-    pub index: u32,
-    pub phantom: PhantomData<&'tcx ()>,
+rustc_index::newtype_index! {
+    /// A **`const`** **v**ariable **ID**.
+    #[debug_format = "?{}c"]
+    pub struct ConstVid {}
 }
 
-/// An **effect** **v**ariable **ID**.
-///
-/// Handling effect infer variables happens separately from const infer variables
-/// because we do not want to reuse any of the const infer machinery. If we try to
-/// relate an effect variable with a normal one, we would ICE, which can catch bugs
-/// where we are not correctly using the effect var for an effect param. Fallback
-/// is also implemented on top of having separate effect and normal const variables.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[derive(TyEncodable, TyDecodable)]
-pub struct EffectVid<'tcx> {
-    pub index: u32,
-    pub phantom: PhantomData<&'tcx ()>,
+rustc_index::newtype_index! {
+    /// An **effect** **v**ariable **ID**.
+    ///
+    /// Handling effect infer variables happens separately from const infer variables
+    /// because we do not want to reuse any of the const infer machinery. If we try to
+    /// relate an effect variable with a normal one, we would ICE, which can catch bugs
+    /// where we are not correctly using the effect var for an effect param. Fallback
+    /// is also implemented on top of having separate effect and normal const variables.
+    #[debug_format = "?{}e"]
+    pub struct EffectVid {}
 }
 
 rustc_index::newtype_index! {
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 7d516410b20..58ad1eb900f 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -594,10 +594,27 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
 /// Canonical user type annotation.
 pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
 
-impl<'tcx> CanonicalUserType<'tcx> {
+/// A user-given type annotation attached to a constant. These arise
+/// from constants that are named via paths, like `Foo::<A>::new` and
+/// so forth.
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
+#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub enum UserType<'tcx> {
+    Ty(Ty<'tcx>),
+
+    /// The canonical type is the result of `type_of(def_id)` with the
+    /// given substitutions applied.
+    TypeOf(DefId, UserArgs<'tcx>),
+}
+
+pub trait IsIdentity {
+    fn is_identity(&self) -> bool;
+}
+
+impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
     /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
     /// i.e., each thing is mapped to a canonical variable with the same index.
-    pub fn is_identity(&self) -> bool {
+    fn is_identity(&self) -> bool {
         match self.value {
             UserType::Ty(_) => false,
             UserType::TypeOf(_, user_args) => {
@@ -640,19 +657,6 @@ impl<'tcx> CanonicalUserType<'tcx> {
     }
 }
 
-/// A user-given type annotation attached to a constant. These arise
-/// from constants that are named via paths, like `Foo::<A>::new` and
-/// so forth.
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub enum UserType<'tcx> {
-    Ty(Ty<'tcx>),
-
-    /// The canonical type is the result of `type_of(def_id)` with the
-    /// given substitutions applied.
-    TypeOf(DefId, UserArgs<'tcx>),
-}
-
 impl<'tcx> std::fmt::Display for UserType<'tcx> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index db3886b32be..32711c23dc4 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -379,6 +379,5 @@ mir_build_unused_unsafe = unnecessary `unsafe` block
     .label = unnecessary `unsafe` block
 
 mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
-mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
 
 mir_build_variant_defined_here = not covered
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 24c6e0eae36..1cf8c202ea4 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -847,6 +847,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
             }
 
+            PatKind::InlineConstant { ref subpattern, .. } => {
+                self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f)
+            }
+
             PatKind::Leaf { ref subpatterns } => {
                 for subpattern in subpatterns {
                     let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index f340feb40d4..32573b4d53a 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -204,6 +204,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 Err(match_pair)
             }
 
+            PatKind::InlineConstant { subpattern: ref pattern, def: _ } => {
+                candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
+
+                Ok(())
+            }
+
             PatKind::Range(box PatRange { lo, hi, end }) => {
                 let (range, bias) = match *lo.ty().kind() {
                     ty::Char => {
@@ -229,8 +235,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // correct the comparison. This is achieved by XORing with a bias (see
                     // pattern/_match.rs for another pertinent example of this pattern).
                     //
-                    // Also, for performance, it's important to only do the second `try_to_bits` if
-                    // necessary.
+                    // Also, for performance, it's important to only do the second
+                    // `try_to_bits` if necessary.
                     let lo = lo.try_to_bits(sz).unwrap() ^ bias;
                     if lo <= min {
                         let hi = hi.try_to_bits(sz).unwrap() ^ bias;
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 30ce37a7ac1..5e7db7413df 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -73,6 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             PatKind::Or { .. } => bug!("or-patterns should have already been handled"),
 
             PatKind::AscribeUserType { .. }
+            | PatKind::InlineConstant { .. }
             | PatKind::Array { .. }
             | PatKind::Wild
             | PatKind::Binding { .. }
@@ -111,6 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | PatKind::Or { .. }
             | PatKind::Binding { .. }
             | PatKind::AscribeUserType { .. }
+            | PatKind::InlineConstant { .. }
             | PatKind::Leaf { .. }
             | PatKind::Deref { .. }
             | PatKind::Error(_) => {
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 8a3b67b8f03..1f817633a2a 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -53,10 +53,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
 }
 
 /// Construct the MIR for a given `DefId`.
-fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
-    // Ensure unsafeck and abstract const building is ran before we steal the THIR.
-    tcx.ensure_with_value()
-        .thir_check_unsafety(tcx.typeck_root_def_id(def.to_def_id()).expect_local());
+fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
     tcx.ensure_with_value().thir_abstract_const(def);
     if let Err(e) = tcx.check_match(def) {
         return construct_error(tcx, def, e);
@@ -65,20 +62,27 @@ fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
     let body = match tcx.thir_body(def) {
         Err(error_reported) => construct_error(tcx, def, error_reported),
         Ok((thir, expr)) => {
-            // We ran all queries that depended on THIR at the beginning
-            // of `mir_build`, so now we can steal it
-            let thir = thir.steal();
+            let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
+                thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig),
+                thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty),
+            };
 
-            tcx.ensure().check_match(def);
             // this must run before MIR dump, because
             // "not all control paths return a value" is reported here.
             //
             // maybe move the check to a MIR pass?
             tcx.ensure().check_liveness(def);
 
-            match thir.body_type {
-                thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig),
-                thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty),
+            if tcx.sess.opts.unstable_opts.thir_unsafeck {
+                // Don't steal here if THIR unsafeck is being used. Instead
+                // steal in unsafeck. This is so that pattern inline constants
+                // can be evaluated as part of building the THIR of the parent
+                // function without a cycle.
+                build_mir(&thir.borrow())
+            } else {
+                // We ran all queries that depended on THIR at the beginning
+                // of `mir_build`, so now we can steal it
+                build_mir(&thir.steal())
             }
         }
     };
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 00d2afce8c6..45be5015371 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -13,6 +13,7 @@ use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
+use std::mem;
 use std::ops::Bound;
 
 struct UnsafetyVisitor<'a, 'tcx> {
@@ -24,7 +25,6 @@ struct UnsafetyVisitor<'a, 'tcx> {
     /// The current "safety context". This notably tracks whether we are in an
     /// `unsafe` block, and whether it has been used.
     safety_context: SafetyContext,
-    body_unsafety: BodyUnsafety,
     /// The `#[target_feature]` attributes of the body. Used for checking
     /// calls to functions with `#[target_feature]` (RFC 2396).
     body_target_features: &'tcx [Symbol],
@@ -34,43 +34,50 @@ struct UnsafetyVisitor<'a, 'tcx> {
     in_union_destructure: bool,
     param_env: ParamEnv<'tcx>,
     inside_adt: bool,
+    warnings: &'a mut Vec<UnusedUnsafeWarning>,
 }
 
 impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
     fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&mut Self)) {
-        if let (
-            SafetyContext::UnsafeBlock { span: enclosing_span, .. },
-            SafetyContext::UnsafeBlock { span: block_span, hir_id, .. },
-        ) = (self.safety_context, safety_context)
+        let prev_context = mem::replace(&mut self.safety_context, safety_context);
+
+        f(self);
+
+        let safety_context = mem::replace(&mut self.safety_context, prev_context);
+        if let SafetyContext::UnsafeBlock { used, span, hir_id, nested_used_blocks } =
+            safety_context
         {
-            self.warn_unused_unsafe(
-                hir_id,
-                block_span,
-                Some(UnusedUnsafeEnclosing::Block {
-                    span: self.tcx.sess.source_map().guess_head_span(enclosing_span),
-                }),
-            );
-            f(self);
-        } else {
-            let prev_context = self.safety_context;
-            self.safety_context = safety_context;
+            if !used {
+                self.warn_unused_unsafe(hir_id, span, None);
 
-            f(self);
+                if let SafetyContext::UnsafeBlock {
+                    nested_used_blocks: ref mut prev_nested_used_blocks,
+                    ..
+                } = self.safety_context
+                {
+                    prev_nested_used_blocks.extend(nested_used_blocks);
+                }
+            } else {
+                for block in nested_used_blocks {
+                    self.warn_unused_unsafe(
+                        block.hir_id,
+                        block.span,
+                        Some(UnusedUnsafeEnclosing::Block {
+                            span: self.tcx.sess.source_map().guess_head_span(span),
+                        }),
+                    );
+                }
 
-            if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context {
-                self.warn_unused_unsafe(
-                    hir_id,
-                    span,
-                    if self.unsafe_op_in_unsafe_fn_allowed() {
-                        self.body_unsafety
-                            .unsafe_fn_sig_span()
-                            .map(|span| UnusedUnsafeEnclosing::Function { span })
-                    } else {
-                        None
-                    },
-                );
+                match self.safety_context {
+                    SafetyContext::UnsafeBlock {
+                        nested_used_blocks: ref mut prev_nested_used_blocks,
+                        ..
+                    } => {
+                        prev_nested_used_blocks.push(NestedUsedBlock { hir_id, span });
+                    }
+                    _ => (),
+                }
             }
-            self.safety_context = prev_context;
         }
     }
 
@@ -102,18 +109,12 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
     }
 
     fn warn_unused_unsafe(
-        &self,
+        &mut self,
         hir_id: hir::HirId,
         block_span: Span,
         enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
     ) {
-        let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
-        self.tcx.emit_spanned_lint(
-            UNUSED_UNSAFE,
-            hir_id,
-            block_span,
-            UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
-        );
+        self.warnings.push(UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe });
     }
 
     /// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node.
@@ -124,9 +125,18 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
     /// Handle closures/coroutines/inline-consts, which is unsafecked with their parent body.
     fn visit_inner_body(&mut self, def: LocalDefId) {
         if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
-            let inner_thir = &inner_thir.borrow();
+            // Runs all other queries that depend on THIR.
+            self.tcx.ensure_with_value().mir_built(def);
+            let inner_thir = &inner_thir.steal();
             let hir_context = self.tcx.hir().local_def_id_to_hir_id(def);
-            let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
+            let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
+            let mut inner_visitor = UnsafetyVisitor {
+                thir: inner_thir,
+                hir_context,
+                safety_context,
+                warnings: self.warnings,
+                ..*self
+            };
             inner_visitor.visit_expr(&inner_thir[expr]);
             // Unsafe blocks can be used in the inner body, make sure to take it into account
             self.safety_context = inner_visitor.safety_context;
@@ -193,8 +203,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 });
             }
             BlockSafety::ExplicitUnsafe(hir_id) => {
+                let used =
+                    matches!(self.tcx.lint_level_at_node(UNUSED_UNSAFE, hir_id), (Level::Allow, _));
                 self.in_safety_context(
-                    SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false },
+                    SafetyContext::UnsafeBlock {
+                        span: block.span,
+                        hir_id,
+                        used,
+                        nested_used_blocks: Vec::new(),
+                    },
                     |this| visit::walk_block(this, block),
                 );
             }
@@ -224,6 +241,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Wild |
                 // these just wrap other patterns
                 PatKind::Or { .. } |
+                PatKind::InlineConstant { .. } |
                 PatKind::AscribeUserType { .. } |
                 PatKind::Error(_) => {}
             }
@@ -277,6 +295,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 visit::walk_pat(self, pat);
                 self.inside_adt = old_inside_adt;
             }
+            PatKind::InlineConstant { def, .. } => {
+                self.visit_inner_body(*def);
+            }
             _ => {
                 visit::walk_pat(self, pat);
             }
@@ -475,36 +496,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
     }
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone)]
 enum SafetyContext {
     Safe,
     BuiltinUnsafeBlock,
     UnsafeFn,
-    UnsafeBlock { span: Span, hir_id: hir::HirId, used: bool },
+    UnsafeBlock {
+        span: Span,
+        hir_id: hir::HirId,
+        used: bool,
+        nested_used_blocks: Vec<NestedUsedBlock>,
+    },
 }
 
 #[derive(Clone, Copy)]
-enum BodyUnsafety {
-    /// The body is not unsafe.
-    Safe,
-    /// The body is an unsafe function. The span points to
-    /// the signature of the function.
-    Unsafe(Span),
+struct NestedUsedBlock {
+    hir_id: hir::HirId,
+    span: Span,
 }
 
-impl BodyUnsafety {
-    /// Returns whether the body is unsafe.
-    fn is_unsafe(&self) -> bool {
-        matches!(self, BodyUnsafety::Unsafe(_))
-    }
-
-    /// If the body is unsafe, returns the `Span` of its signature.
-    fn unsafe_fn_sig_span(self) -> Option<Span> {
-        match self {
-            BodyUnsafety::Unsafe(span) => Some(span),
-            BodyUnsafety::Safe => None,
-        }
-    }
+struct UnusedUnsafeWarning {
+    hir_id: hir::HirId,
+    block_span: Span,
+    enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
 }
 
 #[derive(Clone, Copy, PartialEq)]
@@ -788,34 +802,46 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
     }
 
     let Ok((thir, expr)) = tcx.thir_body(def) else { return };
-    let thir = &thir.borrow();
+    // Runs all other queries that depend on THIR.
+    tcx.ensure_with_value().mir_built(def);
+    let thir = &thir.steal();
     // If `thir` is empty, a type error occurred, skip this body.
     if thir.exprs.is_empty() {
         return;
     }
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def);
-    let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
+    let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
         if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
-            BodyUnsafety::Unsafe(fn_sig.span)
+            SafetyContext::UnsafeFn
         } else {
-            BodyUnsafety::Safe
+            SafetyContext::Safe
         }
     });
     let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
-    let safety_context =
-        if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
+    let mut warnings = Vec::new();
     let mut visitor = UnsafetyVisitor {
         tcx,
         thir,
         safety_context,
         hir_context: hir_id,
-        body_unsafety,
         body_target_features,
         assignment_info: None,
         in_union_destructure: false,
         param_env: tcx.param_env(def),
         inside_adt: false,
+        warnings: &mut warnings,
     };
     visitor.visit_expr(&thir[expr]);
+
+    warnings.sort_by_key(|w| w.block_span);
+    for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings {
+        let block_span = tcx.sess.source_map().guess_head_span(block_span);
+        tcx.emit_spanned_lint(
+            UNUSED_UNSAFE,
+            hir_id,
+            block_span,
+            UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
+        );
+    }
 }
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index c09dd186418..730670a8369 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -392,11 +392,6 @@ pub enum UnusedUnsafeEnclosing {
         #[primary_span]
         span: Span,
     },
-    #[label(mir_build_unused_unsafe_enclosing_fn_label)]
-    Function {
-        #[primary_span]
-        span: Span,
-    },
 }
 
 pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 099fefbf068..745c3046d22 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -20,7 +20,7 @@ mod build;
 mod check_unsafety;
 mod errors;
 pub mod lints;
-pub mod thir;
+mod thir;
 
 use rustc_middle::query::Providers;
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 840c6e13bef..6c3564a20f6 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -191,11 +191,16 @@ impl<'tcx> Cx<'tcx> {
                 source: self.mirror_expr(source),
                 cast: PointerCoercion::ArrayToPointer,
             }
-        } else {
-            // check whether this is casting an enum variant discriminant
-            // to prevent cycles, we refer to the discriminant initializer
+        } else if let hir::ExprKind::Path(ref qpath) = source.kind
+           && let res = self.typeck_results().qpath_res(qpath, source.hir_id)
+           && let ty = self.typeck_results().node_type(source.hir_id)
+           && let ty::Adt(adt_def, args) = ty.kind()
+           && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
+        {
+            // Check whether this is casting an enum variant discriminant.
+            // To prevent cycles, we refer to the discriminant initializer,
             // which is always an integer and thus doesn't need to know the
-            // enum's layout (or its tag type) to compute it during const eval
+            // enum's layout (or its tag type) to compute it during const eval.
             // Example:
             // enum Foo {
             //     A,
@@ -204,21 +209,6 @@ impl<'tcx> Cx<'tcx> {
             // The correct solution would be to add symbolic computations to miri,
             // so we wouldn't have to compute and store the actual value
 
-            let hir::ExprKind::Path(ref qpath) = source.kind else {
-                return ExprKind::Cast { source: self.mirror_expr(source) };
-            };
-
-            let res = self.typeck_results().qpath_res(qpath, source.hir_id);
-            let ty = self.typeck_results().node_type(source.hir_id);
-            let ty::Adt(adt_def, args) = ty.kind() else {
-                return ExprKind::Cast { source: self.mirror_expr(source) };
-            };
-
-            let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
-            else {
-                return ExprKind::Cast { source: self.mirror_expr(source) };
-            };
-
             let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
             let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx);
 
@@ -255,6 +245,10 @@ impl<'tcx> Cx<'tcx> {
             };
 
             ExprKind::Cast { source }
+        } else {
+            // Default to `ExprKind::Cast` for all explicit casts.
+            // MIR building then picks the right MIR casts based on the types.
+            ExprKind::Cast { source: self.mirror_expr(source) }
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 86018340a69..2255220808e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -1326,7 +1326,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
         let ctor;
         let fields;
         match &pat.kind {
-            PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern),
+            PatKind::AscribeUserType { subpattern, .. }
+            | PatKind::InlineConstant { subpattern, .. } => return mkpat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 76ed6d2b6d7..dd71ab1f8e5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -27,6 +27,7 @@ use rustc_middle::ty::{
     self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt,
     TypeVisitableExt, UserType,
 };
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
 use rustc_target::abi::{FieldIdx, Integer};
 
@@ -88,15 +89,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     fn lower_pattern_range_endpoint(
         &mut self,
         expr: Option<&'tcx hir::Expr<'tcx>>,
-    ) -> Result<(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>), ErrorGuaranteed> {
+    ) -> Result<
+        (Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
+        ErrorGuaranteed,
+    > {
         match expr {
-            None => Ok((None, None)),
+            None => Ok((None, None, None)),
             Some(expr) => {
-                let (kind, ascr) = match self.lower_lit(expr) {
+                let (kind, ascr, inline_const) = match self.lower_lit(expr) {
+                    PatKind::InlineConstant { subpattern, def } => {
+                        (subpattern.kind, None, Some(def))
+                    }
                     PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
-                        (kind, Some(ascription))
+                        (kind, Some(ascription), None)
                     }
-                    kind => (kind, None),
+                    kind => (kind, None, None),
                 };
                 let value = if let PatKind::Constant { value } = kind {
                     value
@@ -106,7 +113,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     );
                     return Err(self.tcx.sess.delay_span_bug(expr.span, msg));
                 };
-                Ok((Some(value), ascr))
+                Ok((Some(value), ascr, inline_const))
             }
         }
     }
@@ -177,8 +184,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             return Err(self.tcx.sess.delay_span_bug(span, msg));
         }
 
-        let (lo, lo_ascr) = self.lower_pattern_range_endpoint(lo_expr)?;
-        let (hi, hi_ascr) = self.lower_pattern_range_endpoint(hi_expr)?;
+        let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?;
+        let (hi, hi_ascr, hi_inline) = self.lower_pattern_range_endpoint(hi_expr)?;
 
         let lo = lo.unwrap_or_else(|| {
             // Unwrap is ok because the type is known to be numeric.
@@ -237,6 +244,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 };
             }
         }
+        for inline_const in [lo_inline, hi_inline] {
+            if let Some(def) = inline_const {
+                kind =
+                    PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) };
+            }
+        }
         Ok(kind)
     }
 
@@ -599,11 +612,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // const eval path below.
         // FIXME: investigate the performance impact of removing this.
         let lit_input = match expr.kind {
-            hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
-            hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
-                hir::ExprKind::Lit(ref lit) => {
-                    Some(LitToConstInput { lit: &lit.node, ty, neg: true })
-                }
+            hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+            hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
+                hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }),
                 _ => None,
             },
             _ => None,
@@ -633,13 +644,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         if let Ok(Some(valtree)) =
             self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
         {
-            self.const_to_pat(
+            let subpattern = self.const_to_pat(
                 Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
                 id,
                 span,
                 None,
-            )
-            .kind
+            );
+            PatKind::InlineConstant { subpattern, def: def_id }
         } else {
             // If that fails, convert it to an opaque constant pattern.
             match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
@@ -822,6 +833,9 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
                 PatKind::Deref { subpattern: subpattern.fold_with(folder) }
             }
             PatKind::Constant { value } => PatKind::Constant { value },
+            PatKind::InlineConstant { def, subpattern: ref pattern } => {
+                PatKind::InlineConstant { def, subpattern: pattern.fold_with(folder) }
+            }
             PatKind::Range(ref range) => PatKind::Range(range.clone()),
             PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
                 prefix: prefix.fold_with(folder),
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index c957611b975..c3b2309b7cd 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -692,7 +692,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
             }
             PatKind::Deref { subpattern } => {
                 print_indented!(self, "Deref { ", depth_lvl + 1);
-                print_indented!(self, "subpattern: ", depth_lvl + 2);
+                print_indented!(self, "subpattern:", depth_lvl + 2);
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
@@ -701,6 +701,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
+            PatKind::InlineConstant { def, subpattern } => {
+                print_indented!(self, "InlineConstant {", depth_lvl + 1);
+                print_indented!(self, format!("def: {:?}", def), depth_lvl + 2);
+                print_indented!(self, "subpattern:", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
             PatKind::Range(pat_range) => {
                 print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
             }
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 85a0be8a44c..2c29978173f 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -2,13 +2,13 @@
 //!
 //! Currently, this pass only propagates scalar values.
 
-use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
+use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{
     Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
@@ -16,8 +16,9 @@ use rustc_mir_dataflow::value_analysis::{
 use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
 use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
-use rustc_target::abi::{FieldIdx, VariantIdx};
+use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
 
+use crate::const_prop::throw_machine_stop_str;
 use crate::MirPass;
 
 // These constants are somewhat random guesses and have not been optimized.
@@ -553,16 +554,151 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
 
     fn try_make_constant(
         &self,
+        ecx: &mut InterpCx<'tcx, 'tcx, DummyMachine>,
         place: Place<'tcx>,
         state: &State<FlatSet<Scalar>>,
         map: &Map,
     ) -> Option<Const<'tcx>> {
-        let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
-            return None;
-        };
         let ty = place.ty(self.local_decls, self.patch.tcx).ty;
-        Some(Const::Val(ConstValue::Scalar(value.into()), ty))
+        let layout = ecx.layout_of(ty).ok()?;
+
+        if layout.is_zst() {
+            return Some(Const::zero_sized(ty));
+        }
+
+        if layout.is_unsized() {
+            return None;
+        }
+
+        let place = map.find(place.as_ref())?;
+        if layout.abi.is_scalar()
+            && let Some(value) = propagatable_scalar(place, state, map)
+        {
+            return Some(Const::Val(ConstValue::Scalar(value), ty));
+        }
+
+        if matches!(layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
+            let alloc_id = ecx
+                .intern_with_temp_alloc(layout, |ecx, dest| {
+                    try_write_constant(ecx, dest, place, ty, state, map)
+                })
+                .ok()?;
+            return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty));
+        }
+
+        None
+    }
+}
+
+fn propagatable_scalar(
+    place: PlaceIndex,
+    state: &State<FlatSet<Scalar>>,
+    map: &Map,
+) -> Option<Scalar> {
+    if let FlatSet::Elem(value) = state.get_idx(place, map) && value.try_to_int().is_ok() {
+        // Do not attempt to propagate pointers, as we may fail to preserve their identity.
+        Some(value)
+    } else {
+        None
+    }
+}
+
+#[instrument(level = "trace", skip(ecx, state, map))]
+fn try_write_constant<'tcx>(
+    ecx: &mut InterpCx<'_, 'tcx, DummyMachine>,
+    dest: &PlaceTy<'tcx>,
+    place: PlaceIndex,
+    ty: Ty<'tcx>,
+    state: &State<FlatSet<Scalar>>,
+    map: &Map,
+) -> InterpResult<'tcx> {
+    let layout = ecx.layout_of(ty)?;
+
+    // Fast path for ZSTs.
+    if layout.is_zst() {
+        return Ok(());
+    }
+
+    // Fast path for scalars.
+    if layout.abi.is_scalar()
+        && let Some(value) = propagatable_scalar(place, state, map)
+    {
+        return ecx.write_immediate(Immediate::Scalar(value), dest);
+    }
+
+    match ty.kind() {
+        // ZSTs. Nothing to do.
+        ty::FnDef(..) => {}
+
+        // Those are scalars, must be handled above.
+        ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => throw_machine_stop_str!("primitive type with provenance"),
+
+        ty::Tuple(elem_tys) => {
+            for (i, elem) in elem_tys.iter().enumerate() {
+                let Some(field) = map.apply(place, TrackElem::Field(FieldIdx::from_usize(i))) else {
+                    throw_machine_stop_str!("missing field in tuple")
+                };
+                let field_dest = ecx.project_field(dest, i)?;
+                try_write_constant(ecx, &field_dest, field, elem, state, map)?;
+            }
+        }
+
+        ty::Adt(def, args) => {
+            if def.is_union() {
+                throw_machine_stop_str!("cannot propagate unions")
+            }
+
+            let (variant_idx, variant_def, variant_place, variant_dest) = if def.is_enum() {
+                let Some(discr) = map.apply(place, TrackElem::Discriminant) else {
+                    throw_machine_stop_str!("missing discriminant for enum")
+                };
+                let FlatSet::Elem(Scalar::Int(discr)) = state.get_idx(discr, map) else {
+                    throw_machine_stop_str!("discriminant with provenance")
+                };
+                let discr_bits = discr.assert_bits(discr.size());
+                let Some((variant, _)) = def.discriminants(*ecx.tcx).find(|(_, var)| discr_bits == var.val) else {
+                    throw_machine_stop_str!("illegal discriminant for enum")
+                };
+                let Some(variant_place) = map.apply(place, TrackElem::Variant(variant)) else {
+                    throw_machine_stop_str!("missing variant for enum")
+                };
+                let variant_dest = ecx.project_downcast(dest, variant)?;
+                (variant, def.variant(variant), variant_place, variant_dest)
+            } else {
+                (FIRST_VARIANT, def.non_enum_variant(), place, dest.clone())
+            };
+
+            for (i, field) in variant_def.fields.iter_enumerated() {
+                let ty = field.ty(*ecx.tcx, args);
+                let Some(field) = map.apply(variant_place, TrackElem::Field(i)) else {
+                    throw_machine_stop_str!("missing field in ADT")
+                };
+                let field_dest = ecx.project_field(&variant_dest, i.as_usize())?;
+                try_write_constant(ecx, &field_dest, field, ty, state, map)?;
+            }
+            ecx.write_discriminant(variant_idx, dest)?;
+        }
+
+        // Unsupported for now.
+        ty::Array(_, _)
+
+        // Do not attempt to support indirection in constants.
+        | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_)
+
+        | ty::Never
+        | ty::Foreign(..)
+        | ty::Alias(..)
+        | ty::Param(_)
+        | ty::Bound(..)
+        | ty::Placeholder(..)
+        | ty::Closure(..)
+        | ty::Coroutine(..)
+        | ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"),
+
+        ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(),
     }
+
+    Ok(())
 }
 
 impl<'mir, 'tcx>
@@ -580,8 +716,13 @@ impl<'mir, 'tcx>
     ) {
         match &statement.kind {
             StatementKind::Assign(box (_, rvalue)) => {
-                OperandCollector { state, visitor: self, map: &results.analysis.0.map }
-                    .visit_rvalue(rvalue, location);
+                OperandCollector {
+                    state,
+                    visitor: self,
+                    ecx: &mut results.analysis.0.ecx,
+                    map: &results.analysis.0.map,
+                }
+                .visit_rvalue(rvalue, location);
             }
             _ => (),
         }
@@ -599,7 +740,12 @@ impl<'mir, 'tcx>
                 // Don't overwrite the assignment if it already uses a constant (to keep the span).
             }
             StatementKind::Assign(box (place, _)) => {
-                if let Some(value) = self.try_make_constant(place, state, &results.analysis.0.map) {
+                if let Some(value) = self.try_make_constant(
+                    &mut results.analysis.0.ecx,
+                    place,
+                    state,
+                    &results.analysis.0.map,
+                ) {
                     self.patch.assignments.insert(location, value);
                 }
             }
@@ -614,8 +760,13 @@ impl<'mir, 'tcx>
         terminator: &'mir Terminator<'tcx>,
         location: Location,
     ) {
-        OperandCollector { state, visitor: self, map: &results.analysis.0.map }
-            .visit_terminator(terminator, location);
+        OperandCollector {
+            state,
+            visitor: self,
+            ecx: &mut results.analysis.0.ecx,
+            map: &results.analysis.0.map,
+        }
+        .visit_terminator(terminator, location);
     }
 }
 
@@ -670,6 +821,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
 struct OperandCollector<'tcx, 'map, 'locals, 'a> {
     state: &'a State<FlatSet<Scalar>>,
     visitor: &'a mut Collector<'tcx, 'locals>,
+    ecx: &'map mut InterpCx<'tcx, 'tcx, DummyMachine>,
     map: &'map Map,
 }
 
@@ -682,7 +834,7 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
         location: Location,
     ) {
         if let PlaceElem::Index(local) = elem
-            && let Some(value) = self.visitor.try_make_constant(local.into(), self.state, self.map)
+            && let Some(value) = self.visitor.try_make_constant(self.ecx, local.into(), self.state, self.map)
         {
             self.visitor.patch.before_effect.insert((location, local.into()), value);
         }
@@ -690,7 +842,9 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
 
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         if let Some(place) = operand.place() {
-            if let Some(value) = self.visitor.try_make_constant(place, self.state, self.map) {
+            if let Some(value) =
+                self.visitor.try_make_constant(self.ecx, place, self.state, self.map)
+            {
                 self.visitor.patch.before_effect.insert((location, place), value);
             } else if !place.projection.is_empty() {
                 // Try to propagate into `Index` projections.
@@ -713,7 +867,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
     }
 
     fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
-        unimplemented!()
+        false
     }
 
     fn before_access_global(
@@ -725,13 +879,13 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         is_write: bool,
     ) -> InterpResult<'tcx> {
         if is_write {
-            crate::const_prop::throw_machine_stop_str!("can't write to global");
+            throw_machine_stop_str!("can't write to global");
         }
 
         // If the static allocation is mutable, then we can't const prop it as its content
         // might be different at runtime.
         if alloc.inner().mutability.is_mut() {
-            crate::const_prop::throw_machine_stop_str!("can't access mutable globals in ConstProp");
+            throw_machine_stop_str!("can't access mutable globals in ConstProp");
         }
 
         Ok(())
@@ -781,7 +935,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
         _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
         _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
     ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
-        crate::const_prop::throw_machine_stop_str!("can't do pointer arithmetic");
+        throw_machine_stop_str!("can't do pointer arithmetic");
     }
 
     fn expose_ptr(
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 8b33e00c63c..277060573bc 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -438,10 +438,8 @@ impl<'tcx> Inliner<'tcx> {
             return Err("incompatible instruction set");
         }
 
-        for feature in &callee_attrs.target_features {
-            if !self.codegen_fn_attrs.target_features.contains(feature) {
-                return Err("incompatible target feature");
-            }
+        if callee_attrs.target_features != self.codegen_fn_attrs.target_features {
+            return Err("incompatible target features");
         }
 
         Ok(())
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 25ef5245cf1..84d3b84e13f 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -402,11 +402,6 @@ passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]
 
 passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
 
-passes_invalid_stability =
-    invalid stability version found
-    .label = invalid stability version
-    .item = the stability attribute annotates this item
-
 passes_lang_item_fn_with_target_feature =
     `{$name}` language item function is not allowed to have `#[target_feature]`
     .label = `{$name}` language item function is not allowed to have `#[target_feature]`
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 6f87b56c636..6e840f24c69 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1505,16 +1505,6 @@ pub struct UselessStability {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_invalid_stability)]
-pub struct InvalidStability {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(passes_item)]
-    pub item_sp: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_cannot_stabilize_deprecated)]
 pub struct CannotStabilizeDeprecated {
     #[primary_span]
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index bb23dc257d7..41a240fa880 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -3,7 +3,7 @@
 
 use crate::errors;
 use rustc_attr::{
-    self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
+    self as attr, rust_version_symbol, ConstStability, Since, Stability, StabilityLevel, Unstable,
     UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
@@ -226,37 +226,43 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
                 (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
             {
-                // Explicit version of iter::order::lt to handle parse errors properly
-                for (dep_v, stab_v) in
-                    iter::zip(dep_since.as_str().split('.'), stab_since.as_str().split('.'))
-                {
-                    match stab_v.parse::<u64>() {
-                        Err(_) => {
-                            self.tcx.sess.emit_err(errors::InvalidStability { span, item_sp });
-                            break;
-                        }
-                        Ok(stab_vp) => match dep_v.parse::<u64>() {
-                            Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
-                                Ordering::Less => {
-                                    self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated {
-                                        span,
-                                        item_sp,
-                                    });
+                match stab_since {
+                    Since::Current => {
+                        self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
+                    }
+                    Since::Version(stab_since) => {
+                        // Explicit version of iter::order::lt to handle parse errors properly
+                        for (dep_v, stab_v) in iter::zip(
+                            dep_since.as_str().split('.'),
+                            [stab_since.major, stab_since.minor, stab_since.patch],
+                        ) {
+                            match dep_v.parse::<u64>() {
+                                Ok(dep_vp) => match dep_vp.cmp(&u64::from(stab_v)) {
+                                    Ordering::Less => {
+                                        self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated {
+                                            span,
+                                            item_sp,
+                                        });
+                                        break;
+                                    }
+                                    Ordering::Equal => continue,
+                                    Ordering::Greater => break,
+                                },
+                                Err(_) => {
+                                    if dep_v != "TBD" {
+                                        self.tcx.sess.emit_err(errors::InvalidDeprecationVersion {
+                                            span,
+                                            item_sp,
+                                        });
+                                    }
                                     break;
                                 }
-                                Ordering::Equal => continue,
-                                Ordering::Greater => break,
-                            },
-                            Err(_) => {
-                                if dep_v != "TBD" {
-                                    self.tcx.sess.emit_err(errors::InvalidDeprecationVersion {
-                                        span,
-                                        item_sp,
-                                    });
-                                }
-                                break;
                             }
-                        },
+                        }
+                    }
+                    Since::Err => {
+                        // An error already reported. Assume the unparseable stabilization
+                        // version is older than the deprecation version.
                     }
                 }
             }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index f2d6a0dff9c..4bb7e65747f 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -210,22 +210,7 @@ where
                     }
                 }
             }
-            ty::Alias(ty::Weak, alias) => {
-                self.def_id_visitor.visit_def_id(alias.def_id, "type alias", &ty);
-            }
-            ty::Alias(ty::Projection, proj) => {
-                if V::SKIP_ASSOC_TYS {
-                    // Visitors searching for minimal visibility/reachability want to
-                    // conservatively approximate associated types like `<Type as Trait>::Alias`
-                    // as visible/reachable even if both `Type` and `Trait` are private.
-                    // Ideally, associated types should be substituted in the same way as
-                    // free type aliases, but this isn't done yet.
-                    return ControlFlow::Continue(());
-                }
-                // This will also visit args if necessary, so we don't need to recurse.
-                return self.visit_projection_ty(proj);
-            }
-            ty::Alias(ty::Inherent, data) => {
+            ty::Alias(kind @ (ty::Inherent | ty::Weak | ty::Projection), data) => {
                 if V::SKIP_ASSOC_TYS {
                     // Visitors searching for minimal visibility/reachability want to
                     // conservatively approximate associated types like `Type::Alias`
@@ -235,9 +220,14 @@ where
                     return ControlFlow::Continue(());
                 }
 
+                let kind = match kind {
+                    ty::Inherent | ty::Projection => "associated type",
+                    ty::Weak => "type alias",
+                    ty::Opaque => unreachable!(),
+                };
                 self.def_id_visitor.visit_def_id(
                     data.def_id,
-                    "associated type",
+                    kind,
                     &LazyDefPathStr { def_id: data.def_id, tcx },
                 )?;
 
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 352bf98d01f..3b1f957c890 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -335,7 +335,7 @@ impl Resolver<'_, '_> {
 
         for unused in visitor.unused_imports.values() {
             let mut fixes = Vec::new();
-            let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
+            let spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
                 UnusedSpanResult::Used => continue,
                 UnusedSpanResult::FlatUnused(span, remove) => {
                     fixes.push((remove, String::new()));
@@ -353,20 +353,19 @@ impl Resolver<'_, '_> {
                 }
             };
 
-            let len = spans.len();
-            spans.sort();
-            let ms = MultiSpan::from_spans(spans.clone());
-            let mut span_snippets = spans
+            let ms = MultiSpan::from_spans(spans);
+
+            let mut span_snippets = ms
+                .primary_spans()
                 .iter()
-                .filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
-                    Ok(s) => Some(format!("`{s}`")),
-                    _ => None,
-                })
+                .filter_map(|span| tcx.sess.source_map().span_to_snippet(*span).ok())
+                .map(|s| format!("`{s}`"))
                 .collect::<Vec<String>>();
             span_snippets.sort();
+
             let msg = format!(
                 "unused import{}{}",
-                pluralize!(len),
+                pluralize!(ms.primary_spans().len()),
                 if !span_snippets.is_empty() {
                     format!(": {}", span_snippets.join(", "))
                 } else {
@@ -376,7 +375,7 @@ impl Resolver<'_, '_> {
 
             let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
                 "remove the whole `use` item"
-            } else if spans.len() > 1 {
+            } else if ms.primary_spans().len() > 1 {
                 "remove the unused imports"
             } else {
                 "remove the unused import"
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 4ad838e5aed..edcc22d56c6 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -25,7 +25,7 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
-use thin_vec::ThinVec;
+use thin_vec::{thin_vec, ThinVec};
 
 use crate::errors::{
     AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
@@ -1147,7 +1147,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         namespace: Namespace,
         parent_scope: &ParentScope<'a>,
         start_module: Module<'a>,
-        crate_name: Ident,
+        crate_path: ThinVec<ast::PathSegment>,
         filter_fn: FilterFn,
     ) -> Vec<ImportSuggestion>
     where
@@ -1163,8 +1163,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             Some(x) => Some(x),
         } {
             let in_module_is_extern = !in_module.def_id().is_local();
-            // We have to visit module children in deterministic order to avoid
-            // instabilities in reported imports (#43552).
             in_module.for_each_child(self, |this, ident, ns, name_binding| {
                 // avoid non-importable candidates
                 if !name_binding.is_importable() {
@@ -1214,12 +1212,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     let res = name_binding.res();
                     if filter_fn(res) {
                         // create the path
-                        let mut segms = path_segments.clone();
-                        if lookup_ident.span.at_least_rust_2018() {
+                        let mut segms = if lookup_ident.span.at_least_rust_2018() {
                             // crate-local absolute paths start with `crate::` in edition 2018
                             // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
-                            segms.insert(0, ast::PathSegment::from_ident(crate_name));
-                        }
+                            crate_path.clone()
+                        } else {
+                            ThinVec::new()
+                        };
+                        segms.append(&mut path_segments.clone());
 
                         segms.push(ast::PathSegment::from_ident(ident));
                         let path = Path { span: name_binding.span, segments: segms, tokens: None };
@@ -1318,18 +1318,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     where
         FilterFn: Fn(Res) -> bool,
     {
+        let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
         let mut suggestions = self.lookup_import_candidates_from_module(
             lookup_ident,
             namespace,
             parent_scope,
             self.graph_root,
-            Ident::with_dummy_span(kw::Crate),
+            crate_path,
             &filter_fn,
         );
 
         if lookup_ident.span.at_least_rust_2018() {
-            let extern_prelude_names = self.extern_prelude.clone();
-            for (ident, _) in extern_prelude_names.into_iter() {
+            for ident in self.extern_prelude.clone().into_keys() {
                 if ident.span.from_expansion() {
                     // Idents are adjusted to the root context before being
                     // resolved in the extern prelude, so reporting this to the
@@ -1340,13 +1340,43 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 }
                 let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name));
                 if let Some(crate_id) = crate_id {
-                    let crate_root = self.expect_module(crate_id.as_def_id());
+                    let crate_def_id = crate_id.as_def_id();
+                    let crate_root = self.expect_module(crate_def_id);
+
+                    // Check if there's already an item in scope with the same name as the crate.
+                    // If so, we have to disambiguate the potential import suggestions by making
+                    // the paths *global* (i.e., by prefixing them with `::`).
+                    let needs_disambiguation =
+                        self.resolutions(parent_scope.module).borrow().iter().any(
+                            |(key, name_resolution)| {
+                                if key.ns == TypeNS
+                                    && key.ident == ident
+                                    && let Some(binding) = name_resolution.borrow().binding
+                                {
+                                    match binding.res() {
+                                        // No disambiguation needed if the identically named item we
+                                        // found in scope actually refers to the crate in question.
+                                        Res::Def(_, def_id) => def_id != crate_def_id,
+                                        Res::PrimTy(_) => true,
+                                        _ => false,
+                                    }
+                                } else {
+                                    false
+                                }
+                            },
+                        );
+                    let mut crate_path = ThinVec::new();
+                    if needs_disambiguation {
+                        crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
+                    }
+                    crate_path.push(ast::PathSegment::from_ident(ident));
+
                     suggestions.extend(self.lookup_import_candidates_from_module(
                         lookup_ident,
                         namespace,
                         parent_scope,
                         crate_root,
-                        ident,
+                        crate_path,
                         &filter_fn,
                     ));
                 }
@@ -2554,7 +2584,7 @@ fn show_candidates(
 
     candidates.iter().for_each(|c| {
         (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
-            .push((path_names_to_string(&c.path), c.descr, c.did, &c.note, c.via_import))
+            .push((pprust::path_to_string(&c.path), c.descr, c.did, &c.note, c.via_import))
     });
 
     // we want consistent results across executions, but candidates are produced
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 462e7e85c65..78e410488c3 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -169,6 +169,9 @@ pub enum MirSpanview {
 pub enum InstrumentCoverage {
     /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
     All,
+    /// Additionally, instrument branches and output branch coverage.
+    /// `-Zunstable-options -C instrument-coverage=branch`
+    Branch,
     /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
     ExceptUnusedGenerics,
     /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
@@ -2736,26 +2739,24 @@ pub fn build_session_options(
         _ => {}
     }
 
-    // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
-    // precedence.
-    match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
-        (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
-            handler.early_error(
-                "incompatible values passed for `-C instrument-coverage` \
-                and `-Z instrument-coverage`",
-            );
-        }
-        (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
-        (Some(_), _) if !unstable_opts.unstable_options => {
-            handler.early_error("`-C instrument-coverage=except-*` requires `-Z unstable-options`");
-        }
-        (None, None) => {}
-        (None, ic) => {
-            handler
-                .early_warn("`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`");
-            cg.instrument_coverage = ic;
+    // Check for unstable values of `-C instrument-coverage`.
+    // This is what prevents them from being used on stable compilers.
+    match cg.instrument_coverage {
+        // Stable values:
+        Some(InstrumentCoverage::All | InstrumentCoverage::Off) | None => {}
+        // Unstable values:
+        Some(
+            InstrumentCoverage::Branch
+            | InstrumentCoverage::ExceptUnusedFunctions
+            | InstrumentCoverage::ExceptUnusedGenerics,
+        ) => {
+            if !unstable_opts.unstable_options {
+                handler.early_error(
+                    "`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
+                    require `-Z unstable-options`",
+                );
+            }
         }
-        _ => {}
     }
 
     if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index c090bcaf9d8..35c167837e5 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -389,7 +389,7 @@ mod desc {
     pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
     pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
     pub const parse_instrument_coverage: &str =
-        "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
+        "`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`";
     pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
     pub const parse_unpretty: &str = "`string` or `string=string`";
     pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
@@ -931,6 +931,7 @@ mod parse {
 
         *slot = Some(match v {
             "all" => InstrumentCoverage::All,
+            "branch" => InstrumentCoverage::Branch,
             "except-unused-generics" | "except_unused_generics" => {
                 InstrumentCoverage::ExceptUnusedGenerics
             }
@@ -1356,6 +1357,7 @@ options! {
         reports (note, the compiler build config must include `profiler = true`); \
         implies `-C symbol-mangling-version=v0`. Optional values are:
         `=all` (implicit value)
+        `=branch`
         `=except-unused-generics`
         `=except-unused-functions`
         `=off` (default)"),
@@ -1591,15 +1593,6 @@ options! {
         "a default MIR inlining threshold (default: 50)"),
     input_stats: bool = (false, parse_bool, [UNTRACKED],
         "gather statistics about the input (default: no)"),
-    #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
-    instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
-        "instrument the generated code to support LLVM source-based code coverage \
-        reports (note, the compiler build config must include `profiler = true`); \
-        implies `-C symbol-mangling-version=v0`. Optional values are:
-        `=all` (implicit value)
-        `=except-unused-generics`
-        `=except-unused-functions`
-        `=off` (default)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
     instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 79307498165..f823b556154 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -45,7 +45,7 @@ use std::fmt;
 use std::ops::{Div, Mul};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
-use std::sync::Arc;
+use std::sync::{atomic::AtomicBool, Arc};
 use std::time::Duration;
 
 pub struct OptimizationFuel {
@@ -202,6 +202,12 @@ pub struct Session {
     /// The version of the rustc process, possibly including a commit hash and description.
     pub cfg_version: &'static str,
 
+    /// The inner atomic value is set to true when a feature marked as `internal` is
+    /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
+    /// internal features are wontfix, and they are usually the cause of the ICEs.
+    /// None signifies that this is not tracked.
+    pub using_internal_features: Arc<AtomicBool>,
+
     /// All commandline args used to invoke the compiler, with @file args fully expanded.
     /// This will only be used within debug info, e.g. in the pdb file on windows
     /// This is mainly useful for other tools that reads that debuginfo to figure out
@@ -702,6 +708,10 @@ impl Session {
         self.opts.cg.instrument_coverage() != InstrumentCoverage::Off
     }
 
+    pub fn instrument_coverage_branch(&self) -> bool {
+        self.opts.cg.instrument_coverage() == InstrumentCoverage::Branch
+    }
+
     pub fn instrument_coverage_except_unused_generics(&self) -> bool {
         self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics
     }
@@ -1385,6 +1395,7 @@ pub fn build_session(
     target_override: Option<Target>,
     cfg_version: &'static str,
     ice_file: Option<PathBuf>,
+    using_internal_features: Arc<AtomicBool>,
     expanded_args: Vec<String>,
 ) -> Session {
     // FIXME: This is not general enough to make the warning lint completely override
@@ -1521,6 +1532,7 @@ pub fn build_session(
         target_features: Default::default(),
         unstable_target_features: Default::default(),
         cfg_version,
+        using_internal_features,
         expanded_args,
     };
 
diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml
index 41c7d3a8594..47dd7372f3d 100644
--- a/compiler/rustc_smir/Cargo.toml
+++ b/compiler/rustc_smir/Cargo.toml
@@ -9,6 +9,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+scoped-tls = "1.0"
 stable_mir = {path = "../stable_mir" }
 tracing = "0.1"
 
diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs
index c24b9efe865..dcf6b904077 100644
--- a/compiler/rustc_smir/src/lib.rs
+++ b/compiler/rustc_smir/src/lib.rs
@@ -13,6 +13,7 @@
 #![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![cfg_attr(not(bootstrap), allow(internal_features))]
+#![allow(rustc::usage_of_ty_tykind)]
 
 pub mod rustc_internal;
 
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index f42a9739320..78144524ac5 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -4,7 +4,7 @@
 //! due to incomplete stable coverage.
 
 // Prefer importing stable_mir over internal rustc constructs to make this file more readable.
-use crate::rustc_smir::{MaybeStable, Tables};
+use crate::rustc_smir::Tables;
 use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
 use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty};
 use stable_mir::DefId;
@@ -31,7 +31,7 @@ impl<'tcx> RustcInternal<'tcx> for GenericArgKind {
         match self {
             GenericArgKind::Lifetime(reg) => reg.internal(tables).into(),
             GenericArgKind::Type(ty) => ty.internal(tables).into(),
-            GenericArgKind::Const(cnst) => cnst.internal(tables).into(),
+            GenericArgKind::Const(cnst) => ty_const(cnst, tables).into(),
         }
     }
 }
@@ -46,16 +46,22 @@ impl<'tcx> RustcInternal<'tcx> for Region {
 impl<'tcx> RustcInternal<'tcx> for Ty {
     type T = InternalTy<'tcx>;
     fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        match tables.types[self.0] {
-            MaybeStable::Stable(_) => todo!(),
-            MaybeStable::Rustc(ty) => ty,
+        tables.types[*self]
+    }
+}
+
+fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> {
+    match constant.internal(tables) {
+        rustc_middle::mir::Const::Ty(c) => c,
+        cnst => {
+            panic!("Trying to covert constant `{constant:?}` to type constant, but found {cnst:?}")
         }
     }
 }
 
 impl<'tcx> RustcInternal<'tcx> for Const {
-    type T = rustc_ty::Const<'tcx>;
-    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
-        todo!()
+    type T = rustc_middle::mir::Const<'tcx>;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.constants[self.id]
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index f7e519570fa..4d2a518226d 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -3,7 +3,7 @@
 //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
 //! until stable MIR is complete.
 
-use crate::rustc_smir::Tables;
+use crate::rustc_smir::{Stable, Tables, TablesWrapper};
 use rustc_data_structures::fx;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_middle::mir::interpret::AllocId;
@@ -11,13 +11,24 @@ use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Span;
+use scoped_tls::scoped_thread_local;
 use stable_mir::ty::IndexedVal;
+use std::cell::Cell;
+use std::cell::RefCell;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Index;
 
 mod internal;
 
+pub fn stable<'tcx, S: Stable<'tcx>>(item: &S) -> S::T {
+    with_tables(|tables| item.stable(tables))
+}
+
+pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: &S) -> S::T {
+    with_tables(|tables| item.internal(tables))
+}
+
 impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
     type Output = DefId;
 
@@ -125,18 +136,42 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
     item.id.into()
 }
 
+// A thread local variable that stores a pointer to the tables mapping between TyCtxt
+// datastructures and stable MIR datastructures
+scoped_thread_local! (static TLV: Cell<*const ()>);
+
+pub(crate) fn init<'tcx>(tables: &TablesWrapper<'tcx>, f: impl FnOnce()) {
+    assert!(!TLV.is_set());
+    let ptr = tables as *const _ as *const ();
+    TLV.set(&Cell::new(ptr), || {
+        f();
+    });
+}
+
+/// Loads the current context and calls a function with it.
+/// Do not nest these, as that will ICE.
+pub(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R {
+    assert!(TLV.is_set());
+    TLV.with(|tlv| {
+        let ptr = tlv.get();
+        assert!(!ptr.is_null());
+        let wrapper = ptr as *const TablesWrapper<'tcx>;
+        let mut tables = unsafe { (*wrapper).0.borrow_mut() };
+        f(&mut *tables)
+    })
+}
+
 pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
-    stable_mir::run(
-        Tables {
-            tcx,
-            def_ids: IndexMap::default(),
-            alloc_ids: IndexMap::default(),
-            spans: IndexMap::default(),
-            types: vec![],
-            instances: IndexMap::default(),
-        },
-        f,
-    );
+    let tables = TablesWrapper(RefCell::new(Tables {
+        tcx,
+        def_ids: IndexMap::default(),
+        alloc_ids: IndexMap::default(),
+        spans: IndexMap::default(),
+        types: IndexMap::default(),
+        instances: IndexMap::default(),
+        constants: IndexMap::default(),
+    }));
+    stable_mir::run(&tables, || init(&tables, f));
 }
 
 #[macro_export]
@@ -251,7 +286,7 @@ impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V
 /// Trait used to translate a stable construct to its rustc counterpart.
 ///
 /// This is basically a mirror of [crate::rustc_smir::Stable].
-pub(crate) trait RustcInternal<'tcx> {
+pub trait RustcInternal<'tcx> {
     type T;
     fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T;
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index d5379797f1c..86b49eed4d1 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -20,30 +20,35 @@ use rustc_target::abi::FieldIdx;
 use stable_mir::mir::mono::InstanceDef;
 use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
 use stable_mir::ty::{
-    FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy,
+    Const, ConstId, ConstantKind, FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy,
+    Span, TyKind, UintTy,
 };
 use stable_mir::{self, opaque, Context, Filename};
+use std::cell::RefCell;
 use tracing::debug;
 
 mod alloc;
 mod builder;
 
-impl<'tcx> Context for Tables<'tcx> {
+impl<'tcx> Context for TablesWrapper<'tcx> {
     fn local_crate(&self) -> stable_mir::Crate {
-        smir_crate(self.tcx, LOCAL_CRATE)
+        let tables = self.0.borrow();
+        smir_crate(tables.tcx, LOCAL_CRATE)
     }
 
     fn external_crates(&self) -> Vec<stable_mir::Crate> {
-        self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect()
+        let tables = self.0.borrow();
+        tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
     }
 
     fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
+        let tables = self.0.borrow();
         let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
             .iter()
-            .chain(self.tcx.crates(()).iter())
+            .chain(tables.tcx.crates(()).iter())
             .map(|crate_num| {
-                let crate_name = self.tcx.crate_name(*crate_num).to_string();
-                (name == crate_name).then(|| smir_crate(self.tcx, *crate_num))
+                let crate_name = tables.tcx.crate_name(*crate_num).to_string();
+                (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num))
             })
             .into_iter()
             .filter_map(|c| c)
@@ -52,212 +57,213 @@ impl<'tcx> Context for Tables<'tcx> {
     }
 
     fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String {
-        self.tcx.def_path_str(self[def_id])
+        let tables = self.0.borrow();
+        tables.tcx.def_path_str(tables[def_id])
     }
 
     fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
-        self.tcx.sess.source_map().span_to_diagnostic_string(self[span])
+        let tables = self.0.borrow();
+        tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
     }
 
     fn get_filename(&self, span: &Span) -> Filename {
+        let tables = self.0.borrow();
         opaque(
-            &self
+            &tables
                 .tcx
                 .sess
                 .source_map()
-                .span_to_filename(self[*span])
+                .span_to_filename(tables[*span])
                 .display(rustc_span::FileNameDisplayPreference::Local)
                 .to_string(),
         )
     }
 
     fn get_lines(&self, span: &Span) -> LineInfo {
-        let lines = &self.tcx.sess.source_map().span_to_location_info(self[*span]);
+        let tables = self.0.borrow();
+        let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
         LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
     }
 
-    fn def_kind(&mut self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
-        self.tcx.def_kind(self[def_id]).stable(self)
+    fn def_kind(&self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.def_kind(tables[def_id]).stable(&mut *tables)
     }
 
-    fn span_of_an_item(&mut self, def_id: stable_mir::DefId) -> Span {
-        self.tcx.def_span(self[def_id]).stable(self)
+    fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
     }
 
-    fn all_local_items(&mut self) -> stable_mir::CrateItems {
-        self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect()
+    fn all_local_items(&self) -> stable_mir::CrateItems {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
     }
 
-    fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> {
-        Some(self.crate_item(self.tcx.entry_fn(())?.0))
+    fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        Some(tables.crate_item(tcx.entry_fn(())?.0))
     }
 
-    fn all_trait_decls(&mut self) -> stable_mir::TraitDecls {
-        self.tcx
+    fn all_trait_decls(&self) -> stable_mir::TraitDecls {
+        let mut tables = self.0.borrow_mut();
+        tables
+            .tcx
             .traits(LOCAL_CRATE)
             .iter()
-            .map(|trait_def_id| self.trait_def(*trait_def_id))
+            .map(|trait_def_id| tables.trait_def(*trait_def_id))
             .collect()
     }
 
-    fn trait_decl(&mut self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
-        let def_id = self[trait_def.0];
-        let trait_def = self.tcx.trait_def(def_id);
-        trait_def.stable(self)
+    fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[trait_def.0];
+        let trait_def = tables.tcx.trait_def(def_id);
+        trait_def.stable(&mut *tables)
     }
 
-    fn all_trait_impls(&mut self) -> stable_mir::ImplTraitDecls {
-        self.tcx
+    fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
+        let mut tables = self.0.borrow_mut();
+        tables
+            .tcx
             .trait_impls_in_crate(LOCAL_CRATE)
             .iter()
-            .map(|impl_def_id| self.impl_def(*impl_def_id))
+            .map(|impl_def_id| tables.impl_def(*impl_def_id))
             .collect()
     }
 
-    fn trait_impl(&mut self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
-        let def_id = self[impl_def.0];
-        let impl_trait = self.tcx.impl_trait_ref(def_id).unwrap();
-        impl_trait.stable(self)
+    fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[impl_def.0];
+        let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
+        impl_trait.stable(&mut *tables)
     }
 
-    fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body {
-        let def_id = self[item];
-        self.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(self)
+    fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[item];
+        tables.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(&mut tables)
     }
 
-    fn ty_kind(&mut self, ty: stable_mir::ty::Ty) -> TyKind {
-        self.types[ty.0].clone().stable(self)
+    fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
+        let mut tables = self.0.borrow_mut();
+        tables.types[ty].kind().stable(&mut *tables)
     }
 
-    fn mk_ty(&mut self, kind: TyKind) -> stable_mir::ty::Ty {
-        let n = self.types.len();
-        self.types.push(MaybeStable::Stable(kind));
-        stable_mir::ty::Ty(n)
+    fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let generics = tables.tcx.generics_of(def_id);
+        generics.stable(&mut *tables)
     }
 
-    fn generics_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
-        let def_id = self[def_id];
-        let generics = self.tcx.generics_of(def_id);
-        generics.stable(self)
-    }
-
-    fn predicates_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
-        let def_id = self[def_id];
-        let ty::GenericPredicates { parent, predicates } = self.tcx.predicates_of(def_id);
+    fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let ty::GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
         stable_mir::ty::GenericPredicates {
-            parent: parent.map(|did| self.trait_def(did)),
+            parent: parent.map(|did| tables.trait_def(did)),
             predicates: predicates
                 .iter()
                 .map(|(clause, span)| {
-                    (clause.as_predicate().kind().skip_binder().stable(self), span.stable(self))
+                    (
+                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
+                        span.stable(&mut *tables),
+                    )
                 })
                 .collect(),
         }
     }
 
     fn explicit_predicates_of(
-        &mut self,
+        &self,
         def_id: stable_mir::DefId,
     ) -> stable_mir::ty::GenericPredicates {
-        let def_id = self[def_id];
-        let ty::GenericPredicates { parent, predicates } = self.tcx.explicit_predicates_of(def_id);
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let ty::GenericPredicates { parent, predicates } =
+            tables.tcx.explicit_predicates_of(def_id);
         stable_mir::ty::GenericPredicates {
-            parent: parent.map(|did| self.trait_def(did)),
+            parent: parent.map(|did| tables.trait_def(did)),
             predicates: predicates
                 .iter()
                 .map(|(clause, span)| {
-                    (clause.as_predicate().kind().skip_binder().stable(self), span.stable(self))
+                    (
+                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
+                        span.stable(&mut *tables),
+                    )
                 })
                 .collect(),
         }
     }
 
-    fn instance_body(&mut self, def: InstanceDef) -> Body {
-        let instance = self.instances[def];
-        builder::BodyBuilder::new(self.tcx, instance).build(self)
+    fn instance_body(&self, def: InstanceDef) -> Body {
+        let mut tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables)
     }
 
-    fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty {
-        let instance = self.instances[def];
-        let ty = instance.ty(self.tcx, ParamEnv::empty());
-        self.intern_ty(ty)
+    fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
+        let mut tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        instance.ty(tables.tcx, ParamEnv::empty()).stable(&mut *tables)
     }
 
-    fn instance_def_id(&mut self, def: InstanceDef) -> stable_mir::DefId {
-        let def_id = self.instances[def].def_id();
-        self.create_def_id(def_id)
+    fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables.instances[def].def_id();
+        tables.create_def_id(def_id)
     }
 
-    fn mono_instance(&mut self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
-        let def_id = self[item.0];
-        Instance::mono(self.tcx, def_id).stable(self)
+    fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[item.0];
+        Instance::mono(tables.tcx, def_id).stable(&mut *tables)
     }
 
     fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
-        let def_id = self[def_id];
-        let generics = self.tcx.generics_of(def_id);
-        let result = generics.requires_monomorphization(self.tcx);
+        let tables = self.0.borrow();
+        let def_id = tables[def_id];
+        let generics = tables.tcx.generics_of(def_id);
+        let result = generics.requires_monomorphization(tables.tcx);
         result
     }
 
     fn resolve_instance(
-        &mut self,
+        &self,
         def: stable_mir::ty::FnDef,
         args: &stable_mir::ty::GenericArgs,
     ) -> Option<stable_mir::mir::mono::Instance> {
-        let def_id = def.0.internal(self);
-        let args_ref = args.internal(self);
-        match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
-            Ok(Some(instance)) => Some(instance.stable(self)),
+        let mut tables = self.0.borrow_mut();
+        let def_id = def.0.internal(&mut *tables);
+        let args_ref = args.internal(&mut *tables);
+        match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
+            Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
             Ok(None) | Err(_) => None,
         }
     }
 }
 
-#[derive(Clone)]
-pub enum MaybeStable<S, R> {
-    Stable(S),
-    Rustc(R),
-}
-
-impl<'tcx, S, R> MaybeStable<S, R> {
-    fn stable(self, tables: &mut Tables<'tcx>) -> S
-    where
-        R: Stable<'tcx, T = S>,
-    {
-        match self {
-            MaybeStable::Stable(s) => s,
-            MaybeStable::Rustc(r) => r.stable(tables),
-        }
-    }
-}
-
-impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> {
-    fn eq(&self, other: &R) -> bool {
-        match self {
-            MaybeStable::Stable(_) => false,
-            MaybeStable::Rustc(r) => r == other,
-        }
-    }
-}
+pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
 
 pub struct Tables<'tcx> {
-    pub tcx: TyCtxt<'tcx>,
-    pub def_ids: IndexMap<DefId, stable_mir::DefId>,
-    pub alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
-    pub spans: IndexMap<rustc_span::Span, Span>,
-    pub types: Vec<MaybeStable<TyKind, Ty<'tcx>>>,
-    pub instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
+    pub(crate) tcx: TyCtxt<'tcx>,
+    pub(crate) def_ids: IndexMap<DefId, stable_mir::DefId>,
+    pub(crate) alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
+    pub(crate) spans: IndexMap<rustc_span::Span, Span>,
+    pub(crate) types: IndexMap<Ty<'tcx>, stable_mir::ty::Ty>,
+    pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
+    pub(crate) constants: IndexMap<mir::Const<'tcx>, ConstId>,
 }
 
 impl<'tcx> Tables<'tcx> {
     fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
-        if let Some(id) = self.types.iter().position(|t| *t == ty) {
-            return stable_mir::ty::Ty(id);
-        }
-        let id = self.types.len();
-        self.types.push(MaybeStable::Rustc(ty));
-        stable_mir::ty::Ty(id)
+        self.types.create_or_fetch(ty)
+    }
+
+    fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId {
+        self.constants.create_or_fetch(constant)
     }
 }
 
@@ -270,7 +276,7 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
 }
 
 /// Trait used to convert between an internal MIR type to a Stable MIR type.
-pub(crate) trait Stable<'tcx> {
+pub trait Stable<'tcx> {
     /// The stable representation of the type implementing Stable.
     type T;
     /// Converts an object to the equivalent Stable MIR representation.
@@ -281,9 +287,8 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
     type T = stable_mir::mir::Body;
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        stable_mir::mir::Body {
-            blocks: self
-                .basic_blocks
+        stable_mir::mir::Body::new(
+            self.basic_blocks
                 .iter()
                 .map(|block| stable_mir::mir::BasicBlock {
                     terminator: block.terminator().stable(tables),
@@ -294,15 +299,15 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
                         .collect(),
                 })
                 .collect(),
-            locals: self
-                .local_decls
+            self.local_decls
                 .iter()
                 .map(|decl| stable_mir::mir::LocalDecl {
-                    ty: tables.intern_ty(decl.ty),
+                    ty: decl.ty.stable(tables),
                     span: decl.source_info.span.stable(tables),
                 })
                 .collect(),
-        }
+            self.arg_count,
+        )
     }
 }
 
@@ -396,7 +401,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
             Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
                 cast_kind.stable(tables),
                 op.stable(tables),
-                tables.intern_ty(*ty),
+                ty.stable(tables),
             ),
             BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp(
                 bin_op.stable(tables),
@@ -409,7 +414,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
                 ops.1.stable(tables),
             ),
             NullaryOp(null_op, ty) => {
-                stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), tables.intern_ty(*ty))
+                stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables))
             }
             UnaryOp(un_op, op) => {
                 stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables))
@@ -420,7 +425,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
                 stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands)
             }
             ShallowInitBox(op, ty) => {
-                stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), tables.intern_ty(*ty))
+                stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
             }
             CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
         }
@@ -564,7 +569,7 @@ impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> {
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         use stable_mir::ty::TermKind;
         match self {
-            ty::TermKind::Ty(ty) => TermKind::Type(tables.intern_ty(*ty)),
+            ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables)),
             ty::TermKind::Const(cnst) => {
                 let cnst = cnst.stable(tables);
                 TermKind::Const(cnst)
@@ -845,7 +850,7 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         match self {
             mir::AggregateKind::Array(ty) => {
-                stable_mir::mir::AggregateKind::Array(tables.intern_ty(*ty))
+                stable_mir::mir::AggregateKind::Array(ty.stable(tables))
             }
             mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple,
             mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => {
@@ -877,13 +882,13 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
 impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
     type T = stable_mir::mir::CoroutineKind;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use rustc_hir::{AsyncCoroutineKind, CoroutineKind};
+        use rustc_hir::{CoroutineKind, CoroutineSource};
         match self {
             CoroutineKind::Async(async_gen) => {
                 let async_gen = match async_gen {
-                    AsyncCoroutineKind::Block => stable_mir::mir::AsyncCoroutineKind::Block,
-                    AsyncCoroutineKind::Closure => stable_mir::mir::AsyncCoroutineKind::Closure,
-                    AsyncCoroutineKind::Fn => stable_mir::mir::AsyncCoroutineKind::Fn,
+                    CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block,
+                    CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure,
+                    CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn,
                 };
                 stable_mir::mir::CoroutineKind::Async(async_gen)
             }
@@ -1013,7 +1018,7 @@ impl<'tcx> Stable<'tcx> for ty::GenericArgKind<'tcx> {
         use stable_mir::ty::GenericArgKind;
         match self {
             ty::GenericArgKind::Lifetime(region) => GenericArgKind::Lifetime(region.stable(tables)),
-            ty::GenericArgKind::Type(ty) => GenericArgKind::Type(tables.intern_ty(*ty)),
+            ty::GenericArgKind::Type(ty) => GenericArgKind::Type(ty.stable(tables)),
             ty::GenericArgKind::Const(cnst) => GenericArgKind::Const(cnst.stable(tables)),
         }
     }
@@ -1059,11 +1064,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
         use stable_mir::ty::{Abi, FnSig};
 
         FnSig {
-            inputs_and_output: self
-                .inputs_and_output
-                .iter()
-                .map(|ty| tables.intern_ty(ty))
-                .collect(),
+            inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(),
             c_variadic: self.c_variadic,
             unsafety: self.unsafety.stable(tables),
             abi: match self.abi {
@@ -1201,9 +1202,16 @@ impl<'tcx> Stable<'tcx> for hir::Movability {
 }
 
 impl<'tcx> Stable<'tcx> for Ty<'tcx> {
+    type T = stable_mir::ty::Ty;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.intern_ty(*self)
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
     type T = stable_mir::ty::TyKind;
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        match self.kind() {
+        match self {
             ty::Bool => TyKind::RigidTy(RigidTy::Bool),
             ty::Char => TyKind::RigidTy(RigidTy::Char),
             ty::Int(int_ty) => TyKind::RigidTy(RigidTy::Int(int_ty.stable(tables))),
@@ -1216,15 +1224,15 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> {
             ty::Foreign(def_id) => TyKind::RigidTy(RigidTy::Foreign(tables.foreign_def(*def_id))),
             ty::Str => TyKind::RigidTy(RigidTy::Str),
             ty::Array(ty, constant) => {
-                TyKind::RigidTy(RigidTy::Array(tables.intern_ty(*ty), constant.stable(tables)))
+                TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
             }
-            ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(tables.intern_ty(*ty))),
+            ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
             ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
-                TyKind::RigidTy(RigidTy::RawPtr(tables.intern_ty(*ty), mutbl.stable(tables)))
+                TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
             }
             ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref(
                 region.stable(tables),
-                tables.intern_ty(*ty),
+                ty.stable(tables),
                 mutbl.stable(tables),
             )),
             ty::FnDef(def_id, generic_args) => {
@@ -1251,9 +1259,9 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> {
                 movability.stable(tables),
             )),
             ty::Never => TyKind::RigidTy(RigidTy::Never),
-            ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple(
-                fields.iter().map(|ty| tables.intern_ty(ty)).collect(),
-            )),
+            ty::Tuple(fields) => {
+                TyKind::RigidTy(RigidTy::Tuple(fields.iter().map(|ty| ty.stable(tables)).collect()))
+            }
             ty::Alias(alias_kind, alias_ty) => {
                 TyKind::Alias(alias_kind.stable(tables), alias_ty.stable(tables))
             }
@@ -1272,32 +1280,32 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
     type T = stable_mir::ty::Const;
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        stable_mir::ty::Const {
-            literal: match self.kind() {
-                ty::Value(val) => {
-                    let const_val = tables.tcx.valtree_to_const_val((self.ty(), val));
-                    stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
-                        self.ty(),
-                        const_val,
-                        tables,
-                    ))
-                }
-                ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)),
-                ty::ErrorCt(_) => unreachable!(),
-                ty::InferCt(_) => unreachable!(),
-                ty::BoundCt(_, _) => unimplemented!(),
-                ty::PlaceholderCt(_) => unimplemented!(),
-                ty::Unevaluated(uv) => {
-                    stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
-                        def: tables.const_def(uv.def),
-                        args: uv.args.stable(tables),
-                        promoted: None,
-                    })
-                }
-                ty::ExprCt(_) => unimplemented!(),
-            },
-            ty: tables.intern_ty(self.ty()),
-        }
+        let kind = match self.kind() {
+            ty::Value(val) => {
+                let const_val = tables.tcx.valtree_to_const_val((self.ty(), val));
+                stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
+                    self.ty(),
+                    const_val,
+                    tables,
+                ))
+            }
+            ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)),
+            ty::ErrorCt(_) => unreachable!(),
+            ty::InferCt(_) => unreachable!(),
+            ty::BoundCt(_, _) => unimplemented!(),
+            ty::PlaceholderCt(_) => unimplemented!(),
+            ty::Unevaluated(uv) => {
+                stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
+                    def: tables.const_def(uv.def),
+                    args: uv.args.stable(tables),
+                    promoted: None,
+                })
+            }
+            ty::ExprCt(_) => unimplemented!(),
+        };
+        let ty = self.ty().stable(tables);
+        let id = tables.intern_const(mir::Const::Ty(*self));
+        Const::new(kind, ty, id)
     }
 }
 
@@ -1382,22 +1390,23 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         match *self {
             mir::Const::Ty(c) => c.stable(tables),
-            mir::Const::Unevaluated(unev_const, ty) => stable_mir::ty::Const {
-                literal: stable_mir::ty::ConstantKind::Unevaluated(
-                    stable_mir::ty::UnevaluatedConst {
+            mir::Const::Unevaluated(unev_const, ty) => {
+                let kind =
+                    stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
                         def: tables.const_def(unev_const.def),
                         args: unev_const.args.stable(tables),
                         promoted: unev_const.promoted.map(|u| u.as_u32()),
-                    },
-                ),
-                ty: tables.intern_ty(ty),
-            },
-            mir::Const::Val(val, ty) => stable_mir::ty::Const {
-                literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
-                    ty, val, tables,
-                )),
-                ty: tables.intern_ty(ty),
-            },
+                    });
+                let ty = ty.stable(tables);
+                let id = tables.intern_const(*self);
+                Const::new(kind, ty, id)
+            }
+            mir::Const::Val(val, ty) => {
+                let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables));
+                let ty = ty.stable(tables);
+                let id = tables.intern_const(*self);
+                Const::new(kind, ty, id)
+            }
         }
     }
 }
@@ -1511,30 +1520,32 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
     type T = stable_mir::ty::ClauseKind;
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use ty::ClauseKind::*;
+        use ty::ClauseKind;
         match *self {
-            Trait(trait_object) => stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables)),
-            RegionOutlives(region_outlives) => {
+            ClauseKind::Trait(trait_object) => {
+                stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables))
+            }
+            ClauseKind::RegionOutlives(region_outlives) => {
                 stable_mir::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables))
             }
-            TypeOutlives(type_outlives) => {
+            ClauseKind::TypeOutlives(type_outlives) => {
                 let ty::OutlivesPredicate::<_, _>(a, b) = type_outlives;
                 stable_mir::ty::ClauseKind::TypeOutlives(stable_mir::ty::OutlivesPredicate(
-                    tables.intern_ty(a),
+                    a.stable(tables),
                     b.stable(tables),
                 ))
             }
-            Projection(projection_predicate) => {
+            ClauseKind::Projection(projection_predicate) => {
                 stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables))
             }
-            ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
+            ClauseKind::ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
                 const_.stable(tables),
-                tables.intern_ty(ty),
+                ty.stable(tables),
             ),
-            WellFormed(generic_arg) => {
+            ClauseKind::WellFormed(generic_arg) => {
                 stable_mir::ty::ClauseKind::WellFormed(generic_arg.unpack().stable(tables))
             }
-            ConstEvaluatable(const_) => {
+            ClauseKind::ConstEvaluatable(const_) => {
                 stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
             }
         }
@@ -1559,7 +1570,7 @@ impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> {
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         let ty::SubtypePredicate { a, b, a_is_expected: _ } = self;
-        stable_mir::ty::SubtypePredicate { a: tables.intern_ty(*a), b: tables.intern_ty(*b) }
+        stable_mir::ty::SubtypePredicate { a: a.stable(tables), b: b.stable(tables) }
     }
 }
 
@@ -1568,7 +1579,7 @@ impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> {
 
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         let ty::CoercePredicate { a, b } = self;
-        stable_mir::ty::CoercePredicate { a: tables.intern_ty(*a), b: tables.intern_ty(*b) }
+        stable_mir::ty::CoercePredicate { a: a.stable(tables), b: b.stable(tables) }
     }
 }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 38ae8f570e9..ff61143a12b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -910,6 +910,7 @@ symbols! {
         iter,
         iter_mut,
         iter_repeat,
+        iterator,
         iterator_collect_fn,
         kcfi,
         keyword,
@@ -957,6 +958,7 @@ symbols! {
         log_syntax,
         logf32,
         logf64,
+        loongarch_target_feature,
         loop_break_value,
         lt,
         macro_at_most_once_rep,
diff --git a/compiler/rustc_target/src/abi/call/csky.rs b/compiler/rustc_target/src/abi/call/csky.rs
index bbe95fa20ac..706493b0a6a 100644
--- a/compiler/rustc_target/src/abi/call/csky.rs
+++ b/compiler/rustc_target/src/abi/call/csky.rs
@@ -1,17 +1,39 @@
-// See https://github.com/llvm/llvm-project/blob/d85b94bf0080dcd780656c0f5e6342800720eba9/llvm/lib/Target/CSKY/CSKYCallingConv.td
-use crate::abi::call::{ArgAbi, FnAbi};
+// Reference: CSKY ABI Manual
+// https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1695027452256/T-HEAD_800_Series_ABI_Standards_Manual.pdf
+//
+// Reference: Clang CSKY lowering code
+// https://github.com/llvm/llvm-project/blob/4a074f32a6914f2a8d7215d78758c24942dddc3d/clang/lib/CodeGen/Targets/CSKY.cpp#L76-L162
 
-fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
-    if ret.layout.is_aggregate() || ret.layout.size.bits() > 64 {
-        ret.make_indirect();
+use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
+
+fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+    // For return type, aggregate which <= 2*XLen will be returned in registers.
+    // Otherwise, aggregate will be returned indirectly.
+    if arg.layout.is_aggregate() {
+        let total = arg.layout.size;
+        if total.bits() > 64 {
+            arg.make_indirect();
+        } else if total.bits() > 32 {
+            arg.cast_to(Uniform { unit: Reg::i32(), total });
+        } else {
+            arg.cast_to(Reg::i32());
+        }
     } else {
-        ret.extend_integer_width_to(32);
+        arg.extend_integer_width_to(32);
     }
 }
 
 fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
-    if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 {
-        arg.make_indirect();
+    // For argument type, the first 4*XLen parts of aggregate will be passed
+    // in registers, and the rest will be passed in stack.
+    // So we can coerce to integers directly and let backend handle it correctly.
+    if arg.layout.is_aggregate() {
+        let total = arg.layout.size;
+        if total.bits() > 32 {
+            arg.cast_to(Uniform { unit: Reg::i32(), total });
+        } else {
+            arg.cast_to(Reg::i32());
+        }
     } else {
         arg.extend_integer_width_to(32);
     }
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 20253b32add..a9792ca2795 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -28,6 +28,11 @@ trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-claus
     .label = invalid on-clause here
 
 trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute
+    .help = only `message`, `note` and `label` are allowed as options
+    .label = invalid option found here
+
+trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute
+    .help = at least one of the `message`, `note` and `label` options are expected
 
 trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
         [none] {""}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 0c214ca8753..6562bc86f99 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -37,6 +37,8 @@ pub(super) trait GoalKind<'tcx>:
 
     fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
 
+    fn polarity(self) -> ty::ImplPolarity;
+
     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
 
     fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
index 4950a444ffb..be631552c57 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
@@ -101,6 +101,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         self.projection_ty.trait_ref(tcx)
     }
 
+    fn polarity(self) -> ty::ImplPolarity {
+        ty::ImplPolarity::Positive
+    }
+
     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
         self.with_self_ty(tcx, self_ty)
     }
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index fa91a125b6a..7c4f6562f10 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -22,6 +22,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         self.trait_ref
     }
 
+    fn polarity(self) -> ty::ImplPolarity {
+        self.polarity
+    }
+
     fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
         self.with_self_ty(tcx, self_ty)
     }
@@ -238,14 +242,25 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        if let ty::FnPtr(..) = goal.predicate.self_ty().kind() {
-            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-        } else {
-            Err(NoSolution)
+        let self_ty = goal.predicate.self_ty();
+        match goal.predicate.polarity {
+            ty::ImplPolarity::Positive => {
+                if self_ty.is_fn_ptr() {
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                } else {
+                    Err(NoSolution)
+                }
+            }
+            ty::ImplPolarity::Negative => {
+                // If a type is rigid and not a fn ptr, then we know for certain
+                // that it does *not* implement `FnPtr`.
+                if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                } else {
+                    Err(NoSolution)
+                }
+            }
+            ty::ImplPolarity::Reservation => bug!(),
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 29b0c7189f9..dcf5fd86929 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -9,20 +9,18 @@ use crate::infer::InferOk;
 use crate::solve::inspect;
 use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
 use crate::traits::engine::TraitEngineExt;
-use crate::traits::outlives_bounds::InferCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
 use crate::traits::structural_normalize::StructurallyNormalizeExt;
-use crate::traits::util::impl_subject_and_oblig;
 use crate::traits::NormalizeExt;
 use crate::traits::SkipLeakCheck;
 use crate::traits::{
-    self, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
+    Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
     SelectionContext,
 };
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{util, TraitEngine};
 use rustc_middle::traits::query::NoSolution;
@@ -32,12 +30,11 @@ use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE;
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use std::fmt::Debug;
-use std::iter;
 use std::ops::ControlFlow;
 
 /// Whether we do the orphan check relative to this crate or
@@ -142,16 +139,13 @@ pub fn overlapping_impls(
     Some(overlap)
 }
 
-fn with_fresh_ty_vars<'cx, 'tcx>(
-    selcx: &mut SelectionContext<'cx, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    impl_def_id: DefId,
-) -> ty::ImplHeader<'tcx> {
-    let tcx = selcx.tcx();
-    let impl_args = selcx.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
+fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ty::ImplHeader<'tcx> {
+    let tcx = infcx.tcx;
+    let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
 
-    let header = ty::ImplHeader {
+    ty::ImplHeader {
         impl_def_id,
+        impl_args,
         self_ty: tcx.type_of(impl_def_id).instantiate(tcx, impl_args),
         trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.instantiate(tcx, impl_args)),
         predicates: tcx
@@ -160,10 +154,18 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
             .iter()
             .map(|(c, _)| c.as_predicate())
             .collect(),
-    };
+    }
+}
+
+fn fresh_impl_header_normalized<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    impl_def_id: DefId,
+) -> ty::ImplHeader<'tcx> {
+    let header = fresh_impl_header(infcx, impl_def_id);
 
     let InferOk { value: mut header, obligations } =
-        selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
+        infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
 
     header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
     header
@@ -206,12 +208,13 @@ fn overlap<'tcx>(
     // empty environment.
     let param_env = ty::ParamEnv::empty();
 
-    let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
-    let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
+    let impl1_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl1_def_id);
+    let impl2_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl2_def_id);
 
     // Equate the headers to find their intersection (the general type, with infer vars,
     // that may apply both impls).
-    let mut obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
+    let mut obligations =
+        equate_impl_headers(selcx.infcx, param_env, &impl1_header, &impl2_header)?;
     debug!("overlap: unification check succeeded");
 
     obligations.extend(
@@ -312,20 +315,22 @@ fn overlap<'tcx>(
 #[instrument(level = "debug", skip(infcx), ret)]
 fn equate_impl_headers<'tcx>(
     infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     impl1: &ty::ImplHeader<'tcx>,
     impl2: &ty::ImplHeader<'tcx>,
 ) -> Option<PredicateObligations<'tcx>> {
-    let result = match (impl1.trait_ref, impl2.trait_ref) {
-        (Some(impl1_ref), Some(impl2_ref)) => infcx
-            .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
-            .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
-        (None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
-            DefineOpaqueTypes::Yes,
-            impl1.self_ty,
-            impl2.self_ty,
-        ),
-        _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
-    };
+    let result =
+        match (impl1.trait_ref, impl2.trait_ref) {
+            (Some(impl1_ref), Some(impl2_ref)) => infcx
+                .at(&ObligationCause::dummy(), param_env)
+                .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
+            (None, None) => infcx.at(&ObligationCause::dummy(), param_env).eq(
+                DefineOpaqueTypes::Yes,
+                impl1.self_ty,
+                impl2.self_ty,
+            ),
+            _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
+        };
 
     result.map(|infer_ok| infer_ok.obligations).ok()
 }
@@ -391,107 +396,182 @@ fn impl_intersection_has_negative_obligation(
 ) -> bool {
     debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
 
-    // Create an infcx, taking the predicates of impl1 as assumptions:
-    let infcx = tcx.infer_ctxt().build();
-    // create a parameter environment corresponding to a (placeholder) instantiation of impl1
-    let impl_env = tcx.param_env(impl1_def_id);
-    let subject1 = match traits::fully_normalize(
-        &infcx,
-        ObligationCause::dummy(),
-        impl_env,
-        tcx.impl_subject(impl1_def_id).instantiate_identity(),
-    ) {
-        Ok(s) => s,
-        Err(err) => {
-            tcx.sess.delay_span_bug(
-                tcx.def_span(impl1_def_id),
-                format!("failed to fully normalize {impl1_def_id:?}: {err:?}"),
-            );
-            return false;
-        }
-    };
+    let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build();
+    let universe = infcx.universe();
 
-    // Attempt to prove that impl2 applies, given all of the above.
-    let selcx = &mut SelectionContext::new(&infcx);
-    let impl2_args = infcx.fresh_args_for_item(DUMMY_SP, impl2_def_id);
-    let (subject2, normalization_obligations) =
-        impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_args, |_, _| {
-            ObligationCause::dummy()
-        });
-
-    // do the impls unify? If not, then it's not currently possible to prove any
-    // obligations about their intersection.
-    let Ok(InferOk { obligations: equate_obligations, .. }) =
-        infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No, subject1, subject2)
+    let impl1_header = fresh_impl_header(infcx, impl1_def_id);
+    let param_env =
+        ty::EarlyBinder::bind(tcx.param_env(impl1_def_id)).instantiate(tcx, impl1_header.impl_args);
+
+    let impl2_header = fresh_impl_header(infcx, impl2_def_id);
+
+    // Equate the headers to find their intersection (the general type, with infer vars,
+    // that may apply both impls).
+    let Some(_equate_obligations) =
+        equate_impl_headers(infcx, param_env, &impl1_header, &impl2_header)
     else {
-        debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
         return false;
     };
 
-    for obligation in normalization_obligations.into_iter().chain(equate_obligations) {
-        if negative_impl_exists(&infcx, &obligation, impl1_def_id) {
-            debug!("overlap: obligation unsatisfiable {:?}", obligation);
-            return true;
-        }
-    }
+    plug_infer_with_placeholders(infcx, universe, (impl1_header.impl_args, impl2_header.impl_args));
 
-    false
+    util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args))
+        .any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env))
 }
 
-/// Try to prove that a negative impl exist for the obligation or its supertraits.
-///
-/// If such a negative impl exists, then the obligation definitely must not hold
-/// due to coherence, even if it's not necessarily "knowable" in this crate. Any
-/// valid impl downstream would not be able to exist due to the overlapping
-/// negative impl.
-#[instrument(level = "debug", skip(infcx))]
-fn negative_impl_exists<'tcx>(
+fn plug_infer_with_placeholders<'tcx>(
     infcx: &InferCtxt<'tcx>,
-    o: &PredicateObligation<'tcx>,
-    body_def_id: DefId,
-) -> bool {
-    // Try to prove a negative obligation exists for super predicates
-    for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) {
-        if prove_negated_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) {
-            return true;
+    universe: ty::UniverseIndex,
+    value: impl TypeVisitable<TyCtxt<'tcx>>,
+) {
+    struct PlugInferWithPlaceholder<'a, 'tcx> {
+        infcx: &'a InferCtxt<'tcx>,
+        universe: ty::UniverseIndex,
+        var: ty::BoundVar,
+    }
+
+    impl<'tcx> PlugInferWithPlaceholder<'_, 'tcx> {
+        fn next_var(&mut self) -> ty::BoundVar {
+            let var = self.var;
+            self.var = self.var + 1;
+            var
+        }
+    }
+
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlugInferWithPlaceholder<'_, 'tcx> {
+        fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+            let ty = self.infcx.shallow_resolve(ty);
+            if ty.is_ty_var() {
+                let Ok(InferOk { value: (), obligations }) =
+                    self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+                        DefineOpaqueTypes::No,
+                        ty,
+                        Ty::new_placeholder(
+                            self.infcx.tcx,
+                            ty::Placeholder {
+                                universe: self.universe,
+                                bound: ty::BoundTy {
+                                    var: self.next_var(),
+                                    kind: ty::BoundTyKind::Anon,
+                                },
+                            },
+                        ),
+                    )
+                else {
+                    bug!()
+                };
+                assert_eq!(obligations, &[]);
+                ControlFlow::Continue(())
+            } else {
+                ty.super_visit_with(self)
+            }
+        }
+
+        fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+            let ct = self.infcx.shallow_resolve(ct);
+            if ct.is_ct_infer() {
+                let Ok(InferOk { value: (), obligations }) =
+                    self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+                        DefineOpaqueTypes::No,
+                        ct,
+                        ty::Const::new_placeholder(
+                            self.infcx.tcx,
+                            ty::Placeholder { universe: self.universe, bound: self.next_var() },
+                            ct.ty(),
+                        ),
+                    )
+                else {
+                    bug!()
+                };
+                assert_eq!(obligations, &[]);
+                ControlFlow::Continue(())
+            } else {
+                ct.super_visit_with(self)
+            }
+        }
+
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+            if let ty::ReVar(vid) = *r {
+                let r = self
+                    .infcx
+                    .inner
+                    .borrow_mut()
+                    .unwrap_region_constraints()
+                    .opportunistic_resolve_var(self.infcx.tcx, vid);
+                if r.is_var() {
+                    let Ok(InferOk { value: (), obligations }) =
+                        self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+                            DefineOpaqueTypes::No,
+                            r,
+                            ty::Region::new_placeholder(
+                                self.infcx.tcx,
+                                ty::Placeholder {
+                                    universe: self.universe,
+                                    bound: ty::BoundRegion {
+                                        var: self.next_var(),
+                                        kind: ty::BoundRegionKind::BrAnon,
+                                    },
+                                },
+                            ),
+                        )
+                    else {
+                        bug!()
+                    };
+                    assert_eq!(obligations, &[]);
+                }
+            }
+            ControlFlow::Continue(())
         }
     }
 
-    false
+    value.visit_with(&mut PlugInferWithPlaceholder {
+        infcx,
+        universe,
+        var: ty::BoundVar::from_u32(0),
+    });
 }
 
-#[instrument(level = "debug", skip(infcx))]
-fn prove_negated_obligation<'tcx>(
-    infcx: InferCtxt<'tcx>,
-    o: &PredicateObligation<'tcx>,
-    body_def_id: DefId,
+fn try_prove_negated_where_clause<'tcx>(
+    root_infcx: &InferCtxt<'tcx>,
+    clause: ty::Clause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 ) -> bool {
-    let tcx = infcx.tcx;
-
-    let Some(o) = o.flip_polarity(tcx) else {
+    let Some(negative_predicate) = clause.as_predicate().flip_polarity(root_infcx.tcx) else {
         return false;
     };
 
-    let param_env = o.param_env;
-    let ocx = ObligationCtxt::new(&infcx);
-    ocx.register_obligation(o);
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
+    // FIXME(with_negative_coherence): the infcx has region contraints from equating
+    // the impl headers as requirements. Given that the only region constraints we
+    // get are involving inference regions in the root, it shouldn't matter, but
+    // still sus.
+    //
+    // We probably should just throw away the region obligations registered up until
+    // now, or ideally use them as assumptions when proving the region obligations
+    // that we get from proving the negative predicate below.
+    let ref infcx = root_infcx.fork();
+    let ocx = ObligationCtxt::new(infcx);
+
+    ocx.register_obligation(Obligation::new(
+        infcx.tcx,
+        ObligationCause::dummy(),
+        param_env,
+        negative_predicate,
+    ));
+    if !ocx.select_all_or_error().is_empty() {
         return false;
     }
 
-    let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID);
+    // FIXME: We could use the assumed_wf_types from both impls, I think,
+    // if that wasn't implemented just for LocalDefId, and we'd need to do
+    // the normalization ourselves since this is totally fallible...
+    let outlives_env = OutlivesEnvironment::new(param_env);
 
-    let ocx = ObligationCtxt::new(&infcx);
-    let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id) else {
+    let errors = infcx.resolve_regions(&outlives_env);
+    if !errors.is_empty() {
         return false;
-    };
+    }
 
-    let outlives_env = OutlivesEnvironment::with_bounds(
-        param_env,
-        infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
-    );
-    infcx.resolve_regions(&outlives_env).is_empty()
+    true
 }
 
 /// Returns whether all impls which would apply to the `trait_ref`
@@ -506,13 +586,6 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>(
     trait_ref: ty::TraitRef<'tcx>,
     mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
 ) -> Result<Result<(), Conflict>, E> {
-    if Some(trait_ref.def_id) == tcx.lang_items().fn_ptr_trait() {
-        // The only types implementing `FnPtr` are function pointers,
-        // so if there's no impl of `FnPtr` in the current crate,
-        // then such an impl will never be added in the future.
-        return Ok(Ok(()));
-    }
-
     if orphan_check_trait_ref(trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() {
         // A downstream or cousin crate is allowed to implement some
         // substitution of this trait-ref.
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 88f47b03cc8..d9a1a98191d 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -37,10 +37,10 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
             (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => {
                 Box::new(FulfillmentContext::new(infcx))
             }
-            (TraitSolver::Next | TraitSolver::NextCoherence, true) => {
+            (TraitSolver::Classic | TraitSolver::Next | TraitSolver::NextCoherence, true) => {
                 Box::new(NextFulfillmentCtxt::new(infcx))
             }
-            _ => bug!(
+            (TraitSolver::Next, false) => bug!(
                 "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})",
                 infcx.tcx.sess.opts.unstable_opts.trait_solver,
                 infcx.next_trait_solver()
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 016c44c20f6..c96e41b88bd 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -1,5 +1,8 @@
 use super::{ObligationCauseCode, PredicateObligation};
 use crate::infer::error_reporting::TypeErrCtxt;
+use rustc_ast::AttrArgs;
+use rustc_ast::AttrArgsEq;
+use rustc_ast::AttrKind;
 use rustc_ast::{Attribute, MetaItem, NestedMetaItem};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashMap;
@@ -342,7 +345,22 @@ pub enum AppendConstMessage {
 
 #[derive(LintDiagnostic)]
 #[diag(trait_selection_malformed_on_unimplemented_attr)]
-pub struct NoValueInOnUnimplementedLint;
+#[help]
+pub struct MalformedOnUnimplementedAttrLint {
+    #[label]
+    pub span: Span,
+}
+
+impl MalformedOnUnimplementedAttrLint {
+    fn new(span: Span) -> Self {
+        Self { span }
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
+#[help]
+pub struct MissingOptionsForOnUnimplementedAttr;
 
 impl<'tcx> OnUnimplementedDirective {
     fn parse(
@@ -453,7 +471,7 @@ impl<'tcx> OnUnimplementedDirective {
                     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                     tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
                     vec![item.span()],
-                    NoValueInOnUnimplementedLint,
+                    MalformedOnUnimplementedAttrLint::new(item.span()),
                 );
             } else {
                 // nothing found
@@ -530,21 +548,40 @@ impl<'tcx> OnUnimplementedDirective {
                     append_const_msg: None,
                 }))
             } else {
+                let item = attr.get_normal_item();
+                let report_span = match &item.args {
+                    AttrArgs::Empty => item.path.span,
+                    AttrArgs::Delimited(args) => args.dspan.entire(),
+                    AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => eq_span.to(expr.span),
+                    AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span),
+                };
+
                 tcx.emit_spanned_lint(
                     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                     tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
-                    attr.span,
-                    NoValueInOnUnimplementedLint,
+                    report_span,
+                    MalformedOnUnimplementedAttrLint::new(report_span),
                 );
                 Ok(None)
             }
         } else if is_diagnostic_namespace_variant {
-            tcx.emit_spanned_lint(
-                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
-                attr.span,
-                NoValueInOnUnimplementedLint,
-            );
+            match &attr.kind {
+                AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => {
+                    tcx.emit_spanned_lint(
+                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+                        attr.span,
+                        MalformedOnUnimplementedAttrLint::new(attr.span),
+                    );
+                }
+                _ => tcx.emit_spanned_lint(
+                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+                    attr.span,
+                    MissingOptionsForOnUnimplementedAttr,
+                ),
+            };
+
             Ok(None)
         } else {
             let reported =
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 78b466907b3..b9a08056ad1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -22,7 +22,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::is_range_literal;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Node};
+use rustc_hir::{CoroutineKind, CoroutineSource, Node};
 use rustc_hir::{Expr, HirId};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -2410,7 +2410,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 .and_then(|coroutine_did| {
                     Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() {
                         CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"),
-                        CoroutineKind::Async(AsyncCoroutineKind::Fn) => self
+                        CoroutineKind::Async(CoroutineSource::Fn) => self
                             .tcx
                             .parent(coroutine_did)
                             .as_local()
@@ -2419,10 +2419,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             .map(|name| {
                                 format!("future returned by `{name}` is not {trait_name}")
                             })?,
-                        CoroutineKind::Async(AsyncCoroutineKind::Block) => {
+                        CoroutineKind::Async(CoroutineSource::Block) => {
                             format!("future created by async block is not {trait_name}")
                         }
-                        CoroutineKind::Async(AsyncCoroutineKind::Closure) => {
+                        CoroutineKind::Async(CoroutineSource::Closure) => {
                             format!("future created by async closure is not {trait_name}")
                         }
                     })
@@ -2995,11 +2995,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 let sp = self.tcx.def_span(def_id);
 
                                 // Special-case this to say "async block" instead of `[static coroutine]`.
-                                let kind = tcx.coroutine_kind(def_id).unwrap().descr();
+                                let kind = tcx.coroutine_kind(def_id).unwrap();
                                 err.span_note(
                                     sp,
                                     with_forced_trimmed_paths!(format!(
-                                        "required because it's used within this {kind}",
+                                        "required because it's used within this {kind:#}",
                                     )),
                                 )
                             }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 1245b4a7756..353a69ef6d3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -1611,9 +1611,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> {
         self.tcx.hir().body(body_id).coroutine_kind.map(|gen_kind| match gen_kind {
             hir::CoroutineKind::Coroutine => "a coroutine",
-            hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) => "an async block",
-            hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn) => "an async function",
-            hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure) => "an async closure",
+            hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block",
+            hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function",
+            hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure",
         })
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 55b5604b16b..fb9cf51b513 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,4 +1,5 @@
 use crate::infer::{InferCtxt, TyOrConstInferVar};
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
@@ -68,7 +69,7 @@ pub struct PendingPredicateObligation<'tcx> {
     // should mostly optimize for reading speed, while modifying is not as relevant.
     //
     // For whatever reason using a boxed slice is slower than using a `Vec` here.
-    pub stalled_on: Vec<TyOrConstInferVar<'tcx>>,
+    pub stalled_on: Vec<TyOrConstInferVar>,
 }
 
 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -669,7 +670,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         &mut self,
         obligation: &PredicateObligation<'tcx>,
         trait_obligation: PolyTraitObligation<'tcx>,
-        stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+        stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let infcx = self.selcx.infcx;
         if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
@@ -722,7 +723,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         &mut self,
         obligation: &PredicateObligation<'tcx>,
         project_obligation: PolyProjectionObligation<'tcx>,
-        stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+        stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let tcx = self.selcx.tcx();
 
@@ -775,7 +776,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
 fn args_infer_vars<'a, 'tcx>(
     selcx: &SelectionContext<'a, 'tcx>,
     args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
-) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
+) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> {
     selcx
         .infcx
         .resolve_vars_if_possible(args)
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 2d05f934393..dfc4bdf1484 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -97,6 +97,10 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
 /// object. Note that object-safe traits can have some
 /// non-vtable-safe methods, so long as they require `Self: Sized` or
 /// otherwise ensure that they cannot be used when `Self = Trait`.
+///
+/// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards
+/// compatibility, see <https://github.com/rust-lang/rust/issues/51443> and
+/// [`WHERE_CLAUSES_OBJECT_SAFETY`].
 pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
     debug_assert!(tcx.generics_of(trait_def_id).has_self);
     debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
@@ -105,10 +109,9 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A
         return false;
     }
 
-    match virtual_call_violation_for_method(tcx, trait_def_id, method) {
-        None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
-        Some(_) => false,
-    }
+    virtual_call_violations_for_method(tcx, trait_def_id, method)
+        .iter()
+        .all(|v| matches!(v, MethodViolationCode::WhereClauseReferencesSelf))
 }
 
 fn object_safety_violations_for_trait(
@@ -119,7 +122,7 @@ fn object_safety_violations_for_trait(
     let mut violations: Vec<_> = tcx
         .associated_items(trait_def_id)
         .in_definition_order()
-        .filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item))
+        .flat_map(|&item| object_safety_violations_for_assoc_item(tcx, trait_def_id, item))
         .collect();
 
     // Check the trait itself.
@@ -357,49 +360,52 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
 /// Returns `Some(_)` if this item makes the containing trait not object safe.
 #[instrument(level = "debug", skip(tcx), ret)]
-fn object_safety_violation_for_assoc_item(
+fn object_safety_violations_for_assoc_item(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
     item: ty::AssocItem,
-) -> Option<ObjectSafetyViolation> {
+) -> Vec<ObjectSafetyViolation> {
     // Any item that has a `Self : Sized` requisite is otherwise
     // exempt from the regulations.
     if tcx.generics_require_sized_self(item.def_id) {
-        return None;
+        return Vec::new();
     }
 
     match item.kind {
         // Associated consts are never object safe, as they can't have `where` bounds yet at all,
         // and associated const bounds in trait objects aren't a thing yet either.
         ty::AssocKind::Const => {
-            Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span))
+            vec![ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)]
         }
-        ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| {
-            let node = tcx.hir().get_if_local(item.def_id);
-            // Get an accurate span depending on the violation.
-            let span = match (&v, node) {
-                (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
-                (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
-                (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
-                (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
-                    node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
-                }
-                _ => item.ident(tcx).span,
-            };
+        ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
+            .into_iter()
+            .map(|v| {
+                let node = tcx.hir().get_if_local(item.def_id);
+                // Get an accurate span depending on the violation.
+                let span = match (&v, node) {
+                    (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
+                    (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
+                    (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
+                    (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
+                        node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
+                    }
+                    _ => item.ident(tcx).span,
+                };
 
-            ObjectSafetyViolation::Method(item.name, v, span)
-        }),
+                ObjectSafetyViolation::Method(item.name, v, span)
+            })
+            .collect(),
         // Associated types can only be object safe if they have `Self: Sized` bounds.
         ty::AssocKind::Type => {
             if !tcx.features().generic_associated_types_extended
                 && !tcx.generics_of(item.def_id).params.is_empty()
                 && !item.is_impl_trait_in_trait()
             {
-                Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span))
+                vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)]
             } else {
                 // We will permit associated types if they are explicitly mentioned in the trait object.
                 // We can't check this here, as here we only check if it is guaranteed to not be possible.
-                None
+                Vec::new()
             }
         }
     }
@@ -409,11 +415,11 @@ fn object_safety_violation_for_assoc_item(
 /// object; this does not necessarily imply that the enclosing trait
 /// is not object safe, because the method might have a where clause
 /// `Self:Sized`.
-fn virtual_call_violation_for_method<'tcx>(
+fn virtual_call_violations_for_method<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
     method: ty::AssocItem,
-) -> Option<MethodViolationCode> {
+) -> Vec<MethodViolationCode> {
     let sig = tcx.fn_sig(method.def_id).instantiate_identity();
 
     // The method's first parameter must be named `self`
@@ -438,9 +444,14 @@ fn virtual_call_violation_for_method<'tcx>(
         } else {
             None
         };
-        return Some(MethodViolationCode::StaticMethod(sugg));
+
+        // Not having `self` parameter messes up the later checks,
+        // so we need to return instead of pushing
+        return vec![MethodViolationCode::StaticMethod(sugg)];
     }
 
+    let mut errors = Vec::new();
+
     for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
         if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
             let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
@@ -452,20 +463,20 @@ fn virtual_call_violation_for_method<'tcx>(
             } else {
                 None
             };
-            return Some(MethodViolationCode::ReferencesSelfInput(span));
+            errors.push(MethodViolationCode::ReferencesSelfInput(span));
         }
     }
     if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
-        return Some(MethodViolationCode::ReferencesSelfOutput);
+        errors.push(MethodViolationCode::ReferencesSelfOutput);
     }
     if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
-        return Some(code);
+        errors.push(code);
     }
 
     // We can't monomorphize things like `fn foo<A>(...)`.
     let own_counts = tcx.generics_of(method.def_id).own_counts();
-    if own_counts.types + own_counts.consts != 0 {
-        return Some(MethodViolationCode::Generic);
+    if own_counts.types > 0 || own_counts.consts > 0 {
+        errors.push(MethodViolationCode::Generic);
     }
 
     let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
@@ -485,7 +496,7 @@ fn virtual_call_violation_for_method<'tcx>(
             } else {
                 None
             };
-            return Some(MethodViolationCode::UndispatchableReceiver(span));
+            errors.push(MethodViolationCode::UndispatchableReceiver(span));
         } else {
             // Do sanity check to make sure the receiver actually has the layout of a pointer.
 
@@ -593,10 +604,10 @@ fn virtual_call_violation_for_method<'tcx>(
 
         contains_illegal_self_type_reference(tcx, trait_def_id, pred)
     }) {
-        return Some(MethodViolationCode::WhereClauseReferencesSelf);
+        errors.push(MethodViolationCode::WhereClauseReferencesSelf);
     }
 
-    None
+    errors
 }
 
 /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
@@ -709,7 +720,6 @@ fn object_ty_for_trait<'tcx>(
 // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
 // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
 // `self: Wrapper<Self>`.
-#[allow(dead_code)]
 fn receiver_is_dispatchable<'tcx>(
     tcx: TyCtxt<'tcx>,
     method: ty::AssocItem,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index c3f56ae2756..af30d9121d1 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -898,7 +898,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
                 if debruijn.as_usize() + 1
                     > self.current_index.as_usize() + self.universe_indices.len() =>
             {
-                bug!("Bound vars outside of `self.universe_indices`");
+                bug!(
+                    "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
+                    self.universe_indices
+                );
             }
             ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => {
                 let universe = self.universe_for(debruijn);
@@ -916,7 +919,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
                 if debruijn.as_usize() + 1
                     > self.current_index.as_usize() + self.universe_indices.len() =>
             {
-                bug!("Bound vars outside of `self.universe_indices`");
+                bug!(
+                    "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
+                    self.universe_indices
+                );
             }
             ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
                 let universe = self.universe_for(debruijn);
@@ -935,7 +941,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
                 if debruijn.as_usize() + 1
                     > self.current_index.as_usize() + self.universe_indices.len() =>
             {
-                bug!("Bound vars outside of `self.universe_indices`");
+                bug!(
+                    "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
+                    self.universe_indices
+                );
             }
             ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
                 let universe = self.universe_for(debruijn);
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 349741a698c..c761d0d103e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -293,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                     _ => unreachable!(),
                 }?;
                 // We don't expect ambiguity.
-                if result.is_ambiguous() {
+                if !result.value.is_proven() {
                     // Rustdoc normalizes possibly not well-formed types, so only
                     // treat this as a bug if we're not in rustdoc.
                     if !tcx.sess.opts.actually_rustdoc {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index ee50a36be55..123881d9bc6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -52,8 +52,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
 
-        // The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl.
-        // There are no compiler built-in rules for this.
+        // Negative trait predicates have different rules than positive trait predicates.
         if obligation.polarity() == ty::ImplPolarity::Negative {
             self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
             self.assemble_candidates_from_impls(obligation, &mut candidates);
@@ -1064,6 +1063,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+
         match self_ty.skip_binder().kind() {
             ty::FnPtr(_) => candidates.vec.push(BuiltinCandidate { has_nested: false }),
             ty::Bool
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 1a9de150041..dabe25589a0 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -9,6 +9,7 @@
 #![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
 #![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(assert_matches)]
+#![feature(associated_type_defaults)]
 #![feature(iterator_try_collect)]
 #![feature(let_chains)]
 #![feature(if_let_guard)]
@@ -39,6 +40,7 @@ mod layout_sanity_check;
 mod needs_drop;
 mod opaque_types;
 pub mod representability;
+pub mod sig_types;
 mod structural_match;
 mod ty;
 
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 0010570e7b3..d1a154fe20d 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -53,14 +53,10 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
 
     fn parent(&self) -> Option<LocalDefId> {
         match self.tcx.def_kind(self.item) {
-            DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias => None,
             DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
                 Some(self.tcx.local_parent(self.item))
             }
-            other => span_bug!(
-                self.tcx.def_span(self.item),
-                "unhandled item with opaque types: {other:?}"
-            ),
+            _ => None,
         }
     }
 
@@ -98,14 +94,6 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
         hir_id == scope
     }
 
-    fn collect_body_and_predicate_taits(&mut self) {
-        // Look at all where bounds.
-        self.tcx.predicates_of(self.item).instantiate_identity(self.tcx).visit_with(self);
-        // An item is allowed to constrain opaques declared within its own body (but not nested within
-        // nested functions).
-        self.collect_taits_declared_in_body();
-    }
-
     #[instrument(level = "trace", skip(self))]
     fn collect_taits_declared_in_body(&mut self) {
         let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(self.item)).value;
@@ -132,6 +120,13 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
     }
 }
 
+impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
+    fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
+        self.visit_spanned(span, value);
+        ControlFlow::Continue(())
+    }
+}
+
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
     #[instrument(skip(self), ret, level = "trace")]
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
@@ -269,41 +264,27 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
     }
 }
 
-fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] {
+fn opaque_types_defined_by<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    item: LocalDefId,
+) -> &'tcx ty::List<LocalDefId> {
     let kind = tcx.def_kind(item);
     trace!(?kind);
     let mut collector = OpaqueTypeCollector::new(tcx, item);
+    super::sig_types::walk_types(tcx, item, &mut collector);
     match kind {
-        // Walk over the signature of the function-like to find the opaques.
-        DefKind::AssocFn | DefKind::Fn => {
-            let ty_sig = tcx.fn_sig(item).instantiate_identity();
-            let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap();
-            // Walk over the inputs and outputs manually in order to get good spans for them.
-            collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output());
-            for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) {
-                collector.visit_spanned(hir.span, ty.map_bound(|x| *x));
-            }
-            collector.collect_body_and_predicate_taits();
-        }
-        // Walk over the type of the item to find opaques.
-        DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
-            let span = match tcx.hir().get_by_def_id(item).ty() {
-                Some(ty) => ty.span,
-                _ => tcx.def_span(item),
-            };
-            collector.visit_spanned(span, tcx.type_of(item).instantiate_identity());
-            collector.collect_body_and_predicate_taits();
-        }
-        // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
-        DefKind::TyAlias | DefKind::AssocTy => {
-            tcx.type_of(item).instantiate_identity().visit_with(&mut collector);
-        }
-        DefKind::OpaqueTy => {
-            for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() {
-                collector.visit_spanned(span, pred);
-            }
+        DefKind::AssocFn
+        | DefKind::Fn
+        | DefKind::Static(_)
+        | DefKind::Const
+        | DefKind::AssocConst
+        | DefKind::AnonConst => {
+            collector.collect_taits_declared_in_body();
         }
-        DefKind::Mod
+        DefKind::OpaqueTy
+        | DefKind::TyAlias
+        | DefKind::AssocTy
+        | DefKind::Mod
         | DefKind::Struct
         | DefKind::Union
         | DefKind::Enum
@@ -322,12 +303,13 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [
         | DefKind::LifetimeParam
         | DefKind::GlobalAsm
         | DefKind::Impl { .. } => {}
-        // Closures and coroutines are type checked with their parent, so there is no difference here.
+        // Closures and coroutines are type checked with their parent, so we need to allow all
+        // opaques from the closure signature *and* from the parent body.
         DefKind::Closure | DefKind::Coroutine | DefKind::InlineConst => {
-            return tcx.opaque_types_defined_by(tcx.local_parent(item));
+            collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item)));
         }
     }
-    tcx.arena.alloc_from_iter(collector.opaques)
+    tcx.mk_local_def_ids(&collector.opaques)
 }
 
 pub(super) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs
new file mode 100644
index 00000000000..1ab39974e0f
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/sig_types.rs
@@ -0,0 +1,129 @@
+//! This module contains helpers for walking all types of
+//! a signature, while preserving spans as much as possible
+
+use std::ops::ControlFlow;
+
+use rustc_hir::{def::DefKind, def_id::LocalDefId};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::Span;
+use rustc_type_ir::visit::TypeVisitable;
+
+pub trait SpannedTypeVisitor<'tcx> {
+    type BreakTy = !;
+    fn visit(
+        &mut self,
+        span: Span,
+        value: impl TypeVisitable<TyCtxt<'tcx>>,
+    ) -> ControlFlow<Self::BreakTy>;
+}
+
+pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
+    tcx: TyCtxt<'tcx>,
+    item: LocalDefId,
+    visitor: &mut V,
+) -> ControlFlow<V::BreakTy> {
+    let kind = tcx.def_kind(item);
+    trace!(?kind);
+    match kind {
+        DefKind::Coroutine => {
+            match tcx.type_of(item).instantiate_identity().kind() {
+                ty::Coroutine(_, args, _) => visitor.visit(tcx.def_span(item), args.as_coroutine().sig())?,
+                _ => bug!(),
+            }
+            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+                visitor.visit(span, pred)?;
+            }
+        }
+        // Walk over the signature of the function-like
+        DefKind::Closure | DefKind::AssocFn | DefKind::Fn => {
+            let ty_sig = match kind {
+                DefKind::Closure => match tcx.type_of(item).instantiate_identity().kind() {
+                    ty::Closure(_, args) => args.as_closure().sig(),
+                    _ => bug!(),
+                },
+                _ => tcx.fn_sig(item).instantiate_identity(),
+            };
+            let hir_sig = tcx.hir().get_by_def_id(item).fn_decl().unwrap();
+            // Walk over the inputs and outputs manually in order to get good spans for them.
+            visitor.visit(hir_sig.output.span(), ty_sig.output());
+            for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) {
+                visitor.visit(hir.span, ty.map_bound(|x| *x))?;
+            }
+            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+                visitor.visit(span, pred)?;
+            }
+        }
+        // Walk over the type behind the alias
+        DefKind::TyAlias {..} | DefKind::AssocTy |
+        // Walk over the type of the item
+        DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
+            let span = match tcx.hir().get_by_def_id(item).ty() {
+                Some(ty) => ty.span,
+                _ => tcx.def_span(item),
+            };
+            visitor.visit(span,  tcx.type_of(item).instantiate_identity());
+            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+                visitor.visit(span, pred)?;
+            }
+        }
+        DefKind::OpaqueTy => {
+            for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() {
+                visitor.visit(span, pred)?;
+            }
+        }
+        // Look at field types
+        DefKind::Struct | DefKind::Union | DefKind::Enum => {
+            let span = tcx.def_ident_span(item).unwrap();
+            visitor.visit(span,  tcx.type_of(item).instantiate_identity());
+            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+                visitor.visit(span, pred)?;
+            }
+        }
+        // Does not have a syntactical signature
+        DefKind::InlineConst => {}
+        DefKind::Impl { of_trait } => {
+            if of_trait {
+                let span = tcx.hir().get_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span;
+                let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..];
+                visitor.visit(span, args)?;
+            }
+            let span = match tcx.hir().get_by_def_id(item).ty() {
+                Some(ty) => ty.span,
+                _ => tcx.def_span(item),
+            };
+            visitor.visit(span, tcx.type_of(item).instantiate_identity());
+            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+                visitor.visit(span, pred)?;
+            }}
+        DefKind::Trait => {
+            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+                visitor.visit(span, pred)?;
+            }
+        }
+        DefKind::TraitAlias => {
+            for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
+                visitor.visit(span, pred)?;
+            }
+        }
+        | DefKind::Variant
+        | DefKind::ForeignTy
+        | DefKind::TyParam
+        | DefKind::ConstParam
+        | DefKind::Ctor(_, _)
+        | DefKind::Field
+        | DefKind::LifetimeParam => {
+            span_bug!(
+                tcx.def_span(item),
+                "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help"
+            )
+        }
+        // These don't have any types.
+        | DefKind::ExternCrate
+        | DefKind::ForeignMod
+        | DefKind::Macro(_)
+        | DefKind::GlobalAsm
+        | DefKind::Mod
+        | DefKind::Use => {}
+    }
+    ControlFlow::Continue(())
+}
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
new file mode 100644
index 00000000000..c0b6aed98ef
--- /dev/null
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -0,0 +1,169 @@
+use std::fmt;
+use std::hash;
+use std::ops::ControlFlow;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_serialize::{Decodable, Encodable};
+
+use crate::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::visit::{TypeVisitable, TypeVisitor};
+use crate::TyDecoder;
+use crate::{HashStableContext, Interner, TyEncoder, UniverseIndex};
+
+/// A "canonicalized" type `V` is one where all free inference
+/// variables have been rewritten to "canonical vars". These are
+/// numbered starting from 0 in order of first appearance.
+pub struct Canonical<I: Interner, V> {
+    pub value: V,
+    pub max_universe: UniverseIndex,
+    pub variables: I::CanonicalVars,
+}
+
+impl<I: Interner, V> Canonical<I, V> {
+    /// Allows you to map the `value` of a canonical while keeping the
+    /// same set of bound variables.
+    ///
+    /// **WARNING:** This function is very easy to mis-use, hence the
+    /// name!  In particular, the new value `W` must use all **the
+    /// same type/region variables** in **precisely the same order**
+    /// as the original! (The ordering is defined by the
+    /// `TypeFoldable` implementation of the type in question.)
+    ///
+    /// An example of a **correct** use of this:
+    ///
+    /// ```rust,ignore (not real code)
+    /// let a: Canonical<I, T> = ...;
+    /// let b: Canonical<I, (T,)> = a.unchecked_map(|v| (v, ));
+    /// ```
+    ///
+    /// An example of an **incorrect** use of this:
+    ///
+    /// ```rust,ignore (not real code)
+    /// let a: Canonical<I, T> = ...;
+    /// let ty: Ty<I> = ...;
+    /// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty));
+    /// ```
+    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
+        let Canonical { max_universe, variables, value } = self;
+        Canonical { max_universe, variables, value: map_op(value) }
+    }
+
+    /// Allows you to map the `value` of a canonical while keeping the same set of
+    /// bound variables.
+    ///
+    /// **WARNING:** This function is very easy to mis-use, hence the name! See
+    /// the comment of [Canonical::unchecked_map] for more details.
+    pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> {
+        let Canonical { max_universe, variables, value: _ } = self;
+        Canonical { max_universe, variables, value }
+    }
+}
+
+impl<I: Interner, V: hash::Hash> hash::Hash for Canonical<I, V> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.value.hash(state);
+        self.max_universe.hash(state);
+        self.variables.hash(state);
+    }
+}
+
+impl<CTX: HashStableContext, I: Interner, V: HashStable<CTX>> HashStable<CTX> for Canonical<I, V>
+where
+    I::CanonicalVars: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.value.hash_stable(hcx, hasher);
+        self.max_universe.hash_stable(hcx, hasher);
+        self.variables.hash_stable(hcx, hasher);
+    }
+}
+
+impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
+
+impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> {
+    fn eq(&self, other: &Self) -> bool {
+        self.value == other.value
+            && self.max_universe == other.max_universe
+            && self.variables == other.variables
+    }
+}
+
+impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
+            self.value, self.max_universe, self.variables
+        )
+    }
+}
+
+impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Canonical")
+            .field("value", &self.value)
+            .field("max_universe", &self.max_universe)
+            .field("variables", &self.variables)
+            .finish()
+    }
+}
+
+impl<I: Interner, V: Clone> Clone for Canonical<I, V> {
+    fn clone(&self) -> Self {
+        Canonical {
+            value: self.value.clone(),
+            max_universe: self.max_universe.clone(),
+            variables: self.variables.clone(),
+        }
+    }
+}
+
+impl<I: Interner, V: Copy> Copy for Canonical<I, V> where I::CanonicalVars: Copy {}
+
+impl<I: Interner, V: TypeFoldable<I>> TypeFoldable<I> for Canonical<I, V>
+where
+    I::CanonicalVars: TypeFoldable<I>,
+{
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(Canonical {
+            value: self.value.try_fold_with(folder)?,
+            max_universe: self.max_universe.try_fold_with(folder)?,
+            variables: self.variables.try_fold_with(folder)?,
+        })
+    }
+}
+
+impl<I: Interner, V: TypeVisitable<I>> TypeVisitable<I> for Canonical<I, V>
+where
+    I::CanonicalVars: TypeVisitable<I>,
+{
+    fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> ControlFlow<F::BreakTy> {
+        self.value.visit_with(folder)?;
+        self.max_universe.visit_with(folder)?;
+        self.variables.visit_with(folder)
+    }
+}
+
+impl<I: Interner, E: TyEncoder<I = I>, V: Encodable<E>> Encodable<E> for Canonical<I, V>
+where
+    I::CanonicalVars: Encodable<E>,
+{
+    fn encode(&self, s: &mut E) {
+        self.value.encode(s);
+        self.max_universe.encode(s);
+        self.variables.encode(s);
+    }
+}
+
+impl<I: Interner, D: TyDecoder<I = I>, V: Decodable<D>> Decodable<D> for Canonical<I, V>
+where
+    I::CanonicalVars: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        Canonical {
+            value: Decodable::decode(d),
+            max_universe: Decodable::decode(d),
+            variables: Decodable::decode(d),
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
index 3b638934629..2fbc8f76fa4 100644
--- a/compiler/rustc_type_ir/src/codec.rs
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -1,4 +1,4 @@
-use crate::Interner;
+use crate::{Interner, PredicateKind};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_serialize::{Decoder, Encoder};
@@ -30,9 +30,7 @@ pub trait TyEncoder: Encoder {
 
     fn type_shorthands(&mut self) -> &mut FxHashMap<<Self::I as Interner>::Ty, usize>;
 
-    fn predicate_shorthands(
-        &mut self,
-    ) -> &mut FxHashMap<<Self::I as Interner>::PredicateKind, usize>;
+    fn predicate_shorthands(&mut self) -> &mut FxHashMap<PredicateKind<Self::I>, usize>;
 
     fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId);
 }
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index f84841c9f64..a40c41583af 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -1,12 +1,13 @@
 use rustc_data_structures::stable_hasher::HashStable;
+use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_serialize::{Decodable, Decoder, Encodable};
 use std::cmp::Ordering;
 use std::fmt;
 use std::hash;
 
 use crate::{
-    DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx,
-    TyDecoder, TyEncoder,
+    DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, TyDecoder,
+    TyEncoder, WithInfcx,
 };
 
 use self::ConstKind::*;
@@ -86,11 +87,7 @@ where
     I::ErrorGuaranteed: HashStable<CTX>,
     I::ExprConst: HashStable<CTX>,
 {
-    fn hash_stable(
-        &self,
-        hcx: &mut CTX,
-        hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
-    ) {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         const_kind_discriminant(self).hash_stable(hcx, hasher);
         match self {
             Param(p) => p.hash_stable(hcx, hasher),
@@ -231,13 +228,13 @@ impl<I: Interner> Clone for ConstKind<I> {
 
 impl<I: Interner> fmt::Debug for ConstKind<I> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 
 impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         use ConstKind::*;
diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs
index 7c6a7846900..4ea3eb3e84f 100644
--- a/compiler/rustc_type_ir/src/debug.rs
+++ b/compiler/rustc_type_ir/src/debug.rs
@@ -3,38 +3,48 @@ use crate::{Interner, UniverseIndex};
 use core::fmt;
 use std::marker::PhantomData;
 
-pub trait InferCtxtLike<I: Interner> {
-    fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>;
+pub trait InferCtxtLike {
+    type Interner: Interner;
 
-    fn universe_of_lt(&self, lt: I::InferRegion) -> Option<UniverseIndex>;
+    fn universe_of_ty(&self, ty: <Self::Interner as Interner>::InferTy) -> Option<UniverseIndex>;
 
-    fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>;
+    fn universe_of_lt(
+        &self,
+        lt: <Self::Interner as Interner>::InferRegion,
+    ) -> Option<UniverseIndex>;
+
+    fn universe_of_ct(&self, ct: <Self::Interner as Interner>::InferConst)
+    -> Option<UniverseIndex>;
 }
 
-impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible {
+pub struct NoInfcx<I>(PhantomData<I>);
+
+impl<I: Interner> InferCtxtLike for NoInfcx<I> {
+    type Interner = I;
+
     fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> {
-        match *self {}
+        None
     }
 
     fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> {
-        match *self {}
+        None
     }
 
     fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> {
-        match *self {}
+        None
     }
 }
 
 pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result;
 }
 
 impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         <T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f)
@@ -42,8 +52,8 @@ impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
 }
 
 impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         match f.alternate() {
@@ -70,46 +80,45 @@ impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
     }
 }
 
-pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> {
+pub struct WithInfcx<'a, Infcx: InferCtxtLike, T> {
     pub data: T,
-    pub infcx: Option<&'a InfCtx>,
-    _interner: PhantomData<I>,
+    pub infcx: &'a Infcx,
 }
 
-impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {}
+impl<Infcx: InferCtxtLike, T: Copy> Copy for WithInfcx<'_, Infcx, T> {}
 
-impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> {
+impl<Infcx: InferCtxtLike, T: Clone> Clone for WithInfcx<'_, Infcx, T> {
     fn clone(&self) -> Self {
-        Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner }
+        Self { data: self.data.clone(), infcx: self.infcx }
     }
 }
 
-impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> {
-    pub fn new_no_ctx(data: T) -> Self {
-        Self { data, infcx: None, _interner: PhantomData }
+impl<'a, I: Interner, T> WithInfcx<'a, NoInfcx<I>, T> {
+    pub fn with_no_infcx(data: T) -> Self {
+        Self { data, infcx: &NoInfcx(PhantomData) }
     }
 }
 
-impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> {
-    pub fn new(data: T, infcx: &'a InfCtx) -> Self {
-        Self { data, infcx: Some(infcx), _interner: PhantomData }
+impl<'a, Infcx: InferCtxtLike, T> WithInfcx<'a, Infcx, T> {
+    pub fn new(data: T, infcx: &'a Infcx) -> Self {
+        Self { data, infcx }
     }
 
-    pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> {
-        OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData }
+    pub fn wrap<U>(self, u: U) -> WithInfcx<'a, Infcx, U> {
+        WithInfcx { data: u, infcx: self.infcx }
     }
 
-    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> {
-        OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData }
+    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> WithInfcx<'a, Infcx, U> {
+        WithInfcx { data: f(self.data), infcx: self.infcx }
     }
 
-    pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> {
-        OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData }
+    pub fn as_ref(&self) -> WithInfcx<'a, Infcx, &T> {
+        WithInfcx { data: &self.data, infcx: self.infcx }
     }
 }
 
-impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug
-    for OptWithInfcx<'_, I, InfCtx, T>
+impl<Infcx: InferCtxtLike, T: DebugWithInfcx<Infcx::Interner>> fmt::Debug
+    for WithInfcx<'_, Infcx, T>
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         DebugWithInfcx::fmt(self.as_ref(), f)
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 60e4c587993..7f75e5b35a2 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -14,14 +14,11 @@ pub trait Interner: Sized {
         + Ord
         + IntoIterator<Item = Self::GenericArg>;
     type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord;
+    type Term: Clone + Debug + Hash + Ord;
 
     type Binder<T>;
-
-    // Predicates
-    type Predicate;
-    type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
-
     type TypeAndMut: Clone + Debug + Hash + Ord;
+    type CanonicalVars: Clone + Debug + Hash + Eq;
 
     // Kinds of tys
     type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
@@ -56,6 +53,16 @@ pub trait Interner: Sized {
     type InferRegion: Clone + DebugWithInfcx<Self> + Hash + Ord;
     type PlaceholderRegion: Clone + Debug + Hash + Ord;
 
+    // Predicates
+    type Predicate: Clone + Debug + Hash + Eq;
+    type TraitPredicate: Clone + Debug + Hash + Eq;
+    type RegionOutlivesPredicate: Clone + Debug + Hash + Eq;
+    type TypeOutlivesPredicate: Clone + Debug + Hash + Eq;
+    type ProjectionPredicate: Clone + Debug + Hash + Eq;
+    type SubtypePredicate: Clone + Debug + Hash + Eq;
+    type CoercePredicate: Clone + Debug + Hash + Eq;
+    type ClosureKind: Clone + Debug + Hash + Eq;
+
     fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability);
 }
 
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index d4ca9da96e4..a056fbeda98 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -26,17 +26,21 @@ pub mod visit;
 
 #[macro_use]
 mod macros;
+mod canonical;
 mod const_kind;
 mod debug;
 mod flags;
 mod interner;
+mod predicate_kind;
 mod region_kind;
 
+pub use canonical::*;
 pub use codec::*;
 pub use const_kind::*;
-pub use debug::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
+pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx};
 pub use flags::*;
 pub use interner::*;
+pub use predicate_kind::*;
 pub use region_kind::*;
 pub use ty_info::*;
 pub use ty_kind::*;
diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs
index 9e10c65c20d..cfed84a35c6 100644
--- a/compiler/rustc_type_ir/src/macros.rs
+++ b/compiler/rustc_type_ir/src/macros.rs
@@ -49,4 +49,6 @@ TrivialTypeTraversalImpls! {
     u64,
     String,
     crate::DebruijnIndex,
+    crate::AliasRelationDirection,
+    crate::UniverseIndex,
 }
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
new file mode 100644
index 00000000000..f6fabe691c6
--- /dev/null
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -0,0 +1,626 @@
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_serialize::Decoder;
+use rustc_serialize::{Decodable, Encodable};
+use std::fmt;
+use std::hash;
+use std::ops::ControlFlow;
+
+use crate::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::visit::{TypeVisitable, TypeVisitor};
+use crate::{HashStableContext, Interner};
+use crate::{TyDecoder, TyEncoder};
+
+/// A clause is something that can appear in where bounds or be inferred
+/// by implied bounds.
+pub enum ClauseKind<I: Interner> {
+    /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
+    /// the `Self` type of the trait reference and `A`, `B`, and `C`
+    /// would be the type parameters.
+    Trait(I::TraitPredicate),
+
+    /// `where 'a: 'b`
+    RegionOutlives(I::RegionOutlivesPredicate),
+
+    /// `where T: 'a`
+    TypeOutlives(I::TypeOutlivesPredicate),
+
+    /// `where <T as TraitRef>::Name == X`, approximately.
+    /// See the `ProjectionPredicate` struct for details.
+    Projection(I::ProjectionPredicate),
+
+    /// Ensures that a const generic argument to a parameter `const N: u8`
+    /// is of type `u8`.
+    ConstArgHasType(I::Const, I::Ty),
+
+    /// No syntax: `T` well-formed.
+    WellFormed(I::GenericArg),
+
+    /// Constant initializer must evaluate successfully.
+    ConstEvaluatable(I::Const),
+}
+
+impl<I: Interner> Clone for ClauseKind<I> {
+    fn clone(&self) -> Self {
+        match self {
+            Self::Trait(arg0) => Self::Trait(arg0.clone()),
+            Self::RegionOutlives(arg0) => Self::RegionOutlives(arg0.clone()),
+            Self::TypeOutlives(arg0) => Self::TypeOutlives(arg0.clone()),
+            Self::Projection(arg0) => Self::Projection(arg0.clone()),
+            Self::ConstArgHasType(arg0, arg1) => Self::ConstArgHasType(arg0.clone(), arg1.clone()),
+            Self::WellFormed(arg0) => Self::WellFormed(arg0.clone()),
+            Self::ConstEvaluatable(arg0) => Self::ConstEvaluatable(arg0.clone()),
+        }
+    }
+}
+
+impl<I: Interner> Copy for ClauseKind<I>
+where
+    I::Ty: Copy,
+    I::Const: Copy,
+    I::GenericArg: Copy,
+    I::TraitPredicate: Copy,
+    I::ProjectionPredicate: Copy,
+    I::TypeOutlivesPredicate: Copy,
+    I::RegionOutlivesPredicate: Copy,
+{
+}
+
+impl<I: Interner> PartialEq for ClauseKind<I> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Self::Trait(l0), Self::Trait(r0)) => l0 == r0,
+            (Self::RegionOutlives(l0), Self::RegionOutlives(r0)) => l0 == r0,
+            (Self::TypeOutlives(l0), Self::TypeOutlives(r0)) => l0 == r0,
+            (Self::Projection(l0), Self::Projection(r0)) => l0 == r0,
+            (Self::ConstArgHasType(l0, l1), Self::ConstArgHasType(r0, r1)) => l0 == r0 && l1 == r1,
+            (Self::WellFormed(l0), Self::WellFormed(r0)) => l0 == r0,
+            (Self::ConstEvaluatable(l0), Self::ConstEvaluatable(r0)) => l0 == r0,
+            _ => false,
+        }
+    }
+}
+
+impl<I: Interner> Eq for ClauseKind<I> {}
+
+fn clause_kind_discriminant<I: Interner>(value: &ClauseKind<I>) -> usize {
+    match value {
+        ClauseKind::Trait(_) => 0,
+        ClauseKind::RegionOutlives(_) => 1,
+        ClauseKind::TypeOutlives(_) => 2,
+        ClauseKind::Projection(_) => 3,
+        ClauseKind::ConstArgHasType(_, _) => 4,
+        ClauseKind::WellFormed(_) => 5,
+        ClauseKind::ConstEvaluatable(_) => 6,
+    }
+}
+
+impl<I: Interner> hash::Hash for ClauseKind<I> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        clause_kind_discriminant(self).hash(state);
+        match self {
+            ClauseKind::Trait(p) => p.hash(state),
+            ClauseKind::RegionOutlives(p) => p.hash(state),
+            ClauseKind::TypeOutlives(p) => p.hash(state),
+            ClauseKind::Projection(p) => p.hash(state),
+            ClauseKind::ConstArgHasType(c, t) => {
+                c.hash(state);
+                t.hash(state);
+            }
+            ClauseKind::WellFormed(t) => t.hash(state),
+            ClauseKind::ConstEvaluatable(c) => c.hash(state),
+        }
+    }
+}
+
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ClauseKind<I>
+where
+    I::Ty: HashStable<CTX>,
+    I::Const: HashStable<CTX>,
+    I::GenericArg: HashStable<CTX>,
+    I::TraitPredicate: HashStable<CTX>,
+    I::ProjectionPredicate: HashStable<CTX>,
+    I::TypeOutlivesPredicate: HashStable<CTX>,
+    I::RegionOutlivesPredicate: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        clause_kind_discriminant(self).hash_stable(hcx, hasher);
+        match self {
+            ClauseKind::Trait(p) => p.hash_stable(hcx, hasher),
+            ClauseKind::RegionOutlives(p) => p.hash_stable(hcx, hasher),
+            ClauseKind::TypeOutlives(p) => p.hash_stable(hcx, hasher),
+            ClauseKind::Projection(p) => p.hash_stable(hcx, hasher),
+            ClauseKind::ConstArgHasType(c, t) => {
+                c.hash_stable(hcx, hasher);
+                t.hash_stable(hcx, hasher);
+            }
+            ClauseKind::WellFormed(t) => t.hash_stable(hcx, hasher),
+            ClauseKind::ConstEvaluatable(c) => c.hash_stable(hcx, hasher),
+        }
+    }
+}
+
+impl<I: Interner> TypeFoldable<I> for ClauseKind<I>
+where
+    I::Ty: TypeFoldable<I>,
+    I::Const: TypeFoldable<I>,
+    I::GenericArg: TypeFoldable<I>,
+    I::TraitPredicate: TypeFoldable<I>,
+    I::ProjectionPredicate: TypeFoldable<I>,
+    I::TypeOutlivesPredicate: TypeFoldable<I>,
+    I::RegionOutlivesPredicate: TypeFoldable<I>,
+{
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(match self {
+            ClauseKind::Trait(p) => ClauseKind::Trait(p.try_fold_with(folder)?),
+            ClauseKind::RegionOutlives(p) => ClauseKind::RegionOutlives(p.try_fold_with(folder)?),
+            ClauseKind::TypeOutlives(p) => ClauseKind::TypeOutlives(p.try_fold_with(folder)?),
+            ClauseKind::Projection(p) => ClauseKind::Projection(p.try_fold_with(folder)?),
+            ClauseKind::ConstArgHasType(c, t) => {
+                ClauseKind::ConstArgHasType(c.try_fold_with(folder)?, t.try_fold_with(folder)?)
+            }
+            ClauseKind::WellFormed(p) => ClauseKind::WellFormed(p.try_fold_with(folder)?),
+            ClauseKind::ConstEvaluatable(p) => {
+                ClauseKind::ConstEvaluatable(p.try_fold_with(folder)?)
+            }
+        })
+    }
+}
+
+impl<I: Interner> TypeVisitable<I> for ClauseKind<I>
+where
+    I::Ty: TypeVisitable<I>,
+    I::Const: TypeVisitable<I>,
+    I::GenericArg: TypeVisitable<I>,
+    I::TraitPredicate: TypeVisitable<I>,
+    I::ProjectionPredicate: TypeVisitable<I>,
+    I::TypeOutlivesPredicate: TypeVisitable<I>,
+    I::RegionOutlivesPredicate: TypeVisitable<I>,
+{
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        match self {
+            ClauseKind::Trait(p) => p.visit_with(visitor),
+            ClauseKind::RegionOutlives(p) => p.visit_with(visitor),
+            ClauseKind::TypeOutlives(p) => p.visit_with(visitor),
+            ClauseKind::Projection(p) => p.visit_with(visitor),
+            ClauseKind::ConstArgHasType(c, t) => {
+                c.visit_with(visitor)?;
+                t.visit_with(visitor)
+            }
+            ClauseKind::WellFormed(p) => p.visit_with(visitor),
+            ClauseKind::ConstEvaluatable(p) => p.visit_with(visitor),
+        }
+    }
+}
+
+impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ClauseKind<I>
+where
+    I::Ty: Decodable<D>,
+    I::Const: Decodable<D>,
+    I::GenericArg: Decodable<D>,
+    I::TraitPredicate: Decodable<D>,
+    I::ProjectionPredicate: Decodable<D>,
+    I::TypeOutlivesPredicate: Decodable<D>,
+    I::RegionOutlivesPredicate: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        match Decoder::read_usize(d) {
+            0 => ClauseKind::Trait(Decodable::decode(d)),
+            1 => ClauseKind::RegionOutlives(Decodable::decode(d)),
+            2 => ClauseKind::TypeOutlives(Decodable::decode(d)),
+            3 => ClauseKind::Projection(Decodable::decode(d)),
+            4 => ClauseKind::ConstArgHasType(Decodable::decode(d), Decodable::decode(d)),
+            5 => ClauseKind::WellFormed(Decodable::decode(d)),
+            6 => ClauseKind::ConstEvaluatable(Decodable::decode(d)),
+            _ => panic!(
+                "{}",
+                format!(
+                    "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                    "ClauseKind", 7,
+                )
+            ),
+        }
+    }
+}
+
+impl<I: Interner, E: TyEncoder> Encodable<E> for ClauseKind<I>
+where
+    I::Ty: Encodable<E>,
+    I::Const: Encodable<E>,
+    I::GenericArg: Encodable<E>,
+    I::TraitPredicate: Encodable<E>,
+    I::ProjectionPredicate: Encodable<E>,
+    I::TypeOutlivesPredicate: Encodable<E>,
+    I::RegionOutlivesPredicate: Encodable<E>,
+{
+    fn encode(&self, s: &mut E) {
+        let discriminant = clause_kind_discriminant(self);
+        match self {
+            ClauseKind::Trait(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::RegionOutlives(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::TypeOutlives(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::Projection(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::ConstArgHasType(c, t) => s.emit_enum_variant(discriminant, |s| {
+                c.encode(s);
+                t.encode(s);
+            }),
+            ClauseKind::WellFormed(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+            ClauseKind::ConstEvaluatable(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)),
+        }
+    }
+}
+
+pub enum PredicateKind<I: Interner> {
+    /// Prove a clause
+    Clause(ClauseKind<I>),
+
+    /// Trait must be object-safe.
+    ObjectSafe(I::DefId),
+
+    /// No direct syntax. May be thought of as `where T: FnFoo<...>`
+    /// for some generic args `...` and `T` being a closure type.
+    /// Satisfied (or refuted) once we know the closure's kind.
+    ClosureKind(I::DefId, I::GenericArgs, I::ClosureKind),
+
+    /// `T1 <: T2`
+    ///
+    /// This obligation is created most often when we have two
+    /// unresolved type variables and hence don't have enough
+    /// information to process the subtyping obligation yet.
+    Subtype(I::SubtypePredicate),
+
+    /// `T1` coerced to `T2`
+    ///
+    /// Like a subtyping obligation, this is created most often
+    /// when we have two unresolved type variables and hence
+    /// don't have enough information to process the coercion
+    /// obligation yet. At the moment, we actually process coercions
+    /// very much like subtyping and don't handle the full coercion
+    /// logic.
+    Coerce(I::CoercePredicate),
+
+    /// Constants must be equal. The first component is the const that is expected.
+    ConstEquate(I::Const, I::Const),
+
+    /// A marker predicate that is always ambiguous.
+    /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
+    Ambiguous,
+
+    /// Separate from `ClauseKind::Projection` which is used for normalization in new solver.
+    /// This predicate requires two terms to be equal to eachother.
+    ///
+    /// Only used for new solver
+    AliasRelate(I::Term, I::Term, AliasRelationDirection),
+}
+
+impl<I: Interner> Copy for PredicateKind<I>
+where
+    I::DefId: Copy,
+    I::Const: Copy,
+    I::GenericArgs: Copy,
+    I::Term: Copy,
+    I::CoercePredicate: Copy,
+    I::SubtypePredicate: Copy,
+    I::ClosureKind: Copy,
+    ClauseKind<I>: Copy,
+{
+}
+
+impl<I: Interner> Clone for PredicateKind<I> {
+    fn clone(&self) -> Self {
+        match self {
+            Self::Clause(arg0) => Self::Clause(arg0.clone()),
+            Self::ObjectSafe(arg0) => Self::ObjectSafe(arg0.clone()),
+            Self::ClosureKind(arg0, arg1, arg2) => {
+                Self::ClosureKind(arg0.clone(), arg1.clone(), arg2.clone())
+            }
+            Self::Subtype(arg0) => Self::Subtype(arg0.clone()),
+            Self::Coerce(arg0) => Self::Coerce(arg0.clone()),
+            Self::ConstEquate(arg0, arg1) => Self::ConstEquate(arg0.clone(), arg1.clone()),
+            Self::Ambiguous => Self::Ambiguous,
+            Self::AliasRelate(arg0, arg1, arg2) => {
+                Self::AliasRelate(arg0.clone(), arg1.clone(), arg2.clone())
+            }
+        }
+    }
+}
+
+impl<I: Interner> PartialEq for PredicateKind<I> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Self::Clause(l0), Self::Clause(r0)) => l0 == r0,
+            (Self::ObjectSafe(l0), Self::ObjectSafe(r0)) => l0 == r0,
+            (Self::ClosureKind(l0, l1, l2), Self::ClosureKind(r0, r1, r2)) => {
+                l0 == r0 && l1 == r1 && l2 == r2
+            }
+            (Self::Subtype(l0), Self::Subtype(r0)) => l0 == r0,
+            (Self::Coerce(l0), Self::Coerce(r0)) => l0 == r0,
+            (Self::ConstEquate(l0, l1), Self::ConstEquate(r0, r1)) => l0 == r0 && l1 == r1,
+            (Self::AliasRelate(l0, l1, l2), Self::AliasRelate(r0, r1, r2)) => {
+                l0 == r0 && l1 == r1 && l2 == r2
+            }
+            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
+        }
+    }
+}
+
+impl<I: Interner> Eq for PredicateKind<I> {}
+
+fn predicate_kind_discriminant<I: Interner>(value: &PredicateKind<I>) -> usize {
+    match value {
+        PredicateKind::Clause(_) => 0,
+        PredicateKind::ObjectSafe(_) => 1,
+        PredicateKind::ClosureKind(_, _, _) => 2,
+        PredicateKind::Subtype(_) => 3,
+        PredicateKind::Coerce(_) => 4,
+        PredicateKind::ConstEquate(_, _) => 5,
+        PredicateKind::Ambiguous => 6,
+        PredicateKind::AliasRelate(_, _, _) => 7,
+    }
+}
+
+impl<I: Interner> hash::Hash for PredicateKind<I> {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        predicate_kind_discriminant(self).hash(state);
+        match self {
+            PredicateKind::Clause(p) => p.hash(state),
+            PredicateKind::ObjectSafe(d) => d.hash(state),
+            PredicateKind::ClosureKind(d, g, k) => {
+                d.hash(state);
+                g.hash(state);
+                k.hash(state);
+            }
+            PredicateKind::Subtype(p) => p.hash(state),
+            PredicateKind::Coerce(p) => p.hash(state),
+            PredicateKind::ConstEquate(c1, c2) => {
+                c1.hash(state);
+                c2.hash(state);
+            }
+            PredicateKind::Ambiguous => {}
+            PredicateKind::AliasRelate(t1, t2, r) => {
+                t1.hash(state);
+                t2.hash(state);
+                r.hash(state);
+            }
+        }
+    }
+}
+
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for PredicateKind<I>
+where
+    I::DefId: HashStable<CTX>,
+    I::Const: HashStable<CTX>,
+    I::GenericArgs: HashStable<CTX>,
+    I::Term: HashStable<CTX>,
+    I::CoercePredicate: HashStable<CTX>,
+    I::SubtypePredicate: HashStable<CTX>,
+    I::ClosureKind: HashStable<CTX>,
+    ClauseKind<I>: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        predicate_kind_discriminant(self).hash_stable(hcx, hasher);
+        match self {
+            PredicateKind::Clause(p) => p.hash_stable(hcx, hasher),
+            PredicateKind::ObjectSafe(d) => d.hash_stable(hcx, hasher),
+            PredicateKind::ClosureKind(d, g, k) => {
+                d.hash_stable(hcx, hasher);
+                g.hash_stable(hcx, hasher);
+                k.hash_stable(hcx, hasher);
+            }
+            PredicateKind::Subtype(p) => p.hash_stable(hcx, hasher),
+            PredicateKind::Coerce(p) => p.hash_stable(hcx, hasher),
+            PredicateKind::ConstEquate(c1, c2) => {
+                c1.hash_stable(hcx, hasher);
+                c2.hash_stable(hcx, hasher);
+            }
+            PredicateKind::Ambiguous => {}
+            PredicateKind::AliasRelate(t1, t2, r) => {
+                t1.hash_stable(hcx, hasher);
+                t2.hash_stable(hcx, hasher);
+                r.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<I: Interner> TypeFoldable<I> for PredicateKind<I>
+where
+    I::DefId: TypeFoldable<I>,
+    I::Const: TypeFoldable<I>,
+    I::GenericArgs: TypeFoldable<I>,
+    I::Term: TypeFoldable<I>,
+    I::CoercePredicate: TypeFoldable<I>,
+    I::SubtypePredicate: TypeFoldable<I>,
+    I::ClosureKind: TypeFoldable<I>,
+    ClauseKind<I>: TypeFoldable<I>,
+{
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(match self {
+            PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?),
+            PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?),
+            PredicateKind::ClosureKind(d, g, k) => PredicateKind::ClosureKind(
+                d.try_fold_with(folder)?,
+                g.try_fold_with(folder)?,
+                k.try_fold_with(folder)?,
+            ),
+            PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?),
+            PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?),
+            PredicateKind::ConstEquate(a, b) => {
+                PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?)
+            }
+            PredicateKind::Ambiguous => PredicateKind::Ambiguous,
+            PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate(
+                a.try_fold_with(folder)?,
+                b.try_fold_with(folder)?,
+                d.try_fold_with(folder)?,
+            ),
+        })
+    }
+}
+
+impl<I: Interner> TypeVisitable<I> for PredicateKind<I>
+where
+    I::DefId: TypeVisitable<I>,
+    I::Const: TypeVisitable<I>,
+    I::GenericArgs: TypeVisitable<I>,
+    I::Term: TypeVisitable<I>,
+    I::CoercePredicate: TypeVisitable<I>,
+    I::SubtypePredicate: TypeVisitable<I>,
+    I::ClosureKind: TypeVisitable<I>,
+    ClauseKind<I>: TypeVisitable<I>,
+{
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        match self {
+            PredicateKind::Clause(p) => p.visit_with(visitor),
+            PredicateKind::ObjectSafe(d) => d.visit_with(visitor),
+            PredicateKind::ClosureKind(d, g, k) => {
+                d.visit_with(visitor)?;
+                g.visit_with(visitor)?;
+                k.visit_with(visitor)
+            }
+            PredicateKind::Subtype(s) => s.visit_with(visitor),
+            PredicateKind::Coerce(s) => s.visit_with(visitor),
+            PredicateKind::ConstEquate(a, b) => {
+                a.visit_with(visitor)?;
+                b.visit_with(visitor)
+            }
+            PredicateKind::Ambiguous => ControlFlow::Continue(()),
+            PredicateKind::AliasRelate(a, b, d) => {
+                a.visit_with(visitor)?;
+                b.visit_with(visitor)?;
+                d.visit_with(visitor)
+            }
+        }
+    }
+}
+
+impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for PredicateKind<I>
+where
+    I::DefId: Decodable<D>,
+    I::Const: Decodable<D>,
+    I::GenericArgs: Decodable<D>,
+    I::Term: Decodable<D>,
+    I::CoercePredicate: Decodable<D>,
+    I::SubtypePredicate: Decodable<D>,
+    I::ClosureKind: Decodable<D>,
+    ClauseKind<I>: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        match Decoder::read_usize(d) {
+            0 => PredicateKind::Clause(Decodable::decode(d)),
+            1 => PredicateKind::ObjectSafe(Decodable::decode(d)),
+            2 => PredicateKind::ClosureKind(
+                Decodable::decode(d),
+                Decodable::decode(d),
+                Decodable::decode(d),
+            ),
+            3 => PredicateKind::Subtype(Decodable::decode(d)),
+            4 => PredicateKind::Coerce(Decodable::decode(d)),
+            5 => PredicateKind::ConstEquate(Decodable::decode(d), Decodable::decode(d)),
+            6 => PredicateKind::Ambiguous,
+            7 => PredicateKind::AliasRelate(
+                Decodable::decode(d),
+                Decodable::decode(d),
+                Decodable::decode(d),
+            ),
+            _ => panic!(
+                "{}",
+                format!(
+                    "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                    "PredicateKind", 8,
+                )
+            ),
+        }
+    }
+}
+
+impl<I: Interner, E: TyEncoder> Encodable<E> for PredicateKind<I>
+where
+    I::DefId: Encodable<E>,
+    I::Const: Encodable<E>,
+    I::GenericArgs: Encodable<E>,
+    I::Term: Encodable<E>,
+    I::CoercePredicate: Encodable<E>,
+    I::SubtypePredicate: Encodable<E>,
+    I::ClosureKind: Encodable<E>,
+    ClauseKind<I>: Encodable<E>,
+{
+    fn encode(&self, s: &mut E) {
+        let discriminant = predicate_kind_discriminant(self);
+        match self {
+            PredicateKind::Clause(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)),
+            PredicateKind::ObjectSafe(d) => s.emit_enum_variant(discriminant, |s| d.encode(s)),
+            PredicateKind::ClosureKind(d, g, k) => s.emit_enum_variant(discriminant, |s| {
+                d.encode(s);
+                g.encode(s);
+                k.encode(s);
+            }),
+            PredicateKind::Subtype(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)),
+            PredicateKind::Coerce(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)),
+            PredicateKind::ConstEquate(a, b) => s.emit_enum_variant(discriminant, |s| {
+                a.encode(s);
+                b.encode(s);
+            }),
+            PredicateKind::Ambiguous => s.emit_enum_variant(discriminant, |_s| {}),
+            PredicateKind::AliasRelate(a, b, d) => s.emit_enum_variant(discriminant, |s| {
+                a.encode(s);
+                b.encode(s);
+                d.encode(s);
+            }),
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
+pub enum AliasRelationDirection {
+    Equate,
+    Subtype,
+}
+
+impl std::fmt::Display for AliasRelationDirection {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            AliasRelationDirection::Equate => write!(f, "=="),
+            AliasRelationDirection::Subtype => write!(f, "<:"),
+        }
+    }
+}
+
+// FIXME: Convert to DebugWithInfcx impl
+impl<I: Interner> fmt::Debug for ClauseKind<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"),
+            ClauseKind::Trait(a) => a.fmt(f),
+            ClauseKind::RegionOutlives(pair) => pair.fmt(f),
+            ClauseKind::TypeOutlives(pair) => pair.fmt(f),
+            ClauseKind::Projection(pair) => pair.fmt(f),
+            ClauseKind::WellFormed(data) => write!(f, "WellFormed({data:?})"),
+            ClauseKind::ConstEvaluatable(ct) => {
+                write!(f, "ConstEvaluatable({ct:?})")
+            }
+        }
+    }
+}
+
+// FIXME: Convert to DebugWithInfcx impl
+impl<I: Interner> fmt::Debug for PredicateKind<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            PredicateKind::Clause(a) => a.fmt(f),
+            PredicateKind::Subtype(pair) => pair.fmt(f),
+            PredicateKind::Coerce(pair) => pair.fmt(f),
+            PredicateKind::ObjectSafe(trait_def_id) => {
+                write!(f, "ObjectSafe({trait_def_id:?})")
+            }
+            PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
+                write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})")
+            }
+            PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"),
+            PredicateKind::Ambiguous => write!(f, "Ambiguous"),
+            PredicateKind::AliasRelate(t1, t2, dir) => {
+                write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index 0006eec4d30..19576ea58f1 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -1,12 +1,13 @@
 use rustc_data_structures::stable_hasher::HashStable;
+use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_serialize::{Decodable, Decoder, Encodable};
 use std::cmp::Ordering;
 use std::fmt;
 use std::hash;
 
 use crate::{
-    DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx,
-    TyDecoder, TyEncoder,
+    DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, TyDecoder,
+    TyEncoder, WithInfcx,
 };
 
 use self::RegionKind::*;
@@ -274,8 +275,8 @@ impl<I: Interner> hash::Hash for RegionKind<I> {
 }
 
 impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
         match this.data {
@@ -301,12 +302,12 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
 }
 impl<I: Interner> fmt::Debug for RegionKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 
 // This is manually implemented because a derive would require `I: Encodable`
-impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
+impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for RegionKind<I>
 where
     I::EarlyBoundRegion: Encodable<E>,
     I::BoundRegion: Encodable<E>,
@@ -381,11 +382,7 @@ where
     I::PlaceholderRegion: HashStable<CTX>,
 {
     #[inline]
-    fn hash_stable(
-        &self,
-        hcx: &mut CTX,
-        hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
-    ) {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         std::mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
             ReErased | ReStatic | ReError(_) => {
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 91bfce9a142..b542547589a 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -11,7 +11,7 @@ use crate::HashStableContext;
 use crate::Interner;
 use crate::TyDecoder;
 use crate::TyEncoder;
-use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
+use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx};
 
 use self::TyKind::*;
 
@@ -534,8 +534,8 @@ impl<I: Interner> hash::Hash for TyKind<I> {
 }
 
 impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> fmt::Result {
         match this.data {
@@ -617,12 +617,12 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
 // This is manually implemented because a derive would require `I: Debug`
 impl<I: Interner> fmt::Debug for TyKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        OptWithInfcx::new_no_ctx(self).fmt(f)
+        WithInfcx::with_no_infcx(self).fmt(f)
     }
 }
 
 // This is manually implemented because a derive would require `I: Encodable`
-impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
+impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for TyKind<I>
 where
     I::ErrorGuaranteed: Encodable<E>,
     I::AdtDef: Encodable<E>,
@@ -640,7 +640,6 @@ where
     I::BoundTy: Encodable<E>,
     I::PlaceholderTy: Encodable<E>,
     I::InferTy: Encodable<E>,
-    I::PredicateKind: Encodable<E>,
     I::AllocId: Encodable<E>,
 {
     fn encode(&self, e: &mut E) {
@@ -753,7 +752,6 @@ where
     I::BoundTy: Decodable<D>,
     I::PlaceholderTy: Decodable<D>,
     I::InferTy: Decodable<D>,
-    I::PredicateKind: Decodable<D>,
     I::AllocId: Decodable<D>,
 {
     fn decode(d: &mut D) -> Self {
@@ -817,11 +815,7 @@ where
     I::ErrorGuaranteed: HashStable<CTX>,
 {
     #[inline]
-    fn hash_stable(
-        &self,
-        __hcx: &mut CTX,
-        __hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
-    ) {
+    fn hash_stable(&self, __hcx: &mut CTX, __hasher: &mut StableHasher) {
         std::mem::discriminant(self).hash_stable(__hcx, __hasher);
         match self {
             Bool => {}
@@ -1239,12 +1233,12 @@ impl fmt::Debug for InferTy {
 }
 
 impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy {
-    fn fmt<InfCtx: InferCtxtLike<I>>(
-        this: OptWithInfcx<'_, I, InfCtx, &Self>,
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
         f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         use InferTy::*;
-        match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) {
+        match this.infcx.universe_of_ty(*this.data) {
             None => write!(f, "{:?}", this.data),
             Some(universe) => match *this.data {
                 TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()),
diff --git a/compiler/stable_mir/src/fold.rs b/compiler/stable_mir/src/fold.rs
deleted file mode 100644
index ca6ea92c4a1..00000000000
--- a/compiler/stable_mir/src/fold.rs
+++ /dev/null
@@ -1,245 +0,0 @@
-use std::ops::ControlFlow;
-
-use crate::Opaque;
-
-use super::ty::{
-    Allocation, Binder, Const, ConstDef, ConstantKind, ExistentialPredicate, FnSig, GenericArgKind,
-    GenericArgs, Promoted, Region, RigidTy, TermKind, Ty, TyKind, UnevaluatedConst,
-};
-
-pub trait Folder: Sized {
-    type Break;
-    fn fold_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> {
-        ty.super_fold(self)
-    }
-    fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> {
-        c.super_fold(self)
-    }
-    fn fold_reg(&mut self, reg: &Region) -> ControlFlow<Self::Break, Region> {
-        reg.super_fold(self)
-    }
-}
-
-pub trait Foldable: Sized + Clone {
-    fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        self.super_fold(folder)
-    }
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self>;
-}
-
-impl Foldable for Ty {
-    fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        folder.fold_ty(self)
-    }
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        let mut kind = self.kind();
-        match &mut kind {
-            super::ty::TyKind::RigidTy(ty) => *ty = ty.fold(folder)?,
-            super::ty::TyKind::Alias(_, alias) => alias.args = alias.args.fold(folder)?,
-            super::ty::TyKind::Param(_) => {}
-            super::ty::TyKind::Bound(_, _) => {}
-        }
-        ControlFlow::Continue(kind.into())
-    }
-}
-
-impl Foldable for Const {
-    fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        folder.fold_const(self)
-    }
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        let mut this = self.clone();
-        match &mut this.literal {
-            super::ty::ConstantKind::Allocated(alloc) => *alloc = alloc.fold(folder)?,
-            super::ty::ConstantKind::Unevaluated(uv) => *uv = uv.fold(folder)?,
-            super::ty::ConstantKind::Param(_) => {}
-        }
-        this.ty = this.ty.fold(folder)?;
-        ControlFlow::Continue(this)
-    }
-}
-
-impl Foldable for Opaque {
-    fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(self.clone())
-    }
-}
-
-impl Foldable for Allocation {
-    fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(self.clone())
-    }
-}
-
-impl Foldable for UnevaluatedConst {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        let UnevaluatedConst { def, args, promoted } = self;
-        ControlFlow::Continue(UnevaluatedConst {
-            def: def.fold(folder)?,
-            args: args.fold(folder)?,
-            promoted: promoted.fold(folder)?,
-        })
-    }
-}
-
-impl Foldable for ConstDef {
-    fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(*self)
-    }
-}
-
-impl<T: Foldable> Foldable for Option<T> {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(match self {
-            Some(val) => Some(val.fold(folder)?),
-            None => None,
-        })
-    }
-}
-
-impl Foldable for Promoted {
-    fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(*self)
-    }
-}
-
-impl Foldable for GenericArgs {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(GenericArgs(self.0.fold(folder)?))
-    }
-}
-
-impl Foldable for Region {
-    fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        folder.fold_reg(self)
-    }
-    fn super_fold<V: Folder>(&self, _: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(self.clone())
-    }
-}
-
-impl Foldable for GenericArgKind {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        let mut this = self.clone();
-        match &mut this {
-            GenericArgKind::Lifetime(lt) => *lt = lt.fold(folder)?,
-            GenericArgKind::Type(t) => *t = t.fold(folder)?,
-            GenericArgKind::Const(c) => *c = c.fold(folder)?,
-        }
-        ControlFlow::Continue(this)
-    }
-}
-
-impl Foldable for RigidTy {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        let mut this = self.clone();
-        match &mut this {
-            RigidTy::Bool
-            | RigidTy::Char
-            | RigidTy::Int(_)
-            | RigidTy::Uint(_)
-            | RigidTy::Float(_)
-            | RigidTy::Never
-            | RigidTy::Foreign(_)
-            | RigidTy::Str => {}
-            RigidTy::Array(t, c) => {
-                *t = t.fold(folder)?;
-                *c = c.fold(folder)?;
-            }
-            RigidTy::Slice(inner) => *inner = inner.fold(folder)?,
-            RigidTy::RawPtr(ty, _) => *ty = ty.fold(folder)?,
-            RigidTy::Ref(reg, ty, _) => {
-                *reg = reg.fold(folder)?;
-                *ty = ty.fold(folder)?
-            }
-            RigidTy::FnDef(_, args) => *args = args.fold(folder)?,
-            RigidTy::FnPtr(sig) => *sig = sig.fold(folder)?,
-            RigidTy::Closure(_, args) => *args = args.fold(folder)?,
-            RigidTy::Coroutine(_, args, _) => *args = args.fold(folder)?,
-            RigidTy::Dynamic(pred, r, _) => {
-                *pred = pred.fold(folder)?;
-                *r = r.fold(folder)?;
-            }
-            RigidTy::Tuple(fields) => *fields = fields.fold(folder)?,
-            RigidTy::Adt(_, args) => *args = args.fold(folder)?,
-        }
-        ControlFlow::Continue(this)
-    }
-}
-
-impl<T: Foldable> Foldable for Vec<T> {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        let mut this = self.clone();
-        for arg in &mut this {
-            *arg = arg.fold(folder)?;
-        }
-        ControlFlow::Continue(this)
-    }
-}
-
-impl<T: Foldable> Foldable for Binder<T> {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(Self {
-            value: self.value.fold(folder)?,
-            bound_vars: self.bound_vars.clone(),
-        })
-    }
-}
-
-impl Foldable for ExistentialPredicate {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        let mut this = self.clone();
-        match &mut this {
-            ExistentialPredicate::Trait(tr) => tr.generic_args = tr.generic_args.fold(folder)?,
-            ExistentialPredicate::Projection(p) => {
-                p.term = p.term.fold(folder)?;
-                p.generic_args = p.generic_args.fold(folder)?;
-            }
-            ExistentialPredicate::AutoTrait(_) => {}
-        }
-        ControlFlow::Continue(this)
-    }
-}
-
-impl Foldable for TermKind {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(match self {
-            TermKind::Type(t) => TermKind::Type(t.fold(folder)?),
-            TermKind::Const(c) => TermKind::Const(c.fold(folder)?),
-        })
-    }
-}
-
-impl Foldable for FnSig {
-    fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> {
-        ControlFlow::Continue(Self {
-            inputs_and_output: self.inputs_and_output.fold(folder)?,
-            c_variadic: self.c_variadic,
-            unsafety: self.unsafety,
-            abi: self.abi.clone(),
-        })
-    }
-}
-
-pub enum Never {}
-
-/// In order to instantiate a `Foldable`'s generic parameters with specific arguments,
-/// `GenericArgs` can be used as a `Folder` that replaces all mentions of generic params
-/// with the entries in its list.
-impl Folder for GenericArgs {
-    type Break = Never;
-
-    fn fold_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> {
-        ControlFlow::Continue(match ty.kind() {
-            TyKind::Param(p) => self[p],
-            _ => *ty,
-        })
-    }
-
-    fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> {
-        ControlFlow::Continue(match &c.literal {
-            ConstantKind::Param(p) => self[p.clone()].clone(),
-            _ => c.clone(),
-        })
-    }
-}
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index be5ccac78c7..38915afaa0c 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -32,7 +32,6 @@ use self::ty::{
 extern crate scoped_tls;
 
 pub mod error;
-pub mod fold;
 pub mod mir;
 pub mod ty;
 pub mod visitor;
@@ -175,17 +174,17 @@ pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait {
 }
 
 pub trait Context {
-    fn entry_fn(&mut self) -> Option<CrateItem>;
+    fn entry_fn(&self) -> Option<CrateItem>;
     /// Retrieve all items of the local crate that have a MIR associated with them.
-    fn all_local_items(&mut self) -> CrateItems;
-    fn mir_body(&mut self, item: DefId) -> mir::Body;
-    fn all_trait_decls(&mut self) -> TraitDecls;
-    fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl;
-    fn all_trait_impls(&mut self) -> ImplTraitDecls;
-    fn trait_impl(&mut self, trait_impl: &ImplDef) -> ImplTrait;
-    fn generics_of(&mut self, def_id: DefId) -> Generics;
-    fn predicates_of(&mut self, def_id: DefId) -> GenericPredicates;
-    fn explicit_predicates_of(&mut self, def_id: DefId) -> GenericPredicates;
+    fn all_local_items(&self) -> CrateItems;
+    fn mir_body(&self, item: DefId) -> mir::Body;
+    fn all_trait_decls(&self) -> TraitDecls;
+    fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
+    fn all_trait_impls(&self) -> ImplTraitDecls;
+    fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
+    fn generics_of(&self, def_id: DefId) -> Generics;
+    fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
+    fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
     /// Get information about the local crate.
     fn local_crate(&self) -> Crate;
     /// Retrieve a list of all external crates.
@@ -207,61 +206,55 @@ pub trait Context {
     fn get_lines(&self, span: &Span) -> LineInfo;
 
     /// Returns the `kind` of given `DefId`
-    fn def_kind(&mut self, def_id: DefId) -> DefKind;
+    fn def_kind(&self, def_id: DefId) -> DefKind;
 
     /// `Span` of an item
-    fn span_of_an_item(&mut self, def_id: DefId) -> Span;
+    fn span_of_an_item(&self, def_id: DefId) -> Span;
 
     /// Obtain the representation of a type.
-    fn ty_kind(&mut self, ty: Ty) -> TyKind;
-
-    /// Create a new `Ty` from scratch without information from rustc.
-    fn mk_ty(&mut self, kind: TyKind) -> Ty;
+    fn ty_kind(&self, ty: Ty) -> TyKind;
 
     /// Get the body of an Instance.
     /// FIXME: Monomorphize the body.
-    fn instance_body(&mut self, instance: InstanceDef) -> Body;
+    fn instance_body(&self, instance: InstanceDef) -> Body;
 
     /// Get the instance type with generic substitutions applied and lifetimes erased.
-    fn instance_ty(&mut self, instance: InstanceDef) -> Ty;
+    fn instance_ty(&self, instance: InstanceDef) -> Ty;
 
     /// Get the instance.
-    fn instance_def_id(&mut self, instance: InstanceDef) -> DefId;
+    fn instance_def_id(&self, instance: InstanceDef) -> DefId;
 
     /// Convert a non-generic crate item into an instance.
     /// This function will panic if the item is generic.
-    fn mono_instance(&mut self, item: CrateItem) -> Instance;
+    fn mono_instance(&self, item: CrateItem) -> Instance;
 
     /// Item requires monomorphization.
     fn requires_monomorphization(&self, def_id: DefId) -> bool;
 
     /// Resolve an instance from the given function definition and generic arguments.
-    fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
+    fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
 // datastructures and stable MIR datastructures
-scoped_thread_local! (static TLV: Cell<*mut ()>);
+scoped_thread_local! (static TLV: Cell<*const ()>);
 
-pub fn run(mut context: impl Context, f: impl FnOnce()) {
+pub fn run(context: &dyn Context, f: impl FnOnce()) {
     assert!(!TLV.is_set());
-    fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) {
-        let ptr: *mut () = &mut context as *mut &mut _ as _;
-        TLV.set(&Cell::new(ptr), || {
-            f();
-        });
-    }
-    g(&mut context, f);
+    let ptr: *const () = &context as *const &_ as _;
+    TLV.set(&Cell::new(ptr), || {
+        f();
+    });
 }
 
 /// Loads the current context and calls a function with it.
 /// Do not nest these, as that will ICE.
-pub fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R {
+pub fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
     assert!(TLV.is_set());
     TLV.with(|tlv| {
         let ptr = tlv.get();
         assert!(!ptr.is_null());
-        f(unsafe { *(ptr as *mut &mut dyn Context) })
+        f(unsafe { *(ptr as *const &dyn Context) })
     })
 }
 
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 5eee1ec00df..50c37e8f910 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -2,10 +2,60 @@ use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability
 use crate::Opaque;
 use crate::{ty::Ty, Span};
 
+/// The SMIR representation of a single function.
 #[derive(Clone, Debug)]
 pub struct Body {
     pub blocks: Vec<BasicBlock>,
-    pub locals: LocalDecls,
+
+    // Declarations of locals within the function.
+    //
+    // The first local is the return value pointer, followed by `arg_count`
+    // locals for the function arguments, followed by any user-declared
+    // variables and temporaries.
+    locals: LocalDecls,
+
+    // The number of arguments this function takes.
+    arg_count: usize,
+}
+
+impl Body {
+    /// Constructs a `Body`.
+    ///
+    /// A constructor is required to build a `Body` from outside the crate
+    /// because the `arg_count` and `locals` fields are private.
+    pub fn new(blocks: Vec<BasicBlock>, locals: LocalDecls, arg_count: usize) -> Self {
+        // If locals doesn't contain enough entries, it can lead to panics in
+        // `ret_local`, `arg_locals`, and `inner_locals`.
+        assert!(
+            locals.len() > arg_count,
+            "A Body must contain at least a local for the return value and each of the function's arguments"
+        );
+        Self { blocks, locals, arg_count }
+    }
+
+    /// Return local that holds this function's return value.
+    pub fn ret_local(&self) -> &LocalDecl {
+        &self.locals[0]
+    }
+
+    /// Locals in `self` that correspond to this function's arguments.
+    pub fn arg_locals(&self) -> &[LocalDecl] {
+        &self.locals[1..][..self.arg_count]
+    }
+
+    /// Inner locals for this function. These are the locals that are
+    /// neither the return local nor the argument locals.
+    pub fn inner_locals(&self) -> &[LocalDecl] {
+        &self.locals[self.arg_count + 1..]
+    }
+
+    /// Convenience function to get all the locals in this function.
+    ///
+    /// Locals are typically accessed via the more specific methods `ret_local`,
+    /// `arg_locals`, and `inner_locals`.
+    pub fn locals(&self) -> &[LocalDecl] {
+        &self.locals
+    }
 }
 
 type LocalDecls = Vec<LocalDecl>;
@@ -135,12 +185,12 @@ pub enum UnOp {
 
 #[derive(Clone, Debug)]
 pub enum CoroutineKind {
-    Async(AsyncCoroutineKind),
+    Async(CoroutineSource),
     Coroutine,
 }
 
 #[derive(Clone, Debug)]
-pub enum AsyncCoroutineKind {
+pub enum CoroutineSource {
     Block,
     Closure,
     Fn,
@@ -467,7 +517,7 @@ pub enum NullOp {
 }
 
 impl Operand {
-    pub fn ty(&self, locals: &LocalDecls) -> Ty {
+    pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
         match self {
             Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
             Operand::Constant(c) => c.ty(),
@@ -477,12 +527,12 @@ impl Operand {
 
 impl Constant {
     pub fn ty(&self) -> Ty {
-        self.literal.ty
+        self.literal.ty()
     }
 }
 
 impl Place {
-    pub fn ty(&self, locals: &LocalDecls) -> Ty {
+    pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
         let _start_ty = locals[self.local].ty;
         todo!("Implement projection")
     }
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 8f7f8bd4e38..0dbf6fe23aa 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -6,7 +6,7 @@ use super::{
 use crate::{Filename, Opaque};
 use std::fmt::{self, Debug, Formatter};
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
 pub struct Ty(pub usize);
 
 impl Debug for Ty {
@@ -21,18 +21,37 @@ impl Ty {
     }
 }
 
-impl From<TyKind> for Ty {
-    fn from(value: TyKind) -> Self {
-        with(|context| context.mk_ty(value))
+/// Represents a constant in MIR or from the Type system.
+#[derive(Clone, Debug)]
+pub struct Const {
+    /// The constant kind.
+    kind: ConstantKind,
+    /// The constant type.
+    ty: Ty,
+    /// Used for internal tracking of the internal constant.
+    pub id: ConstId,
+}
+
+impl Const {
+    /// Build a constant. Note that this should only be used by the compiler.
+    pub fn new(kind: ConstantKind, ty: Ty, id: ConstId) -> Const {
+        Const { kind, ty, id }
     }
-}
 
-#[derive(Debug, Clone)]
-pub struct Const {
-    pub literal: ConstantKind,
-    pub ty: Ty,
+    /// Retrieve the constant kind.
+    pub fn kind(&self) -> &ConstantKind {
+        &self.kind
+    }
+
+    /// Get the constant type.
+    pub fn ty(&self) -> Ty {
+        self.ty
+    }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct ConstId(pub usize);
+
 type Ident = Opaque;
 
 #[derive(Debug, Clone)]
@@ -108,15 +127,6 @@ pub struct LineInfo {
     pub end_col: usize,
 }
 
-impl IndexedVal for Span {
-    fn to_val(index: usize) -> Self {
-        Span(index)
-    }
-    fn to_index(&self) -> usize {
-        self.0
-    }
-}
-
 #[derive(Clone, Debug)]
 pub enum TyKind {
     RigidTy(RigidTy),
@@ -603,3 +613,20 @@ pub trait IndexedVal {
 
     fn to_index(&self) -> usize;
 }
+
+macro_rules! index_impl {
+    ($name:ident) => {
+        impl IndexedVal for $name {
+            fn to_val(index: usize) -> Self {
+                $name(index)
+            }
+            fn to_index(&self) -> usize {
+                self.0
+            }
+        }
+    };
+}
+
+index_impl!(ConstId);
+index_impl!(Ty);
+index_impl!(Span);
diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs
index a6020cc5bd9..c337f5b68d3 100644
--- a/compiler/stable_mir/src/visitor.rs
+++ b/compiler/stable_mir/src/visitor.rs
@@ -47,12 +47,12 @@ impl Visitable for Const {
         visitor.visit_const(self)
     }
     fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
-        match &self.literal {
+        match &self.kind() {
             super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?,
             super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?,
             super::ty::ConstantKind::Param(_) => {}
         }
-        self.ty.visit(visitor)
+        self.ty().visit(visitor)
     }
 }
 
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index b2c9a0800c9..6908c824f44 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -6,7 +6,7 @@
 //! match those defined by C, so that code that interacts with C will
 //! refer to the correct types.
 
-#![stable(feature = "", since = "1.30.0")]
+#![stable(feature = "core_ffi", since = "1.30.0")]
 #![allow(non_camel_case_types)]
 
 use crate::fmt;
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index c7ace58afa8..166d04e078d 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -69,6 +69,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
     message = "`{Self}` is not an iterator"
 )]
 #[doc(notable_trait)]
+#[cfg_attr(not(bootstrap), lang = "iterator")]
 #[rustc_diagnostic_item = "Iterator"]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub trait Iterator {
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 03243e31348..a1220d45a5c 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -253,6 +253,7 @@
 #![feature(try_blocks)]
 #![feature(unboxed_closures)]
 #![feature(unsized_fn_params)]
+#![feature(with_negative_coherence)]
 // tidy-alphabetical-end
 //
 // Target features:
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 8396aecf947..55116285842 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -1,6 +1,4 @@
-use crate::cmp::Ordering;
 use crate::fmt::{self, Write};
-use crate::hash;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 
 use super::display_buffer::DisplayBuffer;
@@ -63,7 +61,7 @@ pub enum SocketAddr {
 /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
 /// assert_eq!(socket.port(), 8080);
 /// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SocketAddrV4 {
     ip: Ipv4Addr,
@@ -96,7 +94,7 @@ pub struct SocketAddrV4 {
 /// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
 /// assert_eq!(socket.port(), 8080);
 /// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SocketAddrV6 {
     ip: Ipv6Addr,
@@ -644,48 +642,3 @@ impl fmt::Debug for SocketAddrV6 {
         fmt::Display::fmt(self, fmt)
     }
 }
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV4 {
-    #[inline]
-    fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV6 {
-    #[inline]
-    fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV4 {
-    #[inline]
-    fn cmp(&self, other: &SocketAddrV4) -> Ordering {
-        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV6 {
-    #[inline]
-    fn cmp(&self, other: &SocketAddrV6) -> Ordering {
-        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV4 {
-    fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        (self.port, self.ip).hash(s)
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV6 {
-    fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
-    }
-}
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 8b127132c1c..a6c1adfac65 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -114,7 +114,7 @@ macro_rules! midpoint_impl {
                       without modifying the original"]
         #[inline]
         pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
-            // Use the well known branchless algorthim from Hacker's Delight to compute
+            // Use the well known branchless algorithm from Hacker's Delight to compute
             // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`.
             ((self ^ rhs) >> 1) + (self & rhs)
         }
diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs
index e01a893a068..cd5ca988f7e 100644
--- a/library/core/src/ops/coroutine.rs
+++ b/library/core/src/ops/coroutine.rs
@@ -29,7 +29,7 @@ pub enum CoroutineState<Y, R> {
 
 /// The trait implemented by builtin coroutine types.
 ///
-/// Coroutines, also commonly referred to as coroutines, are currently an
+/// Coroutines are currently an
 /// experimental language feature in Rust. Added in [RFC 2033] coroutines are
 /// currently intended to primarily provide a building block for async/await
 /// syntax but will likely extend to also providing an ergonomic definition for
diff --git a/library/core/tests/net/socket_addr.rs b/library/core/tests/net/socket_addr.rs
index 35a69cead48..3d013d37e04 100644
--- a/library/core/tests/net/socket_addr.rs
+++ b/library/core/tests/net/socket_addr.rs
@@ -199,6 +199,9 @@ fn compare() {
     let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
     let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
     let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
+    let v6_4 = "[2001:db8:f00::2001%42]:23456".parse::<SocketAddrV6>().unwrap();
+    let mut v6_5 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
+    v6_5.set_flowinfo(17);
 
     // equality
     assert_eq!(v4_1, v4_1);
@@ -207,6 +210,8 @@ fn compare() {
     assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
     assert!(v4_1 != v4_2);
     assert!(v6_1 != v6_2);
+    assert!(v6_3 != v6_4);
+    assert!(v6_3 != v6_5);
 
     // compare different addresses
     assert!(v4_1 < v4_2);
@@ -226,6 +231,12 @@ fn compare() {
     assert!(v4_3 > v4_1);
     assert!(v6_3 > v6_1);
 
+    // compare the same address with different scope_id
+    assert!(v6_3 < v6_4);
+
+    // compare the same address with different flowinfo
+    assert!(v6_3 < v6_5);
+
     // compare with an inferred right-hand side
     assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
     assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 063464046e0..bca5d859b66 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1140,10 +1140,10 @@ pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
 #[repr(transparent)]
 pub struct IoSliceMut<'a>(sys::io::IoSliceMut<'a>);
 
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
 unsafe impl<'a> Send for IoSliceMut<'a> {}
 
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
 unsafe impl<'a> Sync for IoSliceMut<'a> {}
 
 #[stable(feature = "iovec", since = "1.36.0")]
@@ -1283,10 +1283,10 @@ impl<'a> DerefMut for IoSliceMut<'a> {
 #[repr(transparent)]
 pub struct IoSlice<'a>(sys::io::IoSlice<'a>);
 
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
 unsafe impl<'a> Send for IoSlice<'a> {}
 
-#[stable(feature = "iovec-send-sync", since = "1.44.0")]
+#[stable(feature = "iovec_send_sync", since = "1.44.0")]
 unsafe impl<'a> Sync for IoSlice<'a> {}
 
 #[stable(feature = "iovec", since = "1.36.0")]
diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs
index 73c530786b2..3dbab4cc486 100644
--- a/library/std/src/sys/unix/stack_overflow.rs
+++ b/library/std/src/sys/unix/stack_overflow.rs
@@ -134,9 +134,19 @@ mod imp {
         // OpenBSD requires this flag for stack mapping
         // otherwise the said mapping will fail as a no-op on most systems
         // and has a different meaning on FreeBSD
-        #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",))]
+        #[cfg(any(
+            target_os = "openbsd",
+            target_os = "netbsd",
+            target_os = "linux",
+            target_os = "dragonfly",
+        ))]
         let flags = MAP_PRIVATE | MAP_ANON | libc::MAP_STACK;
-        #[cfg(not(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",)))]
+        #[cfg(not(any(
+            target_os = "openbsd",
+            target_os = "netbsd",
+            target_os = "linux",
+            target_os = "dragonfly",
+        )))]
         let flags = MAP_PRIVATE | MAP_ANON;
         let stackp =
             mmap64(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0);
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 96a0eb75582..19f666d0463 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -50,6 +50,7 @@ dependencies = [
  "fd-lock",
  "filetime",
  "hex",
+ "home",
  "ignore",
  "junction",
  "libc",
@@ -351,6 +352,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
 [[package]]
+name = "home"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
 name = "ignore"
 version = "0.4.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index e236421b7f5..bc025f44484 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -40,6 +40,7 @@ clap_complete = "4.4.3"
 cmake = "0.1.38"
 filetime = "0.2"
 hex = "0.4"
+home = "0.5.4"
 ignore = "0.4.10"
 libc = "0.2"
 object = { version = "0.32.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 7f16cac7890..e6caabec4f6 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -103,7 +103,6 @@ class GenerateAndParseConfig(unittest.TestCase):
     """Test that we can serialize and deserialize a config.toml file"""
     def test_no_args(self):
         build = serialize_and_parse([])
-        self.assertEqual(build.get_toml("change-id"), '116998')
         self.assertEqual(build.get_toml("profile"), 'dist')
         self.assertIsNone(build.get_toml("llvm.download-ci-llvm"))
 
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 241ae16e595..04bf9723edd 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -124,6 +124,13 @@ fn main() {
     if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
         cmd.arg("--remap-path-prefix").arg(&map);
     }
+    // The remap flags for Cargo registry sources need to be passed after the remapping for the
+    // Rust source code directory, to handle cases when $CARGO_HOME is inside the source directory.
+    if let Ok(maps) = env::var("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP") {
+        for map in maps.split('\t') {
+            cmd.arg("--remap-path-prefix").arg(map);
+        }
+    }
 
     // Force all crates compiled by this compiler to (a) be unstable and (b)
     // allow the `rustc_private` feature to link to other unstable crates
diff --git a/src/bootstrap/src/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs
index f5f80ba2a0b..dbbce6fe220 100644
--- a/src/bootstrap/src/bin/rustdoc.rs
+++ b/src/bootstrap/src/bin/rustdoc.rs
@@ -70,7 +70,9 @@ fn main() {
         cmd.arg("--cfg=bootstrap");
     }
     cmd.arg("-Zunstable-options");
+    // #[cfg(bootstrap)]
     cmd.arg("--check-cfg=values(bootstrap)");
+    // cmd.arg("--check-cfg=cfg(bootstrap)");
 
     if verbose > 1 {
         eprintln!(
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 039a87e760d..36653dcfb20 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -2,7 +2,7 @@ use std::any::{type_name, Any};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
 use std::env;
-use std::ffi::OsStr;
+use std::ffi::{OsStr, OsString};
 use std::fmt::{Debug, Write};
 use std::fs::{self, File};
 use std::hash::Hash;
@@ -1401,19 +1401,28 @@ impl<'a> Builder<'a> {
             rustflags.arg("-Zunstable-options");
         }
 
-        // Enable cfg checking of cargo features for everything but std and also enable cfg
-        // checking of names and values.
+        // #[cfg(bootstrap)]
+        let use_new_check_cfg_syntax = self.local_rebuild;
+
+        // Enable compile-time checking of `cfg` names, values and Cargo `features`.
         //
         // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
         // backtrace, core_simd, std_float, ...), those dependencies have their own
         // features but cargo isn't involved in the #[path] process and so cannot pass the
         // complete list of features, so for that reason we don't enable checking of
         // features for std crates.
-        cargo.arg(if mode != Mode::Std {
-            "-Zcheck-cfg=names,values,output,features"
+        if use_new_check_cfg_syntax {
+            cargo.arg("-Zcheck-cfg");
+            if mode == Mode::Std {
+                rustflags.arg("--check-cfg=cfg(feature,values(any()))");
+            }
         } else {
-            "-Zcheck-cfg=names,values,output"
-        });
+            cargo.arg(if mode != Mode::Std {
+                "-Zcheck-cfg=names,values,output,features"
+            } else {
+                "-Zcheck-cfg=names,values,output"
+            });
+        }
 
         // Add extra cfg not defined in/by rustc
         //
@@ -1433,7 +1442,12 @@ impl<'a> Builder<'a> {
                         .collect::<String>(),
                     None => String::new(),
                 };
-                rustflags.arg(&format!("--check-cfg=values({name}{values})"));
+                if use_new_check_cfg_syntax {
+                    let values = values.strip_prefix(",").unwrap_or(&values); // remove the first `,`
+                    rustflags.arg(&format!("--check-cfg=cfg({name},values({values}))"));
+                } else {
+                    rustflags.arg(&format!("--check-cfg=values({name}{values})"));
+                }
             }
         }
 
@@ -1449,7 +1463,11 @@ impl<'a> Builder<'a> {
         // We also declare that the flag is expected, which we need to do to not
         // get warnings about it being unexpected.
         hostflags.arg("-Zunstable-options");
-        hostflags.arg("--check-cfg=values(bootstrap)");
+        if use_new_check_cfg_syntax {
+            hostflags.arg("--check-cfg=cfg(bootstrap)");
+        } else {
+            hostflags.arg("--check-cfg=values(bootstrap)");
+        }
 
         // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
         // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
@@ -1767,6 +1785,20 @@ impl<'a> Builder<'a> {
             cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to);
         }
 
+        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());
+                env_var.push("=/rust/deps");
+            }
+            cargo.env("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP", env_var);
+        }
+
         // Enable usage of unstable features
         cargo.env("RUSTC_BOOTSTRAP", "1");
         self.add_rust_test_threads(&mut cargo);
diff --git a/src/doc/book b/src/doc/book
-Subproject 72187f5cd0beaaa9c6f584156bcd88f921871e8
+Subproject 3dca2fc50b922a8efb94903b9fee8bb42ab48f3
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject eac173690b8cc99094e1d88bd49dd61127fbd28
+Subproject 22bca3d0f6e9b9b556689b54ce96f25b46ecd1b
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject ddfa4214487686e91b21aa29afb972c08a8f0d5
+Subproject 1842257814919fa62e81bdecd5e8f95be2839db
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 142b2ed77d33f37a9973772bd95e6144ed9dce4
+Subproject 16fd3c06d9e558dae2d52000818274ae70c9e90
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 8eb3a01ab74c567b7174784892fb807f2c632d6
+Subproject 6709beeb7d0fbc5ffc91ac4893a24434123b9bf
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject b98af7d661e4744baab81fb8dc7a049e44a4a99
+Subproject b0ee9ec8fa59a6c7620165e061f4747202377a6
diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
index 57c717c182d..a54abcb606e 100644
--- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
+++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
@@ -10,9 +10,15 @@ target | std | host | notes
 `csky-unknown-linux-gnuabiv2hf` | ✓ |  | C-SKY abiv2 Linux, hardfloat (little endian)
 
 Reference:
-https://c-sky.github.io/
 
-https://gitlab.com/c-sky/
+- [CSKY ABI Manual](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1695027452256/T-HEAD_800_Series_ABI_Standards_Manual.pdf)
+- [csky-linux-gnuabiv2-toolchain](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource/1356021/1619528643136/csky-linux-gnuabiv2-tools-x86_64-glibc-linux-4.9.56-20210423.tar.gz)
+- [csky-linux-gnuabiv2-qemu](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1689324918932/xuantie-qemu-x86_64-Ubuntu-18.04-20230714-0202.tar.gz)
+
+other links:
+
+- https://c-sky.github.io/
+- https://gitlab.com/c-sky/
 
 ## Target maintainers
 
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 ca18ec567a4..7a3ef5e9e2b 100644
--- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md
@@ -123,7 +123,7 @@ rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \
 fn do_embedded() {}         // and because names exhaustiveness was not disabled
 
 #[cfg(has_feathers)]        // This is expected as "has_feathers" was provided in cfg()
-fn do_features() {}         // and because names exhaustiveness was not disbaled
+fn do_features() {}         // and because names exhaustiveness was not disabled
 
 #[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg()
                                  // and because no value checking was enable for "has_feathers"
diff --git a/src/doc/unstable-book/src/language-features/coroutines.md b/src/doc/unstable-book/src/language-features/coroutines.md
index fb1ba791aef..f8e5a22fbd5 100644
--- a/src/doc/unstable-book/src/language-features/coroutines.md
+++ b/src/doc/unstable-book/src/language-features/coroutines.md
@@ -18,7 +18,7 @@ Coroutines are an extra-unstable feature in the compiler right now. Added in
 [RFC 2033] they're mostly intended right now as a information/constraint
 gathering phase. The intent is that experimentation can happen on the nightly
 compiler before actual stabilization. A further RFC will be required to
-stabilize coroutines/coroutines and will likely contain at least a few small
+stabilize coroutines and will likely contain at least a few small
 tweaks to the overall design.
 
 [RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6a7410144fd..449aac4cfc8 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -12,7 +12,7 @@ use thin_vec::ThinVec;
 
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
-use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
+use rustc_attr::{ConstStability, Deprecation, Since, Stability, StabilityLevel};
 use rustc_const_eval::const_eval::is_unstable_const_fn;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -585,14 +585,14 @@ impl Item {
         })
     }
 
-    pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
+    pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Since> {
         match self.stability(tcx)?.level {
             StabilityLevel::Stable { since, .. } => Some(since),
             StabilityLevel::Unstable { .. } => None,
         }
     }
 
-    pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
+    pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Since> {
         match self.const_stability(tcx)?.level {
             StabilityLevel::Stable { since, .. } => Some(since),
             StabilityLevel::Unstable { .. } => None,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 9066061f1a2..94e557dcfdb 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -23,6 +23,7 @@ use std::cell::RefCell;
 use std::mem;
 use std::rc::Rc;
 use std::sync::LazyLock;
+use std::sync::{atomic::AtomicBool, Arc};
 
 use crate::clean::inline::build_external_trait;
 use crate::clean::{self, ItemId};
@@ -198,6 +199,7 @@ pub(crate) fn create_config(
         ..
     }: RustdocOptions,
     RenderOptions { document_private, .. }: &RenderOptions,
+    using_internal_features: Arc<AtomicBool>,
 ) -> rustc_interface::Config {
     // Add the doc cfg into the doc build.
     cfgs.push("doc".to_string());
@@ -293,6 +295,7 @@ pub(crate) fn create_config(
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
+        using_internal_features,
         expanded_args,
     }
 }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index db69cf5752d..97913345e8f 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -110,6 +110,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
         ice_file: None,
+        using_internal_features: Arc::default(),
         expanded_args: options.expanded_args.clone(),
     };
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 89e29d8b59b..e01341acf43 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -48,7 +48,7 @@ use std::str;
 use std::string::ToString;
 
 use askama::Template;
-use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
+use rustc_attr::{ConstStability, Deprecation, Since, StabilityLevel, CURRENT_RUSTC_VERSION};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{DefId, DefIdSet};
@@ -911,13 +911,17 @@ fn assoc_method(
 /// consequence of the above rules.
 fn render_stability_since_raw_with_extra(
     w: &mut Buffer,
-    ver: Option<Symbol>,
+    ver: Option<Since>,
     const_stability: Option<ConstStability>,
-    containing_ver: Option<Symbol>,
-    containing_const_ver: Option<Symbol>,
+    containing_ver: Option<Since>,
+    containing_const_ver: Option<Since>,
     extra_class: &str,
 ) -> bool {
-    let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver);
+    let stable_version = if ver != containing_ver && let Some(ver) = &ver {
+        since_to_string(ver)
+    } else {
+        None
+    };
 
     let mut title = String::new();
     let mut stability = String::new();
@@ -931,7 +935,8 @@ fn render_stability_since_raw_with_extra(
         Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
             if Some(since) != containing_const_ver =>
         {
-            Some((format!("const since {since}"), format!("const: {since}")))
+            since_to_string(&since)
+                .map(|since| (format!("const since {since}"), format!("const: {since}")))
         }
         Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
             let unstable = if let Some(n) = issue {
@@ -971,13 +976,21 @@ fn render_stability_since_raw_with_extra(
     !stability.is_empty()
 }
 
+fn since_to_string(since: &Since) -> Option<String> {
+    match since {
+        Since::Version(since) => Some(since.to_string()),
+        Since::Current => Some(CURRENT_RUSTC_VERSION.to_owned()),
+        Since::Err => None,
+    }
+}
+
 #[inline]
 fn render_stability_since_raw(
     w: &mut Buffer,
-    ver: Option<Symbol>,
+    ver: Option<Since>,
     const_stability: Option<ConstStability>,
-    containing_ver: Option<Symbol>,
-    containing_const_ver: Option<Symbol>,
+    containing_ver: Option<Since>,
+    containing_const_ver: Option<Since>,
 ) -> bool {
     render_stability_since_raw_with_extra(
         w,
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 67f5ea5d98b..41aee06c8d2 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -74,6 +74,7 @@ extern crate jemalloc_sys;
 use std::env::{self, VarError};
 use std::io::{self, IsTerminal};
 use std::process;
+use std::sync::{atomic::AtomicBool, Arc};
 
 use rustc_driver::abort_on_err;
 use rustc_errors::ErrorGuaranteed;
@@ -157,7 +158,7 @@ pub fn main() {
 
     let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
 
-    rustc_driver::install_ice_hook(
+    let using_internal_features = rustc_driver::install_ice_hook(
         "https://github.com/rust-lang/rust/issues/new\
     ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
         |_| (),
@@ -177,7 +178,7 @@ pub fn main() {
     rustc_driver::init_env_logger(&handler, "RUSTDOC_LOG");
 
     let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&handler) {
-        Some(args) => main_args(&mut handler, &args),
+        Some(args) => main_args(&mut handler, &args, using_internal_features),
         _ =>
         {
             #[allow(deprecated)]
@@ -701,7 +702,11 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     }
 }
 
-fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult {
+fn main_args(
+    handler: &mut EarlyErrorHandler,
+    at_args: &[String],
+    using_internal_features: Arc<AtomicBool>,
+) -> MainResult {
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
     // passing empty argument array to execve under some platforms,
@@ -752,7 +757,8 @@ fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult
         (false, true) => {
             let input = options.input.clone();
             let edition = options.edition;
-            let config = core::create_config(handler, options, &render_options);
+            let config =
+                core::create_config(handler, options, &render_options, using_internal_features);
 
             // `markdown::render` can invoke `doctest::make_test`, which
             // requires session globals and a thread pool, so we use
@@ -785,7 +791,7 @@ fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult
     let scrape_examples_options = options.scrape_examples_options.clone();
     let bin_crate = options.bin_crate;
 
-    let config = core::create_config(handler, options, &render_options);
+    let config = core::create_config(handler, options, &render_options, using_internal_features);
 
     interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject d2f6a048529eb8e9ebc55d793abd63456c98fac
+Subproject df3509237935f9418351b77803df7bc05c009b3
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 56f56fff1e7..050df68a0fa 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
-use rustc_hir::{AsyncCoroutineKind, Body, BodyId, CoroutineKind, ExprKind, QPath};
+use rustc_hir::{CoroutineSource, Body, BodyId, CoroutineKind, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -45,7 +45,7 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
 
 impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
-        use AsyncCoroutineKind::{Block, Closure};
+        use CoroutineSource::{Block, Closure};
         // For functions, with explicitly defined types, don't warn.
         // XXXkhuey maybe we should?
         if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind {
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index ae8618dcaa0..0c356934992 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{match_def_path, paths};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{AsyncCoroutineKind, Body, CoroutineKind};
+use rustc_hir::{CoroutineSource, Body, CoroutineKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::CoroutineLayout;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -195,7 +195,7 @@ impl LateLintPass<'_> for AwaitHolding {
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
-        use AsyncCoroutineKind::{Block, Closure, Fn};
+        use CoroutineSource::{Block, Closure, Fn};
         if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind {
             let def_id = cx.tcx.hir().body_owner_def_id(body.id());
             if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 5a87e75722d..a75c76d6fe0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,7 +4,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AsyncCoroutineKind, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
+    CoroutineSource, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
     ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
             ..
         } = block_expr;
         let closure_body = cx.tcx.hir().body(body);
-        if closure_body.coroutine_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block));
+        if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block));
         then {
             return Some(closure_body);
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index ed279a3813d..b3a2060d6ac 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{AsyncCoroutineKind, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath};
+use rustc_hir::{CoroutineSource, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
-        if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.coroutine_kind {
+        if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind {
             if let ExprKind::Block(
                 Block {
                     expr:
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index 2e895d5f236..bf9bdacba5b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -5,7 +5,7 @@ use clippy_utils::peel_blocks;
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::visitors::for_each_expr;
 use rustc_errors::Applicability;
-use rustc_hir::{AsyncCoroutineKind, Closure, CoroutineKind, Expr, ExprKind, MatchSource};
+use rustc_hir::{CoroutineSource, Closure, CoroutineKind, Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
@@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
 fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind &&
         let body = cx.tcx.hir().body(*body) &&
-        matches!(body.coroutine_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block)))
+        matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block)))
     {
         cx
             .typeck_results()
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index f6096ea546d..1e465ac91b7 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -5,6 +5,7 @@
 
 use crate::msrvs::Msrv;
 use hir::LangItem;
+use rustc_attr::{Since, CURRENT_RUSTC_VERSION};
 use rustc_const_eval::transform::check_consts::ConstCx;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -370,19 +371,24 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
                 // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
                 // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
 
-                // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. `rustc-semver`
-                // doesn't accept the `-dev` version number so we have to strip it off.
-                let short_version = since
-                    .as_str()
-                    .split('-')
-                    .next()
-                    .expect("rustc_attr::StabilityLevel::Stable::since` is empty");
+                let const_stab_rust_version = match since {
+                    Since::Version(version) => RustcVersion::new(
+                        u32::from(version.major),
+                        u32::from(version.minor),
+                        u32::from(version.patch),
+                    ),
+                    Since::Current => {
+                        // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev.
+                        // `rustc-semver` doesn't accept the `-dev` version number so we have to strip it off.
+                        let short_version = CURRENT_RUSTC_VERSION.split('-').next().unwrap();
+                        RustcVersion::parse(short_version).unwrap_or_else(|err| {
+                            panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{CURRENT_RUSTC_VERSION}`, {err:?}")
+                        })
+                    },
+                    Since::Err => return false,
+                };
 
-                let since = rustc_span::Symbol::intern(short_version);
-
-                msrv.meets(RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
-                    panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
-                }))
+                msrv.meets(const_stab_rust_version)
             } else {
                 // Unstable const fn with the feature enabled.
                 msrv.current().is_none()
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 0e81419f1fa..11290f88a49 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -178,7 +178,7 @@ pub fn main() {
 
     rustc_driver::init_rustc_env_logger(&handler);
 
-    rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
+    let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
         // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
         // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't
         // accept a generic closure.
@@ -265,9 +265,11 @@ pub fn main() {
         let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
         if clippy_enabled {
             args.extend(clippy_args);
-            rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }).run()
+            rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })
+                .set_using_internal_features(using_internal_features).run()
         } else {
-            rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }).run()
+            rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var })
+                .set_using_internal_features(using_internal_features).run()
         }
     }))
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index 30be9dde73c..f929bec9583 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -24,6 +24,16 @@ help: you might be missing a type parameter
 LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          +++++
 
-error: aborting due to 2 previous errors
+error[E0046]: not all trait items implemented, missing: `VAL`
+  --> $DIR/ice-6252.rs:11:1
+   |
+LL |     const VAL: T;
+   |     ------------ `VAL` from trait
+...
+LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0412`.
+Some errors have detailed explanations: E0046, E0412.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
index 7b9dc76b8f1..775e071147c 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
@@ -1,8 +1,8 @@
 // This file provides a const function that is unstably const forever.
 
 #![feature(staged_api)]
-#![stable(feature = "1", since = "1.0.0")]
+#![stable(feature = "clippytest", since = "1.0.0")]
 
-#[stable(feature = "1", since = "1.0.0")]
+#[stable(feature = "clippytest", since = "1.0.0")]
 #[rustc_const_unstable(feature = "foo", issue = "none")]
 pub const fn unstably_const_fn() {}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index ac270a1f0ba..87d0404e7d8 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3999,10 +3999,10 @@ impl<'test> TestCx<'test> {
         let passes = std::mem::take(&mut test_info.passes);
 
         let proc_res = self.compile_test_with_passes(should_run, Emit::Mir, passes);
-        self.check_mir_dump(test_info);
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
+        self.check_mir_dump(test_info);
 
         if let WillExecute::Yes = should_run {
             let proc_res = self.exec_compiled_test();
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index eda1ceb4084..5078e9eaab3 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -108,7 +108,7 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
     MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
-    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
+    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic env/var
     MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
     MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
     MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 0335ad3c1d8..60ae5d12598 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-9e3f784eb2c7c847b6c3578b373c0e0bc9233ca3
+2e4e2a8f288f642cafcc41fff211955ceddc453d
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index fc6151772a0..531128ed2ec 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -241,6 +241,7 @@ fn run_compiler(
     mut args: Vec<String>,
     target_crate: bool,
     callbacks: &mut (dyn rustc_driver::Callbacks + Send),
+    using_internal_features: std::sync::Arc<std::sync::atomic::AtomicBool>
 ) -> ! {
     if target_crate {
         // Miri needs a custom sysroot for target crates.
@@ -273,7 +274,8 @@ fn run_compiler(
 
     // Invoke compiler, and handle return code.
     let exit_code = rustc_driver::catch_with_exit_code(move || {
-        rustc_driver::RunCompiler::new(&args, callbacks).run()
+        rustc_driver::RunCompiler::new(&args, callbacks)
+            .set_using_internal_features(using_internal_features).run()
     });
     std::process::exit(exit_code)
 }
@@ -295,7 +297,7 @@ fn main() {
     // If the environment asks us to actually be rustc, then do that.
     if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
         // Earliest rustc setup.
-        rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
+        let using_internal_features = rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
         rustc_driver::init_rustc_env_logger(&handler);
 
         let target_crate = if crate_kind == "target" {
@@ -311,11 +313,12 @@ fn main() {
             env::args().collect(),
             target_crate,
             &mut MiriBeRustCompilerCalls { target_crate },
+            using_internal_features,
         )
     }
 
     // Add an ICE bug report hook.
-    rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
+    let using_internal_features = rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
 
     // Init loggers the Miri way.
     init_early_loggers(&handler);
@@ -578,5 +581,5 @@ fn main() {
 
     debug!("rustc arguments: {:?}", rustc_args);
     debug!("crate arguments: {:?}", miri_config.args);
-    run_compiler(rustc_args, /* target_crate: */ true, &mut MiriCompilerCalls { miri_config })
+    run_compiler(rustc_args, /* target_crate: */ true, &mut MiriCompilerCalls { miri_config }, using_internal_features)
 }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
index b63b0bdff12..4232cd396c9 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -661,13 +661,11 @@ impl<'tcx> Tree {
             for (perms_range, perms) in self.rperms.iter_mut_all() {
                 let idx = self.tag_mapping.get(&tag).unwrap();
                 // Only visit initialized permissions
-                if let Some(p) = perms.get(idx) && p.initialized {
-                    TreeVisitor {
-                        nodes: &mut self.nodes,
-                        tag_mapping: &self.tag_mapping,
-                        perms,
-                    }
-                    .traverse_nonchildren(
+                if let Some(p) = perms.get(idx)
+                    && p.initialized
+                {
+                    TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
+                        .traverse_nonchildren(
                         tag,
                         |args| node_app(perms_range.clone(), args),
                         |args| err_handler(perms_range.clone(), args),
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index bec2972c50d..4cab86af886 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -41,6 +41,7 @@
 //! on the data-race detection code.
 
 use std::{
+    borrow::Cow,
     cell::{Cell, Ref, RefCell, RefMut},
     fmt::Debug,
     mem,
@@ -167,7 +168,7 @@ pub struct DataRace;
 /// explicitly to reduce memory usage for the
 /// common case where no atomic operations
 /// exists on the memory cell.
-#[derive(Clone, PartialEq, Eq, Default, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug)]
 struct AtomicMemoryCellClocks {
     /// The clock-vector of the timestamp of the last atomic
     /// read operation performed by each thread.
@@ -186,6 +187,11 @@ struct AtomicMemoryCellClocks {
     /// happen-before a thread if an acquire-load is
     /// performed on the data.
     sync_vector: VClock,
+
+    /// The size of accesses to this atomic location.
+    /// We use this to detect non-synchronized mixed-size accesses. Since all accesses must be
+    /// aligned to their size, this is sufficient to detect imperfectly overlapping accesses.
+    size: Size,
 }
 
 /// Type of write operation: allocating memory
@@ -220,54 +226,101 @@ impl WriteType {
 /// for data-race detection.
 #[derive(Clone, PartialEq, Eq, Debug)]
 struct MemoryCellClocks {
-    /// The vector-clock timestamp of the last write
-    /// corresponding to the writing threads timestamp.
-    write: VTimestamp,
-
-    /// The identifier of the vector index, corresponding to a thread
-    /// that performed the last write operation.
-    write_index: VectorIdx,
+    /// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need
+    /// a full `VClock` here, it's always a single thread and nothing synchronizes, so the effective
+    /// clock is all-0 except for the thread that did the write.
+    write: (VectorIdx, VTimestamp),
 
     /// The type of operation that the write index represents,
     /// either newly allocated memory, a non-atomic write or
     /// a deallocation of memory.
     write_type: WriteType,
 
-    /// The vector-clock of the timestamp of the last read operation
-    /// performed by a thread since the last write operation occurred.
-    /// It is reset to zero on each write operation.
+    /// The vector-clock of all non-atomic reads that happened since the last non-atomic write
+    /// (i.e., we join together the "singleton" clocks corresponding to each read). It is reset to
+    /// zero on each write operation.
     read: VClock,
 
-    /// Atomic acquire & release sequence tracking clocks.
+    /// Atomic access, acquire, release sequence tracking clocks.
     /// For non-atomic memory in the common case this
     /// value is set to None.
     atomic_ops: Option<Box<AtomicMemoryCellClocks>>,
 }
 
+impl AtomicMemoryCellClocks {
+    fn new(size: Size) -> Self {
+        AtomicMemoryCellClocks {
+            read_vector: Default::default(),
+            write_vector: Default::default(),
+            sync_vector: Default::default(),
+            size,
+        }
+    }
+}
+
 impl MemoryCellClocks {
     /// Create a new set of clocks representing memory allocated
     ///  at a given vector timestamp and index.
     fn new(alloc: VTimestamp, alloc_index: VectorIdx) -> Self {
         MemoryCellClocks {
             read: VClock::default(),
-            write: alloc,
-            write_index: alloc_index,
+            write: (alloc_index, alloc),
             write_type: WriteType::Allocate,
             atomic_ops: None,
         }
     }
 
+    #[inline]
+    fn write_was_before(&self, other: &VClock) -> bool {
+        // This is the same as `self.write() <= other` but
+        // without actually manifesting a clock for `self.write`.
+        self.write.1 <= other[self.write.0]
+    }
+
+    #[inline]
+    fn write(&self) -> VClock {
+        VClock::new_with_index(self.write.0, self.write.1)
+    }
+
     /// Load the internal atomic memory cells if they exist.
     #[inline]
     fn atomic(&self) -> Option<&AtomicMemoryCellClocks> {
         self.atomic_ops.as_deref()
     }
 
-    /// Load or create the internal atomic memory metadata
-    /// if it does not exist.
+    /// Load the internal atomic memory cells if they exist.
     #[inline]
-    fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks {
-        self.atomic_ops.get_or_insert_with(Default::default)
+    fn atomic_mut_unwrap(&mut self) -> &mut AtomicMemoryCellClocks {
+        self.atomic_ops.as_deref_mut().unwrap()
+    }
+
+    /// Load or create the internal atomic memory metadata if it does not exist. Also ensures we do
+    /// not do mixed-size atomic accesses, and updates the recorded atomic access size.
+    fn atomic_access(
+        &mut self,
+        thread_clocks: &ThreadClockSet,
+        size: Size,
+    ) -> Result<&mut AtomicMemoryCellClocks, DataRace> {
+        match self.atomic_ops {
+            Some(ref mut atomic) => {
+                // We are good if the size is the same or all atomic accesses are before our current time.
+                if atomic.size == size {
+                    Ok(atomic)
+                } else if atomic.read_vector <= thread_clocks.clock
+                    && atomic.write_vector <= thread_clocks.clock
+                {
+                    // This is now the new size that must be used for accesses here.
+                    atomic.size = size;
+                    Ok(atomic)
+                } else {
+                    Err(DataRace)
+                }
+            }
+            None => {
+                self.atomic_ops = Some(Box::new(AtomicMemoryCellClocks::new(size)));
+                Ok(self.atomic_ops.as_mut().unwrap())
+            }
+        }
     }
 
     /// Update memory cell data-race tracking for atomic
@@ -277,23 +330,15 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &mut ThreadClockSet,
         index: VectorIdx,
+        access_size: Size,
     ) -> Result<(), DataRace> {
-        self.atomic_read_detect(thread_clocks, index)?;
+        self.atomic_read_detect(thread_clocks, index, access_size)?;
         if let Some(atomic) = self.atomic() {
             thread_clocks.clock.join(&atomic.sync_vector);
         }
         Ok(())
     }
 
-    /// Checks if the memory cell access is ordered with all prior atomic reads and writes
-    fn race_free_with_atomic(&self, thread_clocks: &ThreadClockSet) -> bool {
-        if let Some(atomic) = self.atomic() {
-            atomic.read_vector <= thread_clocks.clock && atomic.write_vector <= thread_clocks.clock
-        } else {
-            true
-        }
-    }
-
     /// Update memory cell data-race tracking for atomic
     /// load relaxed semantics, is a no-op if this memory was
     /// not used previously as atomic memory.
@@ -301,8 +346,9 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &mut ThreadClockSet,
         index: VectorIdx,
+        access_size: Size,
     ) -> Result<(), DataRace> {
-        self.atomic_read_detect(thread_clocks, index)?;
+        self.atomic_read_detect(thread_clocks, index, access_size)?;
         if let Some(atomic) = self.atomic() {
             thread_clocks.fence_acquire.join(&atomic.sync_vector);
         }
@@ -315,9 +361,10 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &ThreadClockSet,
         index: VectorIdx,
+        access_size: Size,
     ) -> Result<(), DataRace> {
-        self.atomic_write_detect(thread_clocks, index)?;
-        let atomic = self.atomic_mut();
+        self.atomic_write_detect(thread_clocks, index, access_size)?;
+        let atomic = self.atomic_mut_unwrap(); // initialized by `atomic_write_detect`
         atomic.sync_vector.clone_from(&thread_clocks.clock);
         Ok(())
     }
@@ -328,14 +375,15 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &ThreadClockSet,
         index: VectorIdx,
+        access_size: Size,
     ) -> Result<(), DataRace> {
-        self.atomic_write_detect(thread_clocks, index)?;
+        self.atomic_write_detect(thread_clocks, index, access_size)?;
 
         // The handling of release sequences was changed in C++20 and so
         // the code here is different to the paper since now all relaxed
         // stores block release sequences. The exception for same-thread
         // relaxed stores has been removed.
-        let atomic = self.atomic_mut();
+        let atomic = self.atomic_mut_unwrap();
         atomic.sync_vector.clone_from(&thread_clocks.fence_release);
         Ok(())
     }
@@ -346,9 +394,10 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &ThreadClockSet,
         index: VectorIdx,
+        access_size: Size,
     ) -> Result<(), DataRace> {
-        self.atomic_write_detect(thread_clocks, index)?;
-        let atomic = self.atomic_mut();
+        self.atomic_write_detect(thread_clocks, index, access_size)?;
+        let atomic = self.atomic_mut_unwrap();
         atomic.sync_vector.join(&thread_clocks.clock);
         Ok(())
     }
@@ -359,24 +408,31 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &ThreadClockSet,
         index: VectorIdx,
+        access_size: Size,
     ) -> Result<(), DataRace> {
-        self.atomic_write_detect(thread_clocks, index)?;
-        let atomic = self.atomic_mut();
+        self.atomic_write_detect(thread_clocks, index, access_size)?;
+        let atomic = self.atomic_mut_unwrap();
         atomic.sync_vector.join(&thread_clocks.fence_release);
         Ok(())
     }
 
-    /// Detect data-races with an atomic read, caused by a non-atomic write that does
+    /// Detect data-races with an atomic read, caused by a non-atomic access that does
     /// not happen-before the atomic-read.
     fn atomic_read_detect(
         &mut self,
         thread_clocks: &ThreadClockSet,
         index: VectorIdx,
+        access_size: Size,
     ) -> Result<(), DataRace> {
         log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, thread_clocks);
-        let atomic = self.atomic_mut();
+        let atomic = self.atomic_access(thread_clocks, access_size)?;
         atomic.read_vector.set_at_index(&thread_clocks.clock, index);
-        if self.write <= thread_clocks.clock[self.write_index] { Ok(()) } else { Err(DataRace) }
+        // Make sure the last non-atomic write and all non-atomic reads were before this access.
+        if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock {
+            Ok(())
+        } else {
+            Err(DataRace)
+        }
     }
 
     /// Detect data-races with an atomic write, either with a non-atomic read or with
@@ -385,11 +441,13 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &ThreadClockSet,
         index: VectorIdx,
+        access_size: Size,
     ) -> Result<(), DataRace> {
         log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, thread_clocks);
-        let atomic = self.atomic_mut();
+        let atomic = self.atomic_access(thread_clocks, access_size)?;
         atomic.write_vector.set_at_index(&thread_clocks.clock, index);
-        if self.write <= thread_clocks.clock[self.write_index] && self.read <= thread_clocks.clock {
+        // Make sure the last non-atomic write and all non-atomic reads were before this access.
+        if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock {
             Ok(())
         } else {
             Err(DataRace)
@@ -408,9 +466,12 @@ impl MemoryCellClocks {
         if !current_span.is_dummy() {
             thread_clocks.clock[index].span = current_span;
         }
-        if self.write <= thread_clocks.clock[self.write_index] {
+        if self.write_was_before(&thread_clocks.clock) {
             let race_free = if let Some(atomic) = self.atomic() {
+                // We must be ordered-after all atomic accesses, reads and writes.
+                // This ensures we don't mix atomic and non-atomic accesses.
                 atomic.write_vector <= thread_clocks.clock
+                    && atomic.read_vector <= thread_clocks.clock
             } else {
                 true
             };
@@ -434,15 +495,14 @@ impl MemoryCellClocks {
         if !current_span.is_dummy() {
             thread_clocks.clock[index].span = current_span;
         }
-        if self.write <= thread_clocks.clock[self.write_index] && self.read <= thread_clocks.clock {
+        if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock {
             let race_free = if let Some(atomic) = self.atomic() {
                 atomic.write_vector <= thread_clocks.clock
                     && atomic.read_vector <= thread_clocks.clock
             } else {
                 true
             };
-            self.write = thread_clocks.clock[index];
-            self.write_index = index;
+            self.write = (index, thread_clocks.clock[index]);
             self.write_type = write_type;
             if race_free {
                 self.read.set_zero_vector();
@@ -473,7 +533,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         // the *value* (including the associated provenance if this is an AtomicPtr) at this location.
         // Only metadata on the location itself is used.
         let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place))?;
-        this.validate_overlapping_atomic(place)?;
         this.buffered_atomic_read(place, atomic, scalar, || {
             this.validate_atomic_load(place, atomic)
         })
@@ -489,7 +548,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         this.atomic_access_check(dest)?;
 
-        this.validate_overlapping_atomic(dest)?;
         this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?;
         this.validate_atomic_store(dest, atomic)?;
         // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause
@@ -512,7 +570,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         this.atomic_access_check(place)?;
 
-        this.validate_overlapping_atomic(place)?;
         let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
 
         // Atomics wrap around on overflow.
@@ -537,7 +594,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         this.atomic_access_check(place)?;
 
-        this.validate_overlapping_atomic(place)?;
         let old = this.allow_data_races_mut(|this| this.read_scalar(place))?;
         this.allow_data_races_mut(|this| this.write_scalar(new, place))?;
 
@@ -559,10 +615,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         this.atomic_access_check(place)?;
 
-        this.validate_overlapping_atomic(place)?;
         let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
         let lt = this.wrapping_binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?;
 
+        #[rustfmt::skip] // rustfmt makes this unreadable
         let new_val = if min {
             if lt { &old } else { &rhs }
         } else {
@@ -598,7 +654,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         this.atomic_access_check(place)?;
 
-        this.validate_overlapping_atomic(place)?;
         // Failure ordering cannot be stronger than success ordering, therefore first attempt
         // to read with the failure ordering and if successful then try again with the success
         // read ordering and write in the success case.
@@ -785,41 +840,54 @@ impl VClockAlloc {
         mem_clocks: &MemoryCellClocks,
         action: &str,
         is_atomic: bool,
+        access_size: Size,
         ptr_dbg: Pointer<AllocId>,
     ) -> InterpResult<'tcx> {
         let (current_index, current_clocks) = global.current_thread_state(thread_mgr);
+        let mut action = Cow::Borrowed(action);
+        let mut involves_non_atomic = true;
         let write_clock;
-        let (other_action, other_thread, other_clock) = if mem_clocks.write
-            > current_clocks.clock[mem_clocks.write_index]
-        {
-            // Convert the write action into the vector clock it
-            // represents for diagnostic purposes.
-            write_clock = VClock::new_with_index(mem_clocks.write_index, mem_clocks.write);
-            (mem_clocks.write_type.get_descriptor(), mem_clocks.write_index, &write_clock)
-        } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &current_clocks.clock) {
-            ("Read", idx, &mem_clocks.read)
-        } else if !is_atomic {
-            if let Some(atomic) = mem_clocks.atomic() {
+        let (other_action, other_thread, other_clock) =
+            // First check the atomic-nonatomic cases. If it looks like multiple
+            // cases apply, this one should take precedence, else it might look like
+            // we are reporting races between two non-atomic reads.
+            if !is_atomic &&
+                let Some(atomic) = mem_clocks.atomic() &&
+                let Some(idx) = Self::find_gt_index(&atomic.write_vector, &current_clocks.clock)
+            {
+                (format!("Atomic Store"), idx, &atomic.write_vector)
+            } else if !is_atomic &&
+                let Some(atomic) = mem_clocks.atomic() &&
+                let Some(idx) = Self::find_gt_index(&atomic.read_vector, &current_clocks.clock)
+            {
+                (format!("Atomic Load"), idx, &atomic.read_vector)
+            // Then check races with non-atomic writes/reads.
+            } else if mem_clocks.write.1 > current_clocks.clock[mem_clocks.write.0] {
+                write_clock = mem_clocks.write();
+                (mem_clocks.write_type.get_descriptor().to_owned(), mem_clocks.write.0, &write_clock)
+            } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &current_clocks.clock) {
+                (format!("Read"), idx, &mem_clocks.read)
+            // Finally, mixed-size races.
+            } else if is_atomic && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size {
+                // This is only a race if we are not synchronized with all atomic accesses, so find
+                // the one we are not synchronized with.
+                involves_non_atomic = false;
+                action = format!("{}-byte (different-size) {action}", access_size.bytes()).into();
                 if let Some(idx) = Self::find_gt_index(&atomic.write_vector, &current_clocks.clock)
-                {
-                    ("Atomic Store", idx, &atomic.write_vector)
-                } else if let Some(idx) =
-                    Self::find_gt_index(&atomic.read_vector, &current_clocks.clock)
-                {
-                    ("Atomic Load", idx, &atomic.read_vector)
-                } else {
-                    unreachable!(
-                        "Failed to report data-race for non-atomic operation: no race found"
-                    )
-                }
+                    {
+                        (format!("{}-byte Atomic Store", atomic.size.bytes()), idx, &atomic.write_vector)
+                    } else if let Some(idx) =
+                        Self::find_gt_index(&atomic.read_vector, &current_clocks.clock)
+                    {
+                        (format!("{}-byte Atomic Load", atomic.size.bytes()), idx, &atomic.read_vector)
+                    } else {
+                        unreachable!(
+                            "Failed to report data-race for mixed-size access: no race found"
+                        )
+                    }
             } else {
-                unreachable!(
-                    "Failed to report data-race for non-atomic operation: no atomic component"
-                )
-            }
-        } else {
-            unreachable!("Failed to report data-race for atomic operation")
-        };
+                unreachable!("Failed to report data-race")
+            };
 
         // Load elaborated thread information about the racing thread actions.
         let current_thread_info = global.print_thread_metadata(thread_mgr, current_index);
@@ -827,6 +895,7 @@ impl VClockAlloc {
 
         // Throw the data-race detection.
         Err(err_machine_stop!(TerminationInfo::DataRace {
+            involves_non_atomic,
             ptr: ptr_dbg,
             op1: RacingOp {
                 action: other_action.to_string(),
@@ -841,26 +910,6 @@ impl VClockAlloc {
         }))?
     }
 
-    /// Detect racing atomic read and writes (not data races)
-    /// on every byte of the current access range
-    pub(super) fn race_free_with_atomic(
-        &self,
-        range: AllocRange,
-        global: &GlobalState,
-        thread_mgr: &ThreadManager<'_, '_>,
-    ) -> bool {
-        if global.race_detecting() {
-            let (_, thread_clocks) = global.current_thread_state(thread_mgr);
-            let alloc_ranges = self.alloc_ranges.borrow();
-            for (_, mem_clocks) in alloc_ranges.iter(range.start, range.size) {
-                if !mem_clocks.race_free_with_atomic(&thread_clocks) {
-                    return false;
-                }
-            }
-        }
-        true
-    }
-
     /// Detect data-races for an unsynchronized read operation, will not perform
     /// data-race detection if `race_detecting()` is false, either due to no threads
     /// being created or if it is temporarily disabled during a racy read or write
@@ -890,7 +939,8 @@ impl VClockAlloc {
                         &machine.threads,
                         mem_clocks,
                         "Read",
-                        false,
+                        /* is_atomic */ false,
+                        access_range.size,
                         Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
                     );
                 }
@@ -929,7 +979,8 @@ impl VClockAlloc {
                         &machine.threads,
                         mem_clocks,
                         write_type.get_descriptor(),
-                        false,
+                        /* is_atomic */ false,
+                        access_range.size,
                         Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
                     );
                 }
@@ -1050,16 +1101,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         atomic: AtomicReadOrd,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_ref();
-        this.validate_overlapping_atomic(place)?;
         this.validate_atomic_op(
             place,
             atomic,
             "Atomic Load",
             move |memory, clocks, index, atomic| {
                 if atomic == AtomicReadOrd::Relaxed {
-                    memory.load_relaxed(&mut *clocks, index)
+                    memory.load_relaxed(&mut *clocks, index, place.layout.size)
                 } else {
-                    memory.load_acquire(&mut *clocks, index)
+                    memory.load_acquire(&mut *clocks, index, place.layout.size)
                 }
             },
         )
@@ -1073,16 +1123,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         atomic: AtomicWriteOrd,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        this.validate_overlapping_atomic(place)?;
         this.validate_atomic_op(
             place,
             atomic,
             "Atomic Store",
             move |memory, clocks, index, atomic| {
                 if atomic == AtomicWriteOrd::Relaxed {
-                    memory.store_relaxed(clocks, index)
+                    memory.store_relaxed(clocks, index, place.layout.size)
                 } else {
-                    memory.store_release(clocks, index)
+                    memory.store_release(clocks, index, place.layout.size)
                 }
             },
         )
@@ -1099,17 +1148,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
         let acquire = matches!(atomic, Acquire | AcqRel | SeqCst);
         let release = matches!(atomic, Release | AcqRel | SeqCst);
         let this = self.eval_context_mut();
-        this.validate_overlapping_atomic(place)?;
         this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| {
             if acquire {
-                memory.load_acquire(clocks, index)?;
+                memory.load_acquire(clocks, index, place.layout.size)?;
             } else {
-                memory.load_relaxed(clocks, index)?;
+                memory.load_relaxed(clocks, index, place.layout.size)?;
             }
             if release {
-                memory.rmw_release(clocks, index)
+                memory.rmw_release(clocks, index, place.layout.size)
             } else {
-                memory.rmw_relaxed(clocks, index)
+                memory.rmw_relaxed(clocks, index, place.layout.size)
             }
         })
     }
@@ -1160,7 +1208,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
                                     &this.machine.threads,
                                     mem_clocks,
                                     description,
-                                    true,
+                                    /* is_atomic */ true,
+                                    place.layout.size,
                                     Pointer::new(
                                         alloc_id,
                                         Size::from_bytes(mem_clocks_range.start),
diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs
index 6781b1f6dd3..2ff344bb1a3 100644
--- a/src/tools/miri/src/concurrency/weak_memory.rs
+++ b/src/tools/miri/src/concurrency/weak_memory.rs
@@ -169,14 +169,6 @@ impl StoreBufferAlloc {
         Self { store_buffers: RefCell::new(RangeObjectMap::new()) }
     }
 
-    /// Checks if the range imperfectly overlaps with existing buffers
-    /// Used to determine if mixed-size atomic accesses
-    fn is_overlapping(&self, range: AllocRange) -> bool {
-        let buffers = self.store_buffers.borrow();
-        let access_type = buffers.access_type(range);
-        matches!(access_type, AccessType::ImperfectlyOverlapping(_))
-    }
-
     /// When a non-atomic access happens on a location that has been atomically accessed
     /// before without data race, we can determine that the non-atomic access fully happens
     /// after all the prior atomic accesses so the location no longer needs to exhibit
@@ -190,6 +182,8 @@ impl StoreBufferAlloc {
                     buffers.remove_from_pos(pos);
                 }
                 AccessType::ImperfectlyOverlapping(pos_range) => {
+                    // We rely on the data-race check making sure this is synchronized.
+                    // Therefore we can forget about the old data here.
                     buffers.remove_pos_range(pos_range);
                 }
                 AccessType::Empty(_) => {
@@ -215,7 +209,7 @@ impl StoreBufferAlloc {
                 pos
             }
             AccessType::ImperfectlyOverlapping(pos_range) => {
-                // Once we reach here we would've already checked that this access is not racy
+                // Once we reach here we would've already checked that this access is not racy.
                 let mut buffers = self.store_buffers.borrow_mut();
                 buffers.remove_pos_range(pos_range.clone());
                 buffers.insert_at_pos(pos_range.start, range, StoreBuffer::new(init));
@@ -240,6 +234,7 @@ impl StoreBufferAlloc {
                 pos
             }
             AccessType::ImperfectlyOverlapping(pos_range) => {
+                // Once we reach here we would've already checked that this access is not racy.
                 buffers.remove_pos_range(pos_range.clone());
                 buffers.insert_at_pos(pos_range.start, range, StoreBuffer::new(init));
                 pos_range.start
@@ -473,37 +468,6 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir,
 pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
     crate::MiriInterpCxExt<'mir, 'tcx>
 {
-    // If weak memory emulation is enabled, check if this atomic op imperfectly overlaps with a previous
-    // atomic read or write. If it does, then we require it to be ordered (non-racy) with all previous atomic
-    // accesses on all the bytes in range
-    fn validate_overlapping_atomic(
-        &self,
-        place: &MPlaceTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx> {
-        let this = self.eval_context_ref();
-        let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?;
-        if let crate::AllocExtra {
-            weak_memory: Some(alloc_buffers),
-            data_race: Some(alloc_clocks),
-            ..
-        } = this.get_alloc_extra(alloc_id)?
-        {
-            let range = alloc_range(base_offset, place.layout.size);
-            if alloc_buffers.is_overlapping(range)
-                && !alloc_clocks.race_free_with_atomic(
-                    range,
-                    this.machine.data_race.as_ref().unwrap(),
-                    &this.machine.threads,
-                )
-            {
-                throw_unsup_format!(
-                    "racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation"
-                );
-            }
-        }
-        Ok(())
-    }
-
     fn buffered_atomic_rmw(
         &mut self,
         new_val: Scalar<Provenance>,
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index cb095f94f35..9b8f263b7ce 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -43,9 +43,10 @@ pub enum TerminationInfo {
         span: SpanData,
     },
     DataRace {
+        involves_non_atomic: bool,
+        ptr: Pointer,
         op1: RacingOp,
         op2: RacingOp,
-        ptr: Pointer,
     },
 }
 
@@ -74,11 +75,15 @@ impl fmt::Display for TerminationInfo {
                 write!(f, "multiple definitions of symbol `{link_name}`"),
             SymbolShimClashing { link_name, .. } =>
                 write!(f, "found `{link_name}` symbol definition that clashes with a built-in shim",),
-            DataRace { ptr, op1, op2 } =>
+            DataRace { involves_non_atomic, ptr, op1, op2 } =>
                 write!(
                     f,
-                    "Data race detected between (1) {} on {} and (2) {} on {} at {ptr:?}. (2) just happened here",
-                    op1.action, op1.thread_info, op2.action, op2.thread_info
+                    "{} detected between (1) {} on {} and (2) {} on {} at {ptr:?}. (2) just happened here",
+                    if *involves_non_atomic { "Data race" } else { "Race condition" },
+                    op1.action,
+                    op1.thread_info,
+                    op2.action,
+                    op2.thread_info
                 ),
         }
     }
diff --git a/src/tools/miri/src/intptrcast.rs b/src/tools/miri/src/intptrcast.rs
index ab6a256f714..9966ee3fd91 100644
--- a/src/tools/miri/src/intptrcast.rs
+++ b/src/tools/miri/src/intptrcast.rs
@@ -27,9 +27,9 @@ pub type GlobalState = RefCell<GlobalStateInner>;
 #[derive(Clone, Debug)]
 pub struct GlobalStateInner {
     /// This is used as a map between the address of each allocation and its `AllocId`. It is always
-    /// sorted. We cannot use a `HashMap` since we can be given an address that is offset from the
-    /// base address, and we need to find the `AllocId` it belongs to.
-    /// This is not the *full* inverse of `base_addr`; dead allocations have been removed.
+    /// sorted by address. We cannot use a `HashMap` since we can be given an address that is offset
+    /// from the base address, and we need to find the `AllocId` it belongs to. This is not the
+    /// *full* inverse of `base_addr`; dead allocations have been removed.
     int_to_ptr_map: Vec<(u64, AllocId)>,
     /// The base address for each allocation.  We cannot put that into
     /// `AllocExtra` because function pointers also have a base address, and
@@ -285,7 +285,12 @@ impl GlobalStateInner {
         // However, we *can* remove it from `int_to_ptr_map`, since any wildcard pointers that exist
         // can no longer actually be accessing that address. This ensures `alloc_id_from_addr` never
         // returns a dead allocation.
-        self.int_to_ptr_map.retain(|&(_, id)| id != dead_id);
+        // To avoid a linear scan we first look up the address in `base_addr`, and then find it in
+        // `int_to_ptr_map`.
+        let addr = *self.base_addr.get(&dead_id).unwrap();
+        let pos = self.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr).unwrap();
+        let removed = self.int_to_ptr_map.remove(pos);
+        assert_eq!(removed, (addr, dead_id)); // double-check that we removed the right thing
         // We can also remove it from `exposed`, since this allocation can anyway not be returned by
         // `alloc_id_from_addr` any more.
         self.exposed.remove(&dead_id);
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index d6d0483f5e3..4918698c6b2 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -51,13 +51,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             "macos" => {
                 absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")];
                 relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")];
-                // Some clocks only seem to exist in the aarch64 version of the target.
-                if this.tcx.sess.target.arch == "aarch64" {
-                    // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
-                    // that's not really something a program running inside Miri can tell, anyway.
-                    // We need to support it because std uses it.
-                    relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW"));
-                }
+                // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
+                // that's not really something a program running inside Miri can tell, anyway.
+                // We need to support it because std uses it.
+                relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW"));
             }
             target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"),
         }
@@ -68,7 +65,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         } else if relative_clocks.contains(&clk_id) {
             this.machine.clock.now().duration_since(this.machine.clock.anchor())
         } else {
-            // Unsupported clock.
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
             return Ok(Scalar::from_i32(-1));
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index c887e18e97e..bddc30b8379 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -363,7 +363,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 this.read_target_isize(hModule)?;
                 let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
-                if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) {
+                if let Ok(name) = str::from_utf8(name)
+                    && is_dyn_sym(name)
+                {
                     let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
                     this.write_pointer(ptr, dest)?;
                 } else {
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs
new file mode 100644
index 00000000000..d530ed2f5a4
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs
@@ -0,0 +1,25 @@
+//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
+use std::sync::atomic::{AtomicU16, AtomicU8, Ordering};
+use std::thread;
+
+fn convert(a: &AtomicU16) -> &[AtomicU8; 2] {
+    unsafe { std::mem::transmute(a) }
+}
+
+// We can't allow mixed-size accesses; they are not possible in C++ and even
+// Intel says you shouldn't do it.
+fn main() {
+    let a = AtomicU16::new(0);
+    let a16 = &a;
+    let a8 = convert(a16);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            a16.load(Ordering::SeqCst);
+        });
+        s.spawn(|| {
+            a8[0].load(Ordering::SeqCst);
+            //~^ ERROR: Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>`
+        });
+    });
+}
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr
new file mode 100644
index 00000000000..06944a11db8
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here
+  --> $DIR/mixed_size_read.rs:LL:CC
+   |
+LL |             a8[0].load(Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> $DIR/mixed_size_read.rs:LL:CC
+   |
+LL |             a16.load(Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span):
+   = note: inside closure at $DIR/mixed_size_read.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write.rs
new file mode 100644
index 00000000000..df3551612c3
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_write.rs
@@ -0,0 +1,25 @@
+//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
+use std::sync::atomic::{AtomicU16, AtomicU8, Ordering};
+use std::thread;
+
+fn convert(a: &AtomicU16) -> &[AtomicU8; 2] {
+    unsafe { std::mem::transmute(a) }
+}
+
+// We can't allow mixed-size accesses; they are not possible in C++ and even
+// Intel says you shouldn't do it.
+fn main() {
+    let a = AtomicU16::new(0);
+    let a16 = &a;
+    let a8 = convert(a16);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            a16.store(1, Ordering::SeqCst);
+        });
+        s.spawn(|| {
+            a8[0].store(1, Ordering::SeqCst);
+            //~^ ERROR: Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>`
+        });
+    });
+}
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr
new file mode 100644
index 00000000000..4bb949175bf
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here
+  --> $DIR/mixed_size_write.rs:LL:CC
+   |
+LL |             a8[0].store(1, Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> $DIR/mixed_size_write.rs:LL:CC
+   |
+LL |             a16.store(1, Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span):
+   = note: inside closure at $DIR/mixed_size_write.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.rs b/src/tools/miri/tests/fail/data_race/read_read_race1.rs
new file mode 100644
index 00000000000..eebfbc74d40
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/read_read_race1.rs
@@ -0,0 +1,27 @@
+//@compile-flags: -Zmiri-preemption-rate=0.0
+use std::sync::atomic::{AtomicU16, Ordering};
+use std::thread;
+
+// Make sure races between atomic and non-atomic reads are detected.
+// This seems harmless but C++ does not allow them, so we can't allow them for now either.
+// This test coverse the case where the non-atomic access come first.
+fn main() {
+    let a = AtomicU16::new(0);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            let ptr = &a as *const AtomicU16 as *mut u16;
+            unsafe { ptr.read() };
+        });
+        s.spawn(|| {
+            thread::yield_now();
+
+            // We also put a non-atomic access here, but that should *not* be reported.
+            let ptr = &a as *const AtomicU16 as *mut u16;
+            unsafe { ptr.read() };
+            // Then do the atomic access.
+            a.load(Ordering::SeqCst);
+            //~^ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>`
+        });
+    });
+}
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr
new file mode 100644
index 00000000000..158b438bd0d
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here
+  --> $DIR/read_read_race1.rs:LL:CC
+   |
+LL |             a.load(Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> $DIR/read_read_race1.rs:LL:CC
+   |
+LL |             unsafe { ptr.read() };
+   |                      ^^^^^^^^^^
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span):
+   = note: inside closure at $DIR/read_read_race1.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.rs b/src/tools/miri/tests/fail/data_race/read_read_race2.rs
new file mode 100644
index 00000000000..230b429e287
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/read_read_race2.rs
@@ -0,0 +1,27 @@
+//@compile-flags: -Zmiri-preemption-rate=0.0
+use std::sync::atomic::{AtomicU16, Ordering};
+use std::thread;
+
+// Make sure races between atomic and non-atomic reads are detected.
+// This seems harmless but C++ does not allow them, so we can't allow them for now either.
+// This test coverse the case where the atomic access come first.
+fn main() {
+    let a = AtomicU16::new(0);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            // We also put a non-atomic access here, but that should *not* be reported.
+            let ptr = &a as *const AtomicU16 as *mut u16;
+            unsafe { ptr.read() };
+            // Then do the atomic access.
+            a.load(Ordering::SeqCst);
+        });
+        s.spawn(|| {
+            thread::yield_now();
+
+            let ptr = &a as *const AtomicU16 as *mut u16;
+            unsafe { ptr.read() };
+            //~^ ERROR: Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>`
+        });
+    });
+}
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr
new file mode 100644
index 00000000000..7f867b9edbb
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here
+  --> $DIR/read_read_race2.rs:LL:CC
+   |
+LL |             unsafe { ptr.read() };
+   |                      ^^^^^^^^^^ Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> $DIR/read_read_race2.rs:LL:CC
+   |
+LL |             a.load(Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span):
+   = note: inside closure at $DIR/read_read_race2.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs
index 7bbb7f9fe7c..36dc0d5f3f7 100644
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs
+++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs
@@ -19,7 +19,7 @@ fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] {
 
 // Wine's SRWLock implementation does this, which is definitely undefined in C++ memory model
 // https://github.com/wine-mirror/wine/blob/303f8042f9db508adaca02ef21f8de4992cb9c03/dlls/ntdll/sync.c#L543-L566
-// Though it probably works just fine on x86
+// It probably works just fine on x86, but Intel does document this as "don't do it!"
 pub fn main() {
     let x = static_atomic_u32(0);
     let j1 = spawn(move || {
@@ -31,7 +31,7 @@ pub fn main() {
         let x_split = split_u32_ptr(x_ptr);
         unsafe {
             let hi = ptr::addr_of!((*x_split)[0]);
-            std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping
+            std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: different-size
         }
     });
 
diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr
index dda22ac9ce2..055585ab96f 100644
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr
+++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr
@@ -1,11 +1,17 @@
-error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation
+error: Undefined Behavior: Race condition detected between (1) 4-byte Atomic Store on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here
   --> $DIR/racing_mixed_size.rs:LL:CC
    |
 LL |             std::intrinsics::atomic_load_relaxed(hi);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte Atomic Store on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here
    |
-   = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
-   = note: BACKTRACE:
+help: and (1) occurred earlier here
+  --> $DIR/racing_mixed_size.rs:LL:CC
+   |
+LL |         x.store(1, Relaxed);
+   |         ^^^^^^^^^^^^^^^^^^^
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span):
    = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs
index 73178980b7e..5cd14540ca3 100644
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs
+++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs
@@ -16,7 +16,7 @@ fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] {
 
 // Racing mixed size reads may cause two loads to read-from
 // the same store but observe different values, which doesn't make
-// sense under the formal model so we forbade this.
+// sense under the formal model so we forbid this.
 pub fn main() {
     let x = static_atomic(0);
 
@@ -29,7 +29,7 @@ pub fn main() {
         let x_split = split_u32_ptr(x_ptr);
         unsafe {
             let hi = x_split as *const u16 as *const AtomicU16;
-            (*hi).load(Relaxed); //~ ERROR: imperfectly overlapping
+            (*hi).load(Relaxed); //~ ERROR: different-size
         }
     });
 
diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr
index 59fa5c74102..2eefa0a87b4 100644
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr
+++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr
@@ -1,11 +1,17 @@
-error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation
+error: Undefined Behavior: Race condition detected between (1) 4-byte Atomic Load on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here
   --> $DIR/racing_mixed_size_read.rs:LL:CC
    |
 LL |             (*hi).load(Relaxed);
-   |             ^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation
+   |             ^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte Atomic Load on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here
    |
-   = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
-   = note: BACKTRACE:
+help: and (1) occurred earlier here
+  --> $DIR/racing_mixed_size_read.rs:LL:CC
+   |
+LL |         x.load(Relaxed);
+   |         ^^^^^^^^^^^^^^^
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span):
    = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
index a456528ec20..648c004c97c 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
@@ -2,7 +2,7 @@
 //@compile-flags: -Zmiri-disable-isolation
 
 use std::mem::MaybeUninit;
-use std::ptr;
+use std::ptr::{self, addr_of};
 use std::sync::atomic::AtomicI32;
 use std::sync::atomic::Ordering;
 use std::thread;
@@ -13,7 +13,7 @@ fn wake_nobody() {
 
     // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
     unsafe {
-        assert_eq!(libc::syscall(libc::SYS_futex, &futex as *const i32, libc::FUTEX_WAKE, 1), 0);
+        assert_eq!(libc::syscall(libc::SYS_futex, addr_of!(futex), libc::FUTEX_WAKE, 1), 0);
     }
 
     // Same, but without omitting the unused arguments.
@@ -21,7 +21,7 @@ fn wake_nobody() {
         assert_eq!(
             libc::syscall(
                 libc::SYS_futex,
-                &futex as *const i32,
+                addr_of!(futex),
                 libc::FUTEX_WAKE,
                 1,
                 ptr::null::<libc::timespec>(),
@@ -52,7 +52,7 @@ fn wait_wrong_val() {
         assert_eq!(
             libc::syscall(
                 libc::SYS_futex,
-                &futex as *const i32,
+                addr_of!(futex),
                 libc::FUTEX_WAIT,
                 456,
                 ptr::null::<libc::timespec>(),
@@ -73,7 +73,7 @@ fn wait_timeout() {
         assert_eq!(
             libc::syscall(
                 libc::SYS_futex,
-                &futex as *const i32,
+                addr_of!(futex),
                 libc::FUTEX_WAIT,
                 123,
                 &libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 },
@@ -110,7 +110,7 @@ fn wait_absolute_timeout() {
         assert_eq!(
             libc::syscall(
                 libc::SYS_futex,
-                &futex as *const i32,
+                addr_of!(futex),
                 libc::FUTEX_WAIT_BITSET,
                 123,
                 &timeout,
@@ -136,7 +136,7 @@ fn wait_wake() {
             assert_eq!(
                 libc::syscall(
                     libc::SYS_futex,
-                    &FUTEX as *const i32,
+                    addr_of!(FUTEX),
                     libc::FUTEX_WAKE,
                     10, // Wake up at most 10 threads.
                 ),
@@ -149,7 +149,7 @@ fn wait_wake() {
         assert_eq!(
             libc::syscall(
                 libc::SYS_futex,
-                &FUTEX as *const i32,
+                addr_of!(FUTEX),
                 libc::FUTEX_WAIT,
                 0,
                 ptr::null::<libc::timespec>(),
@@ -173,7 +173,7 @@ fn wait_wake_bitset() {
             assert_eq!(
                 libc::syscall(
                     libc::SYS_futex,
-                    &FUTEX as *const i32,
+                    addr_of!(FUTEX),
                     libc::FUTEX_WAKE_BITSET,
                     10, // Wake up at most 10 threads.
                     ptr::null::<libc::timespec>(),
@@ -188,7 +188,7 @@ fn wait_wake_bitset() {
             assert_eq!(
                 libc::syscall(
                     libc::SYS_futex,
-                    &FUTEX as *const i32,
+                    addr_of!(FUTEX),
                     libc::FUTEX_WAKE_BITSET,
                     10, // Wake up at most 10 threads.
                     ptr::null::<libc::timespec>(),
@@ -204,7 +204,7 @@ fn wait_wake_bitset() {
         assert_eq!(
             libc::syscall(
                 libc::SYS_futex,
-                &FUTEX as *const i32,
+                addr_of!(FUTEX),
                 libc::FUTEX_WAIT_BITSET,
                 0,
                 ptr::null::<libc::timespec>(),
@@ -244,7 +244,7 @@ fn concurrent_wait_wake() {
             unsafe {
                 let ret = libc::syscall(
                     libc::SYS_futex,
-                    &FUTEX as *const AtomicI32,
+                    addr_of!(FUTEX),
                     libc::FUTEX_WAIT,
                     HELD,
                     ptr::null::<libc::timespec>(),
@@ -267,7 +267,7 @@ fn concurrent_wait_wake() {
         FUTEX.store(FREE, Ordering::Relaxed);
         unsafe {
             DATA = 1;
-            libc::syscall(libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAKE, 1);
+            libc::syscall(libc::SYS_futex, addr_of!(FUTEX), libc::FUTEX_WAKE, 1);
         }
 
         t.join().unwrap();
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
index 82c49cfb17c..40d3fa19e53 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
@@ -186,7 +186,7 @@ fn test_clocks() {
             unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) };
         assert_eq!(is_error, 0);
     }
-    #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
+    #[cfg(target_os = "macos")]
     {
         let is_error = unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) };
         assert_eq!(is_error, 0);
diff --git a/src/tools/miri/tests/pass/concurrency/simple.rs b/src/tools/miri/tests/pass/concurrency/simple.rs
index 556e0a24769..ec549a998ba 100644
--- a/src/tools/miri/tests/pass/concurrency/simple.rs
+++ b/src/tools/miri/tests/pass/concurrency/simple.rs
@@ -62,6 +62,23 @@ fn panic_named() {
         .unwrap_err();
 }
 
+// This is not a data race!
+fn shared_readonly() {
+    use std::sync::Arc;
+
+    let x = Arc::new(42i32);
+    let h = thread::spawn({
+        let x = Arc::clone(&x);
+        move || {
+            assert_eq!(*x, 42);
+        }
+    });
+
+    assert_eq!(*x, 42);
+
+    h.join().unwrap();
+}
+
 fn main() {
     create_and_detach();
     create_and_join();
@@ -71,6 +88,7 @@ fn main() {
     create_nested_and_join();
     create_move_in();
     create_move_out();
+    shared_readonly();
     panic();
     panic_named();
 }
diff --git a/src/tools/miri/tests/pass/intrinsics-math.rs b/src/tools/miri/tests/pass/intrinsics-math.rs
index 5f7730a3e86..589864f4f4b 100644
--- a/src/tools/miri/tests/pass/intrinsics-math.rs
+++ b/src/tools/miri/tests/pass/intrinsics-math.rs
@@ -125,9 +125,8 @@ pub fn main() {
 
     assert_approx_eq!(5.0f32.gamma(), 24.0);
     assert_approx_eq!(5.0f64.gamma(), 24.0);
-    // These fail even on the host, precision seems to be terrible.
-    //assert_approx_eq!(-0.5f32.gamma(), -2.0 * f32::consts::PI.sqrt());
-    //assert_approx_eq!(-0.5f64.gamma(), -2.0 * f64::consts::PI.sqrt());
+    assert_approx_eq!((-0.5f32).gamma(), (-2.0) * f32::consts::PI.sqrt());
+    assert_approx_eq!((-0.5f64).gamma(), (-2.0) * f64::consts::PI.sqrt());
 
     assert_eq!(2.0f32.ln_gamma(), (0.0, 1));
     assert_eq!(2.0f64.ln_gamma(), (0.0, 1));
diff --git a/src/tools/miri/tests/pass/weak_memory/extra_cpp_unsafe.rs b/src/tools/miri/tests/pass/weak_memory/extra_cpp_unsafe.rs
deleted file mode 100644
index 48b15191b38..00000000000
--- a/src/tools/miri/tests/pass/weak_memory/extra_cpp_unsafe.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//@compile-flags: -Zmiri-ignore-leaks
-
-// Tests operations not performable through C++'s atomic API
-// but doable in unsafe Rust which we think *should* be fine.
-// Nonetheless they may be determined as inconsistent with the
-// memory model in the future.
-
-#![feature(atomic_from_mut)]
-
-use std::sync::atomic::AtomicU32;
-use std::sync::atomic::Ordering::*;
-use std::thread::spawn;
-
-fn static_atomic(val: u32) -> &'static AtomicU32 {
-    let ret = Box::leak(Box::new(AtomicU32::new(val)));
-    ret
-}
-
-// We allow perfectly overlapping non-atomic and atomic reads to race
-fn racing_mixed_atomicity_read() {
-    let x = static_atomic(0);
-    x.store(42, Relaxed);
-
-    let j1 = spawn(move || x.load(Relaxed));
-
-    let j2 = spawn(move || {
-        let x_ptr = x as *const AtomicU32 as *const u32;
-        unsafe { x_ptr.read() }
-    });
-
-    let r1 = j1.join().unwrap();
-    let r2 = j2.join().unwrap();
-
-    assert_eq!(r1, 42);
-    assert_eq!(r2, 42);
-}
-
-pub fn main() {
-    racing_mixed_atomicity_read();
-}
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index 3c33cfe985d..8a8f98a5eda 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -24,10 +24,11 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
     let host_triple = env.host_triple();
     let version = find_dist_version(&dist_dir)?;
 
-    // Extract rustc, libstd and src archives to create the optimized sysroot
+    // Extract rustc, libstd, cargo and src archives to create the optimized sysroot
     let rustc_dir = extract_dist_dir(&format!("rustc-{version}-{host_triple}"))?.join("rustc");
     let libstd_dir = extract_dist_dir(&format!("rust-std-{version}-{host_triple}"))?
         .join(format!("rust-std-{host_triple}"));
+    let cargo_dir = extract_dist_dir(&format!("cargo-{version}-{host_triple}"))?.join("cargo");
     let extracted_src_dir = extract_dist_dir(&format!("rust-src-{version}"))?.join("rust-src");
 
     // We need to manually copy libstd to the extracted rustc sysroot
@@ -46,6 +47,8 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
 
     let rustc_path = rustc_dir.join("bin").join(format!("rustc{}", executable_extension()));
     assert!(rustc_path.is_file());
+    let cargo_path = cargo_dir.join("bin").join(format!("cargo{}", executable_extension()));
+    assert!(cargo_path.is_file());
 
     // Specify path to a LLVM config so that LLVM is not rebuilt.
     // It doesn't really matter which LLVM config we choose, because no sysroot will be compiled.
@@ -62,11 +65,13 @@ change-id = 115898
 
 [build]
 rustc = "{rustc}"
+cargo = "{cargo}"
 
 [target.{host_triple}]
 llvm-config = "{llvm_config}"
 "#,
         rustc = rustc_path.to_string().replace('\\', "/"),
+        cargo = cargo_path.to_string().replace('\\', "/"),
         llvm_config = llvm_config.to_string().replace('\\', "/")
     );
     log::info!("Using following `config.toml` for running tests:\n{config_content}");
diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
index ed47baa67da..313e5dddbbb 100644
--- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
+++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
@@ -41,7 +41,8 @@
 +                             debug ((f: (bool, bool, u32)).2: u32) => const 123_u32;
                               let _10: std::option::Option<u16>;
                               scope 7 {
-                                  debug o => _10;
+-                                 debug o => _10;
++                                 debug o => const Option::<u16>::Some(99_u16);
                                   let _17: u32;
                                   let _18: u32;
                                   scope 8 {
@@ -81,7 +82,7 @@
           _15 = const false;
           _16 = const 123_u32;
           StorageLive(_10);
-          _10 = Option::<u16>::Some(const 99_u16);
+          _10 = const Option::<u16>::Some(99_u16);
           _17 = const 32_u32;
           _18 = const 32_u32;
           StorageLive(_11);
@@ -97,3 +98,7 @@
       }
   }
   
+  ALLOC0 (size: 4, align: 2) {
+      01 00 63 00                                     │ ..c.
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
index 2f1a70f32d0..4569ffe483b 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
@@ -43,7 +43,7 @@
 -         _6 = CheckedAdd(_4, _5);
 -         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind unreachable];
 +         _5 = const 2_i32;
-+         _6 = CheckedAdd(const 1_i32, const 2_i32);
++         _6 = const (3_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind unreachable];
       }
   
@@ -60,7 +60,7 @@
 -         _10 = CheckedAdd(_9, const 1_i32);
 -         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind unreachable];
 +         _9 = const i32::MAX;
-+         _10 = CheckedAdd(const i32::MAX, const 1_i32);
++         _10 = const (i32::MIN, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind unreachable];
       }
   
@@ -76,5 +76,13 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 80 01 __ __ __                         │ .....░░░
++ }
++ 
++ ALLOC1 (size: 8, align: 4) {
++     03 00 00 00 00 __ __ __                         │ .....░░░
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
index 0d8a9aca3d8..aa7e404eb9f 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
@@ -43,7 +43,7 @@
 -         _6 = CheckedAdd(_4, _5);
 -         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind continue];
 +         _5 = const 2_i32;
-+         _6 = CheckedAdd(const 1_i32, const 2_i32);
++         _6 = const (3_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
@@ -60,7 +60,7 @@
 -         _10 = CheckedAdd(_9, const 1_i32);
 -         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind continue];
 +         _9 = const i32::MAX;
-+         _10 = CheckedAdd(const i32::MAX, const 1_i32);
++         _10 = const (i32::MIN, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind continue];
       }
   
@@ -76,5 +76,13 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 80 01 __ __ __                         │ .....░░░
++ }
++ 
++ ALLOC1 (size: 8, align: 4) {
++     03 00 00 00 00 __ __ __                         │ .....░░░
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs
index b41ac0b3d2a..f7fac8890a0 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.rs
+++ b/tests/mir-opt/dataflow-const-prop/checked.rs
@@ -1,7 +1,7 @@
 // skip-filecheck
-// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // unit-test: DataflowConstProp
 // compile-flags: -Coverflow-checks=on
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 // EMIT_MIR checked.main.DataflowConstProp.diff
 #[allow(arithmetic_overflow)]
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
index 3946e7c7d96..798b0c041b4 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
@@ -23,7 +23,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = E::V1(const 0_i32);
+-         _1 = E::V1(const 0_i32);
++         _1 = const E::V1(0_i32);
           StorageLive(_2);
 -         _3 = discriminant(_1);
 -         switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
@@ -59,5 +60,9 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 00 00 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
index 3946e7c7d96..798b0c041b4 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
@@ -23,7 +23,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = E::V1(const 0_i32);
+-         _1 = E::V1(const 0_i32);
++         _1 = const E::V1(0_i32);
           StorageLive(_2);
 -         _3 = discriminant(_1);
 -         switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2];
@@ -59,5 +60,9 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 00 00 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
index 1348b279330..d502b198239 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
@@ -44,7 +44,8 @@
           StorageLive(_1);
           StorageLive(_2);
           _2 = const {ALLOC1: &E};
-          _1 = (*_2);
+-         _1 = (*_2);
++         _1 = const E::V1(0_i32);
           StorageDead(_2);
           StorageLive(_3);
 -         _4 = discriminant(_1);
@@ -110,6 +111,10 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC3 (size: 8, align: 4) {
++     00 00 00 00 00 00 00 00                         │ ........
   }
   
   ALLOC2 (static: RC, size: 4, align: 4) {
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
index 66929e886d3..5d69572b507 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
@@ -44,7 +44,8 @@
           StorageLive(_1);
           StorageLive(_2);
           _2 = const {ALLOC1: &E};
-          _1 = (*_2);
+-         _1 = (*_2);
++         _1 = const E::V1(0_i32);
           StorageDead(_2);
           StorageLive(_3);
 -         _4 = discriminant(_1);
@@ -110,6 +111,10 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC3 (size: 8, align: 4) {
++     00 00 00 00 00 00 00 00                         │ ........
   }
   
   ALLOC2 (static: RC, size: 8, align: 8) {
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
index 87bb1454c96..2d4591ea2d3 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
@@ -23,7 +23,7 @@
           StorageLive(_4);
 -         _4 = CheckedAdd(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
-+         _4 = CheckedAdd(const u8::MAX, const 1_u8);
++         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable];
       }
   
@@ -37,5 +37,9 @@
           _0 = const ();
           return;
       }
++ }
++ 
++ ALLOC0 (size: 2, align: 1) {
++     00 01                                           │ ..
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
index b2f13640a4c..e99ac782a2f 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
@@ -23,7 +23,7 @@
           StorageLive(_4);
 -         _4 = CheckedAdd(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
-+         _4 = CheckedAdd(const u8::MAX, const 1_u8);
++         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
       }
   
@@ -37,5 +37,9 @@
           _0 = const ();
           return;
       }
++ }
++ 
++ ALLOC0 (size: 2, align: 1) {
++     00 01                                           │ ..
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff
index 4b1a8d932c6..98bd40ab2c3 100644
--- a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff
@@ -17,7 +17,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = I32(const 0_i32);
+-         _1 = I32(const 0_i32);
++         _1 = const I32(0_i32);
           StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
@@ -31,12 +32,20 @@
           StorageDead(_5);
           StorageDead(_4);
 -         _2 = I32(move _3);
-+         _2 = I32(const 0_i32);
++         _2 = const I32(0_i32);
           StorageDead(_3);
           _0 = const ();
           StorageDead(_2);
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 4, align: 4) {
++     00 00 00 00                                     │ ....
++ }
++ 
++ ALLOC1 (size: 4, align: 4) {
++     00 00 00 00                                     │ ....
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
index e80f31ca934..8499d0a89c3 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
@@ -7,13 +7,24 @@
       let mut _3: i32;
       let mut _5: i32;
       let mut _6: i32;
-      let mut _11: BigStruct;
-      let mut _16: &&BigStruct;
-      let mut _17: &BigStruct;
-      let mut _18: &BigStruct;
-      let mut _19: &BigStruct;
-      let mut _20: &BigStruct;
-      let mut _21: &BigStruct;
+      let mut _10: SmallStruct;
+      let mut _14: &&SmallStruct;
+      let mut _16: f32;
+      let mut _17: std::option::Option<S>;
+      let mut _18: &[f32];
+      let mut _22: BigStruct;
+      let mut _26: &&BigStruct;
+      let mut _28: f32;
+      let mut _29: std::option::Option<S>;
+      let mut _30: &[f32];
+      let mut _31: &SmallStruct;
+      let mut _32: &SmallStruct;
+      let mut _33: &SmallStruct;
+      let mut _34: &SmallStruct;
+      let mut _35: &BigStruct;
+      let mut _36: &BigStruct;
+      let mut _37: &BigStruct;
+      let mut _38: &BigStruct;
       scope 1 {
           debug s => _1;
           let _2: i32;
@@ -22,24 +33,44 @@
               let _4: i32;
               scope 3 {
                   debug b => _4;
-                  let _7: S;
-                  let _8: u8;
-                  let _9: f32;
-                  let _10: S;
+                  let _7: f32;
+                  let _8: std::option::Option<S>;
+                  let _9: &[f32];
                   scope 4 {
                       debug a => _7;
                       debug b => _8;
                       debug c => _9;
-                      debug d => _10;
-                      let _12: S;
-                      let _13: u8;
-                      let _14: f32;
-                      let _15: S;
+                      let _11: f32;
+                      let _12: std::option::Option<S>;
+                      let _13: &[f32];
                       scope 5 {
-                          debug a => _12;
-                          debug b => _13;
-                          debug c => _14;
-                          debug d => _15;
+                          debug a => _11;
+                          debug b => _12;
+                          debug c => _13;
+                          let _15: SmallStruct;
+                          scope 6 {
+                              debug ss => _15;
+                              let _19: f32;
+                              let _20: std::option::Option<S>;
+                              let _21: &[f32];
+                              scope 7 {
+                                  debug a => _19;
+                                  debug b => _20;
+                                  debug c => _21;
+                                  let _23: f32;
+                                  let _24: std::option::Option<S>;
+                                  let _25: &[f32];
+                                  scope 8 {
+                                      debug a => _23;
+                                      debug b => _24;
+                                      debug c => _25;
+                                      let _27: BigStruct;
+                                      scope 9 {
+                                          debug bs => _27;
+                                      }
+                                  }
+                              }
+                          }
                       }
                   }
               }
@@ -48,7 +79,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = S(const 1_i32);
+-         _1 = S(const 1_i32);
++         _1 = const S(1_i32);
           StorageLive(_2);
           StorageLive(_3);
 -         _3 = (_1.0: i32);
@@ -68,47 +100,95 @@
 +         _4 = const 6_i32;
           StorageDead(_6);
           StorageDead(_5);
-          StorageLive(_11);
-          _11 = const _;
+          StorageLive(_10);
+          _10 = const _;
           StorageLive(_7);
--         _7 = (_11.0: S);
-+         _7 = const S(1_i32);
+-         _7 = (_10.0: f32);
++         _7 = const 4f32;
           StorageLive(_8);
--         _8 = (_11.1: u8);
-+         _8 = const 5_u8;
+-         _8 = (_10.1: std::option::Option<S>);
++         _8 = const Option::<S>::Some(S(1_i32));
           StorageLive(_9);
--         _9 = (_11.2: f32);
-+         _9 = const 7f32;
-          StorageLive(_10);
--         _10 = (_11.3: S);
-+         _10 = const S(13_i32);
-          StorageDead(_11);
-          StorageLive(_16);
-          _16 = const {ALLOC1: &&BigStruct};
-          _17 = deref_copy (*_16);
+          _9 = (_10.2: &[f32]);
+          StorageDead(_10);
+          StorageLive(_14);
+          _14 = const {ALLOC4: &&SmallStruct};
+          _31 = deref_copy (*_14);
+          StorageLive(_11);
+          _32 = deref_copy (*_14);
+-         _11 = ((*_32).0: f32);
++         _11 = const 9f32;
           StorageLive(_12);
-          _18 = deref_copy (*_16);
--         _12 = ((*_18).0: S);
-+         _12 = const S(1_i32);
+          _33 = deref_copy (*_14);
+          _12 = ((*_33).1: std::option::Option<S>);
           StorageLive(_13);
-          _19 = deref_copy (*_16);
--         _13 = ((*_19).1: u8);
-+         _13 = const 5_u8;
-          StorageLive(_14);
-          _20 = deref_copy (*_16);
--         _14 = ((*_20).2: f32);
-+         _14 = const 7f32;
+          _34 = deref_copy (*_14);
+          _13 = ((*_34).2: &[f32]);
+          StorageDead(_14);
           StorageLive(_15);
-          _21 = deref_copy (*_16);
--         _15 = ((*_21).3: S);
-+         _15 = const S(13_i32);
+          StorageLive(_16);
+-         _16 = _11;
++         _16 = const 9f32;
+          StorageLive(_17);
+          _17 = _12;
+          StorageLive(_18);
+          _18 = _13;
+-         _15 = SmallStruct(move _16, move _17, move _18);
++         _15 = SmallStruct(const 9f32, move _17, move _18);
+          StorageDead(_18);
+          StorageDead(_17);
           StorageDead(_16);
+          StorageLive(_22);
+          _22 = const _;
+          StorageLive(_19);
+-         _19 = (_22.0: f32);
++         _19 = const 25f32;
+          StorageLive(_20);
+          _20 = (_22.1: std::option::Option<S>);
+          StorageLive(_21);
+          _21 = (_22.2: &[f32]);
+          StorageDead(_22);
+          StorageLive(_26);
+          _26 = const {ALLOC5: &&BigStruct};
+          _35 = deref_copy (*_26);
+          StorageLive(_23);
+          _36 = deref_copy (*_26);
+-         _23 = ((*_36).0: f32);
++         _23 = const 82f32;
+          StorageLive(_24);
+          _37 = deref_copy (*_26);
+-         _24 = ((*_37).1: std::option::Option<S>);
++         _24 = const Option::<S>::Some(S(35_i32));
+          StorageLive(_25);
+          _38 = deref_copy (*_26);
+          _25 = ((*_38).2: &[f32]);
+          StorageDead(_26);
+          StorageLive(_27);
+          StorageLive(_28);
+-         _28 = _23;
++         _28 = const 82f32;
+          StorageLive(_29);
+-         _29 = _24;
++         _29 = const Option::<S>::Some(S(35_i32));
+          StorageLive(_30);
+          _30 = _25;
+-         _27 = BigStruct(move _28, move _29, move _30);
++         _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
+          StorageDead(_30);
+          StorageDead(_29);
+          StorageDead(_28);
           _0 = const ();
+          StorageDead(_27);
+          StorageDead(_25);
+          StorageDead(_24);
+          StorageDead(_23);
+          StorageDead(_21);
+          StorageDead(_20);
+          StorageDead(_19);
           StorageDead(_15);
-          StorageDead(_14);
           StorageDead(_13);
           StorageDead(_12);
-          StorageDead(_10);
+          StorageDead(_11);
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_7);
@@ -117,13 +197,51 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC6 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC7 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC8 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC9 (size: 8, align: 4) {
++     01 00 00 00 01 00 00 00                         │ ........
++ }
++ 
++ ALLOC10 (size: 4, align: 4) {
++     01 00 00 00                                     │ ....
   }
   
-  ALLOC1 (static: STAT, size: 4, align: 4) {
+  ALLOC5 (static: BIG_STAT, size: 4, align: 4) {
       ╾ALLOC0╼                                     │ ╾──╼
   }
   
-  ALLOC0 (size: 16, align: 4) {
-      01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
+  ALLOC0 (size: 20, align: 4) {
+      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼....
+      0x10 │ 00 00 a4 42                                     │ ...B
+  }
+  
+  ALLOC1 (size: 8, align: 4) {
+      00 00 34 42 00 00 90 42                         │ ..4B...B
+  }
+  
+  ALLOC4 (static: SMALL_STAT, size: 4, align: 4) {
+      ╾ALLOC2╼                                     │ ╾──╼
+  }
+  
+  ALLOC2 (size: 20, align: 4) {
+      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼....
+      0x10 │ 00 00 10 41                                     │ ...A
+  }
+  
+  ALLOC3 (size: 4, align: 4) {
+      00 00 50 41                                     │ ..PA
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
index de9cf197199..01ec3f623d1 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
@@ -7,13 +7,24 @@
       let mut _3: i32;
       let mut _5: i32;
       let mut _6: i32;
-      let mut _11: BigStruct;
-      let mut _16: &&BigStruct;
-      let mut _17: &BigStruct;
-      let mut _18: &BigStruct;
-      let mut _19: &BigStruct;
-      let mut _20: &BigStruct;
-      let mut _21: &BigStruct;
+      let mut _10: SmallStruct;
+      let mut _14: &&SmallStruct;
+      let mut _16: f32;
+      let mut _17: std::option::Option<S>;
+      let mut _18: &[f32];
+      let mut _22: BigStruct;
+      let mut _26: &&BigStruct;
+      let mut _28: f32;
+      let mut _29: std::option::Option<S>;
+      let mut _30: &[f32];
+      let mut _31: &SmallStruct;
+      let mut _32: &SmallStruct;
+      let mut _33: &SmallStruct;
+      let mut _34: &SmallStruct;
+      let mut _35: &BigStruct;
+      let mut _36: &BigStruct;
+      let mut _37: &BigStruct;
+      let mut _38: &BigStruct;
       scope 1 {
           debug s => _1;
           let _2: i32;
@@ -22,24 +33,44 @@
               let _4: i32;
               scope 3 {
                   debug b => _4;
-                  let _7: S;
-                  let _8: u8;
-                  let _9: f32;
-                  let _10: S;
+                  let _7: f32;
+                  let _8: std::option::Option<S>;
+                  let _9: &[f32];
                   scope 4 {
                       debug a => _7;
                       debug b => _8;
                       debug c => _9;
-                      debug d => _10;
-                      let _12: S;
-                      let _13: u8;
-                      let _14: f32;
-                      let _15: S;
+                      let _11: f32;
+                      let _12: std::option::Option<S>;
+                      let _13: &[f32];
                       scope 5 {
-                          debug a => _12;
-                          debug b => _13;
-                          debug c => _14;
-                          debug d => _15;
+                          debug a => _11;
+                          debug b => _12;
+                          debug c => _13;
+                          let _15: SmallStruct;
+                          scope 6 {
+                              debug ss => _15;
+                              let _19: f32;
+                              let _20: std::option::Option<S>;
+                              let _21: &[f32];
+                              scope 7 {
+                                  debug a => _19;
+                                  debug b => _20;
+                                  debug c => _21;
+                                  let _23: f32;
+                                  let _24: std::option::Option<S>;
+                                  let _25: &[f32];
+                                  scope 8 {
+                                      debug a => _23;
+                                      debug b => _24;
+                                      debug c => _25;
+                                      let _27: BigStruct;
+                                      scope 9 {
+                                          debug bs => _27;
+                                      }
+                                  }
+                              }
+                          }
                       }
                   }
               }
@@ -48,7 +79,8 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = S(const 1_i32);
+-         _1 = S(const 1_i32);
++         _1 = const S(1_i32);
           StorageLive(_2);
           StorageLive(_3);
 -         _3 = (_1.0: i32);
@@ -68,47 +100,95 @@
 +         _4 = const 6_i32;
           StorageDead(_6);
           StorageDead(_5);
-          StorageLive(_11);
-          _11 = const _;
+          StorageLive(_10);
+          _10 = const _;
           StorageLive(_7);
--         _7 = (_11.0: S);
-+         _7 = const S(1_i32);
+-         _7 = (_10.0: f32);
++         _7 = const 4f32;
           StorageLive(_8);
--         _8 = (_11.1: u8);
-+         _8 = const 5_u8;
+-         _8 = (_10.1: std::option::Option<S>);
++         _8 = const Option::<S>::Some(S(1_i32));
           StorageLive(_9);
--         _9 = (_11.2: f32);
-+         _9 = const 7f32;
-          StorageLive(_10);
--         _10 = (_11.3: S);
-+         _10 = const S(13_i32);
-          StorageDead(_11);
-          StorageLive(_16);
-          _16 = const {ALLOC1: &&BigStruct};
-          _17 = deref_copy (*_16);
+          _9 = (_10.2: &[f32]);
+          StorageDead(_10);
+          StorageLive(_14);
+          _14 = const {ALLOC4: &&SmallStruct};
+          _31 = deref_copy (*_14);
+          StorageLive(_11);
+          _32 = deref_copy (*_14);
+-         _11 = ((*_32).0: f32);
++         _11 = const 9f32;
           StorageLive(_12);
-          _18 = deref_copy (*_16);
--         _12 = ((*_18).0: S);
-+         _12 = const S(1_i32);
+          _33 = deref_copy (*_14);
+          _12 = ((*_33).1: std::option::Option<S>);
           StorageLive(_13);
-          _19 = deref_copy (*_16);
--         _13 = ((*_19).1: u8);
-+         _13 = const 5_u8;
-          StorageLive(_14);
-          _20 = deref_copy (*_16);
--         _14 = ((*_20).2: f32);
-+         _14 = const 7f32;
+          _34 = deref_copy (*_14);
+          _13 = ((*_34).2: &[f32]);
+          StorageDead(_14);
           StorageLive(_15);
-          _21 = deref_copy (*_16);
--         _15 = ((*_21).3: S);
-+         _15 = const S(13_i32);
+          StorageLive(_16);
+-         _16 = _11;
++         _16 = const 9f32;
+          StorageLive(_17);
+          _17 = _12;
+          StorageLive(_18);
+          _18 = _13;
+-         _15 = SmallStruct(move _16, move _17, move _18);
++         _15 = SmallStruct(const 9f32, move _17, move _18);
+          StorageDead(_18);
+          StorageDead(_17);
           StorageDead(_16);
+          StorageLive(_22);
+          _22 = const _;
+          StorageLive(_19);
+-         _19 = (_22.0: f32);
++         _19 = const 25f32;
+          StorageLive(_20);
+          _20 = (_22.1: std::option::Option<S>);
+          StorageLive(_21);
+          _21 = (_22.2: &[f32]);
+          StorageDead(_22);
+          StorageLive(_26);
+          _26 = const {ALLOC5: &&BigStruct};
+          _35 = deref_copy (*_26);
+          StorageLive(_23);
+          _36 = deref_copy (*_26);
+-         _23 = ((*_36).0: f32);
++         _23 = const 82f32;
+          StorageLive(_24);
+          _37 = deref_copy (*_26);
+-         _24 = ((*_37).1: std::option::Option<S>);
++         _24 = const Option::<S>::Some(S(35_i32));
+          StorageLive(_25);
+          _38 = deref_copy (*_26);
+          _25 = ((*_38).2: &[f32]);
+          StorageDead(_26);
+          StorageLive(_27);
+          StorageLive(_28);
+-         _28 = _23;
++         _28 = const 82f32;
+          StorageLive(_29);
+-         _29 = _24;
++         _29 = const Option::<S>::Some(S(35_i32));
+          StorageLive(_30);
+          _30 = _25;
+-         _27 = BigStruct(move _28, move _29, move _30);
++         _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
+          StorageDead(_30);
+          StorageDead(_29);
+          StorageDead(_28);
           _0 = const ();
+          StorageDead(_27);
+          StorageDead(_25);
+          StorageDead(_24);
+          StorageDead(_23);
+          StorageDead(_21);
+          StorageDead(_20);
+          StorageDead(_19);
           StorageDead(_15);
-          StorageDead(_14);
           StorageDead(_13);
           StorageDead(_12);
-          StorageDead(_10);
+          StorageDead(_11);
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_7);
@@ -117,13 +197,51 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC6 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC7 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC8 (size: 8, align: 4) {
++     01 00 00 00 23 00 00 00                         │ ....#...
++ }
++ 
++ ALLOC9 (size: 8, align: 4) {
++     01 00 00 00 01 00 00 00                         │ ........
++ }
++ 
++ ALLOC10 (size: 4, align: 4) {
++     01 00 00 00                                     │ ....
   }
   
-  ALLOC1 (static: STAT, size: 8, align: 8) {
+  ALLOC5 (static: BIG_STAT, size: 8, align: 8) {
       ╾ALLOC0╼                         │ ╾──────╼
   }
   
-  ALLOC0 (size: 16, align: 4) {
-      01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░
+  ALLOC0 (size: 32, align: 8) {
+      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼
+      0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........B░░░░
+  }
+  
+  ALLOC1 (size: 8, align: 4) {
+      00 00 34 42 00 00 90 42                         │ ..4B...B
+  }
+  
+  ALLOC4 (static: SMALL_STAT, size: 8, align: 8) {
+      ╾ALLOC2╼                         │ ╾──────╼
+  }
+  
+  ALLOC2 (size: 32, align: 8) {
+      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼
+      0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........A░░░░
+  }
+  
+  ALLOC3 (size: 4, align: 4) {
+      00 00 50 41                                     │ ..PA
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs
index 7b0646a5356..043981a2954 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.rs
+++ b/tests/mir-opt/dataflow-const-prop/struct.rs
@@ -6,7 +6,10 @@
 struct S(i32);
 
 #[derive(Copy, Clone)]
-struct BigStruct(S, u8, f32, S);
+struct SmallStruct(f32, Option<S>, &'static [f32]);
+
+#[derive(Copy, Clone)]
+struct BigStruct(f32, Option<S>, &'static [f32]);
 
 // EMIT_MIR struct.main.DataflowConstProp.diff
 fn main() {
@@ -15,9 +18,21 @@ fn main() {
     s.0 = 3;
     let b = a + s.0;
 
-    const VAL: BigStruct = BigStruct(S(1), 5, 7., S(13));
-    let BigStruct(a, b, c, d) = VAL;
+    const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]);
+    let SmallStruct(a, b, c) = SMALL_VAL;
+
+    static SMALL_STAT: &SmallStruct = &SmallStruct(9., None, &[13.]);
+    let SmallStruct(a, b, c) = *SMALL_STAT;
+
+    let ss = SmallStruct(a, b, c);
+
+    const BIG_VAL: BigStruct = BigStruct(25., None, &[]);
+    let BigStruct(a, b, c) = BIG_VAL;
+
+    static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]);
+    let BigStruct(a, b, c) = *BIG_STAT;
 
-    static STAT: &BigStruct = &BigStruct(S(1), 5, 7., S(13));
-    let BigStruct(a, b, c, d) = *STAT;
+    // We arbitrarily limit the size of synthetized values to 4 pointers.
+    // `BigStruct` can be read, but we will keep a MIR aggregate for this.
+    let bs = BigStruct(a, b, c);
 }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.rs b/tests/mir-opt/dataflow-const-prop/transmute.rs
index 02e4f1e5013..bb85e458678 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.rs
+++ b/tests/mir-opt/dataflow-const-prop/transmute.rs
@@ -52,8 +52,8 @@ pub unsafe fn undef_union_as_integer() -> u32 {
 // EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff
 pub unsafe fn unreachable_direct() -> ! {
     // CHECK-LABEL: fn unreachable_direct(
-    // CHECK: [[unit:_.*]] = ();
-    // CHECK: move [[unit]] as Never (Transmute);
+    // CHECK: = const ();
+    // CHECK: = const ZeroSized: Never;
     let x: Never = unsafe { transmute(()) };
     match x {}
 }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
index fc0634b1f8f..fb28aa8f6d9 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
@@ -11,8 +11,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = Union32 { value: move _2 };
+-         _2 = ();
+-         _1 = Union32 { value: move _2 };
++         _2 = const ();
++         _1 = Union32 { value: const () };
           StorageDead(_2);
           _0 = move _1 as u32 (Transmute);
           StorageDead(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
index fc0634b1f8f..fb28aa8f6d9 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
@@ -11,8 +11,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = Union32 { value: move _2 };
+-         _2 = ();
+-         _1 = Union32 { value: move _2 };
++         _2 = const ();
++         _1 = Union32 { value: const () };
           StorageDead(_2);
           _0 = move _1 as u32 (Transmute);
           StorageDead(_1);
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
index acbb5cd1bc7..c8d4d6edba1 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
@@ -14,8 +14,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = move _2 as Never (Transmute);
+-         _2 = ();
+-         _1 = move _2 as Never (Transmute);
++         _2 = const ();
++         _1 = const ZeroSized: Never;
           unreachable;
       }
   }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
index acbb5cd1bc7..c8d4d6edba1 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
@@ -14,8 +14,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = move _2 as Never (Transmute);
+-         _2 = ();
+-         _1 = move _2 as Never (Transmute);
++         _2 = const ();
++         _1 = const ZeroSized: Never;
           unreachable;
       }
   }
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff
index 5e385d21ec6..f5723cac7d9 100644
--- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff
@@ -11,6 +11,9 @@
       let mut _8: i32;
       let mut _9: i32;
       let mut _10: i32;
+      let mut _12: i32;
+      let mut _13: (i32, i32);
+      let mut _14: i32;
       scope 1 {
           debug a => _1;
           let _2: i32;
@@ -19,13 +22,18 @@
               let _6: i32;
               scope 3 {
                   debug c => _6;
+                  let _11: (i32, (i32, i32), i32);
+                  scope 4 {
+                      debug d => _11;
+                  }
               }
           }
       }
   
       bb0: {
           StorageLive(_1);
-          _1 = (const 1_i32, const 2_i32);
+-         _1 = (const 1_i32, const 2_i32);
++         _1 = const (1_i32, 2_i32);
           StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
@@ -41,7 +49,8 @@
 -         _2 = Add(move _3, const 3_i32);
 +         _2 = const 6_i32;
           StorageDead(_3);
-          _1 = (const 2_i32, const 3_i32);
+-         _1 = (const 2_i32, const 3_i32);
++         _1 = const (2_i32, 3_i32);
           StorageLive(_6);
           StorageLive(_7);
           StorageLive(_8);
@@ -61,11 +70,43 @@
 +         _6 = const 11_i32;
           StorageDead(_10);
           StorageDead(_7);
+          StorageLive(_11);
+          StorageLive(_12);
+-         _12 = _2;
++         _12 = const 6_i32;
+          StorageLive(_13);
+-         _13 = _1;
++         _13 = const (2_i32, 3_i32);
+          StorageLive(_14);
+-         _14 = _6;
+-         _11 = (move _12, move _13, move _14);
++         _14 = const 11_i32;
++         _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
           _0 = const ();
+          StorageDead(_11);
           StorageDead(_6);
           StorageDead(_2);
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC1 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC2 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC3 (size: 8, align: 4) {
++     01 00 00 00 02 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..f5723cac7d9
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff
@@ -0,0 +1,112 @@
+- // MIR for `main` before DataflowConstProp
++ // MIR for `main` after DataflowConstProp
+  
+  fn main() -> () {
+      let mut _0: ();
+      let mut _1: (i32, i32);
+      let mut _3: i32;
+      let mut _4: i32;
+      let mut _5: i32;
+      let mut _7: i32;
+      let mut _8: i32;
+      let mut _9: i32;
+      let mut _10: i32;
+      let mut _12: i32;
+      let mut _13: (i32, i32);
+      let mut _14: i32;
+      scope 1 {
+          debug a => _1;
+          let _2: i32;
+          scope 2 {
+              debug b => _2;
+              let _6: i32;
+              scope 3 {
+                  debug c => _6;
+                  let _11: (i32, (i32, i32), i32);
+                  scope 4 {
+                      debug d => _11;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = (const 1_i32, const 2_i32);
++         _1 = const (1_i32, 2_i32);
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+-         _4 = (_1.0: i32);
++         _4 = const 1_i32;
+          StorageLive(_5);
+-         _5 = (_1.1: i32);
+-         _3 = Add(move _4, move _5);
++         _5 = const 2_i32;
++         _3 = const 3_i32;
+          StorageDead(_5);
+          StorageDead(_4);
+-         _2 = Add(move _3, const 3_i32);
++         _2 = const 6_i32;
+          StorageDead(_3);
+-         _1 = (const 2_i32, const 3_i32);
++         _1 = const (2_i32, 3_i32);
+          StorageLive(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = (_1.0: i32);
++         _8 = const 2_i32;
+          StorageLive(_9);
+-         _9 = (_1.1: i32);
+-         _7 = Add(move _8, move _9);
++         _9 = const 3_i32;
++         _7 = const 5_i32;
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageLive(_10);
+-         _10 = _2;
+-         _6 = Add(move _7, move _10);
++         _10 = const 6_i32;
++         _6 = const 11_i32;
+          StorageDead(_10);
+          StorageDead(_7);
+          StorageLive(_11);
+          StorageLive(_12);
+-         _12 = _2;
++         _12 = const 6_i32;
+          StorageLive(_13);
+-         _13 = _1;
++         _13 = const (2_i32, 3_i32);
+          StorageLive(_14);
+-         _14 = _6;
+-         _11 = (move _12, move _13, move _14);
++         _14 = const 11_i32;
++         _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
+          _0 = const ();
+          StorageDead(_11);
+          StorageDead(_6);
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC1 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC2 (size: 8, align: 4) {
++     02 00 00 00 03 00 00 00                         │ ........
++ }
++ 
++ ALLOC3 (size: 8, align: 4) {
++     01 00 00 00 02 00 00 00                         │ ........
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs
index c63ce8b140f..bb706eafe88 100644
--- a/tests/mir-opt/dataflow-const-prop/tuple.rs
+++ b/tests/mir-opt/dataflow-const-prop/tuple.rs
@@ -1,5 +1,6 @@
 // skip-filecheck
 // unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR tuple.main.DataflowConstProp.diff
 fn main() {
@@ -7,4 +8,6 @@ fn main() {
     let b = a.0 + a.1 + 3;
     a = (2, 3);
     let c = a.0 + a.1 + b;
+
+    let d = (b, a, c);
 }
diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-abort.diff
deleted file mode 100644
index eac51000cac..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-abort.diff
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `inlined_no_sanitize` before Inline
-+ // MIR for `inlined_no_sanitize` after Inline
-  
-  fn inlined_no_sanitize() -> () {
-      let mut _0: ();
-      let _1: ();
-+     scope 1 (inlined no_sanitize) {
-+     }
-  
-      bb0: {
-          StorageLive(_1);
--         _1 = no_sanitize() -> [return: bb1, unwind unreachable];
--     }
-- 
--     bb1: {
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff
deleted file mode 100644
index eba5ad9cf26..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `inlined_no_sanitize` before Inline
-+ // MIR for `inlined_no_sanitize` after Inline
-  
-  fn inlined_no_sanitize() -> () {
-      let mut _0: ();
-      let _1: ();
-+     scope 1 (inlined no_sanitize) {
-+     }
-  
-      bb0: {
-          StorageLive(_1);
--         _1 = no_sanitize() -> [return: bb1, unwind continue];
--     }
-- 
--     bb1: {
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-abort.diff
deleted file mode 100644
index c2a81b9804e..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-abort.diff
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `inlined_target_feature` before Inline
-+ // MIR for `inlined_target_feature` after Inline
-  
-  fn inlined_target_feature() -> () {
-      let mut _0: ();
-      let _1: ();
-+     scope 1 (inlined target_feature) {
-+     }
-  
-      bb0: {
-          StorageLive(_1);
--         _1 = target_feature() -> [return: bb1, unwind unreachable];
--     }
-- 
--     bb1: {
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff
deleted file mode 100644
index 24457819b2c..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `inlined_target_feature` before Inline
-+ // MIR for `inlined_target_feature` after Inline
-  
-  fn inlined_target_feature() -> () {
-      let mut _0: ();
-      let _1: ();
-+     scope 1 (inlined target_feature) {
-+     }
-  
-      bb0: {
-          StorageLive(_1);
--         _1 = target_feature() -> [return: bb1, unwind continue];
--     }
-- 
--     bb1: {
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-abort.diff
deleted file mode 100644
index 791c5a0f29f..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-abort.diff
+++ /dev/null
@@ -1,22 +0,0 @@
-- // MIR for `not_inlined_c_variadic` before Inline
-+ // MIR for `not_inlined_c_variadic` after Inline
-  
-  fn not_inlined_c_variadic() -> () {
-      let mut _0: ();
-      let _1: u32;
-      scope 1 {
-          debug s => _1;
-      }
-  
-      bb0: {
-          StorageLive(_1);
-          _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> [return: bb1, unwind unreachable];
-      }
-  
-      bb1: {
-          _0 = const ();
-          StorageDead(_1);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff
deleted file mode 100644
index 364acab6d93..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,22 +0,0 @@
-- // MIR for `not_inlined_c_variadic` before Inline
-+ // MIR for `not_inlined_c_variadic` after Inline
-  
-  fn not_inlined_c_variadic() -> () {
-      let mut _0: ();
-      let _1: u32;
-      scope 1 {
-          debug s => _1;
-      }
-  
-      bb0: {
-          StorageLive(_1);
-          _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> [return: bb1, unwind continue];
-      }
-  
-      bb1: {
-          _0 = const ();
-          StorageDead(_1);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-abort.diff
deleted file mode 100644
index b9d0946b7c3..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-abort.diff
+++ /dev/null
@@ -1,19 +0,0 @@
-- // MIR for `not_inlined_no_sanitize` before Inline
-+ // MIR for `not_inlined_no_sanitize` after Inline
-  
-  fn not_inlined_no_sanitize() -> () {
-      let mut _0: ();
-      let _1: ();
-  
-      bb0: {
-          StorageLive(_1);
-          _1 = no_sanitize() -> [return: bb1, unwind unreachable];
-      }
-  
-      bb1: {
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff
deleted file mode 100644
index 965b7ddca32..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,19 +0,0 @@
-- // MIR for `not_inlined_no_sanitize` before Inline
-+ // MIR for `not_inlined_no_sanitize` after Inline
-  
-  fn not_inlined_no_sanitize() -> () {
-      let mut _0: ();
-      let _1: ();
-  
-      bb0: {
-          StorageLive(_1);
-          _1 = no_sanitize() -> [return: bb1, unwind continue];
-      }
-  
-      bb1: {
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-abort.diff
deleted file mode 100644
index 7c689a73482..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-abort.diff
+++ /dev/null
@@ -1,19 +0,0 @@
-- // MIR for `not_inlined_target_feature` before Inline
-+ // MIR for `not_inlined_target_feature` after Inline
-  
-  fn not_inlined_target_feature() -> () {
-      let mut _0: ();
-      let _1: ();
-  
-      bb0: {
-          StorageLive(_1);
-          _1 = target_feature() -> [return: bb1, unwind unreachable];
-      }
-  
-      bb1: {
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff
deleted file mode 100644
index bcdbd6e3314..00000000000
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff
+++ /dev/null
@@ -1,19 +0,0 @@
-- // MIR for `not_inlined_target_feature` before Inline
-+ // MIR for `not_inlined_target_feature` after Inline
-  
-  fn not_inlined_target_feature() -> () {
-      let mut _0: ();
-      let _1: ();
-  
-      bb0: {
-          StorageLive(_1);
-          _1 = target_feature() -> [return: bb1, unwind continue];
-      }
-  
-      bb1: {
-          StorageDead(_1);
-          _0 = const ();
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/inline/inline_compatibility.rs b/tests/mir-opt/inline/inline_compatibility.rs
index 52f4debf5db..3ad880715fe 100644
--- a/tests/mir-opt/inline/inline_compatibility.rs
+++ b/tests/mir-opt/inline/inline_compatibility.rs
@@ -1,51 +1,71 @@
-// skip-filecheck
 // Checks that only functions with compatible attributes are inlined.
-//
 // only-x86_64
-// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// compile-flags: -Cpanic=abort
 
 #![crate_type = "lib"]
 #![feature(no_sanitize)]
 #![feature(target_feature_11)]
 #![feature(c_variadic)]
 
-// EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff
+#[inline]
+#[target_feature(enable = "sse2")]
+unsafe fn sse2() {}
+
+#[inline]
+fn nop() {}
+
+// CHECK-LABEL: fn f0()
+// CHECK:       bb0: {
+// CHECK-NEXT:  return;
 #[target_feature(enable = "sse2")]
-pub unsafe fn inlined_target_feature() {
-    target_feature();
+pub unsafe fn f0() {
+    sse2();
 }
 
-// EMIT_MIR inline_compatibility.not_inlined_target_feature.Inline.diff
-pub unsafe fn not_inlined_target_feature() {
-    target_feature();
+// CHECK-LABEL: fn f1()
+// CHECK:       bb0: {
+// CHECK-NEXT:  sse2()
+pub unsafe fn f1() {
+    sse2();
 }
 
-// EMIT_MIR inline_compatibility.inlined_no_sanitize.Inline.diff
+// CHECK-LABEL: fn f2()
+// CHECK:       bb0: {
+// CHECK-NEXT:  nop()
+#[target_feature(enable = "avx")]
+pub unsafe fn f2() {
+    nop();
+}
+
+#[inline]
+#[no_sanitize(address)]
+pub unsafe fn no_sanitize() {}
+
+// CHECK-LABEL: fn inlined_no_sanitize()
+// CHECK:       bb0: {
+// CHECK-NEXT:  return;
 #[no_sanitize(address)]
 pub unsafe fn inlined_no_sanitize() {
     no_sanitize();
 }
 
-// EMIT_MIR inline_compatibility.not_inlined_no_sanitize.Inline.diff
+// CHECK-LABEL: fn not_inlined_no_sanitize()
+// CHECK:       bb0: {
+// CHECK-NEXT:  no_sanitize()
 pub unsafe fn not_inlined_no_sanitize() {
     no_sanitize();
 }
 
-#[inline]
-#[target_feature(enable = "sse2")]
-pub unsafe fn target_feature() {}
-
-#[inline]
-#[no_sanitize(address)]
-pub unsafe fn no_sanitize() {}
-
-// EMIT_MIR inline_compatibility.not_inlined_c_variadic.Inline.diff
+// CHECK-LABEL: fn not_inlined_c_variadic()
+// CHECK:       bb0: {
+// CHECK-NEXT:  StorageLive(_1)
+// CHECK-NEXT:  _1 = sum
 pub unsafe fn not_inlined_c_variadic() {
-    let s = sum(4u32, 4u32, 30u32, 200u32, 1000u32);
+    let _ = sum(4u32, 4u32, 30u32, 200u32, 1000u32);
 }
 
-#[no_mangle]
 #[inline(always)]
+#[no_mangle]
 unsafe extern "C" fn sum(n: u32, mut vs: ...) -> u32 {
     let mut s = 0;
     let mut i = 0;
diff --git a/tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff b/tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff
index 1c417d4346d..9e1bce1ee20 100644
--- a/tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff
+++ b/tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff
@@ -6,22 +6,27 @@
       let mut _0: *const &u8;
       let mut _2: *const &u8;
       let mut _3: *const &u8;
+      let mut _4: *const &u8;
       scope 1 (inlined generic_cast::<&u8, &u8>) {
-          debug x => _3;
-          let mut _4: *const &u8;
+          debug x => _4;
+          let mut _5: *const &u8;
       }
   
       bb0: {
           StorageLive(_2);
           StorageLive(_3);
-          _3 = _1;
           StorageLive(_4);
-          _4 = _3;
--         _2 = move _4 as *const &u8 (PtrToPtr);
-+         _2 = move _4;
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _4;
+-         _3 = move _5 as *const &u8 (PtrToPtr);
++         _3 = move _5;
+          StorageDead(_5);
           StorageDead(_4);
-          StorageDead(_3);
+-         _2 = move _3 as *const &u8 (PtrToPtr);
++         _2 = move _3;
           _0 = _2;
+          StorageDead(_3);
           StorageDead(_2);
           return;
       }
diff --git a/tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff b/tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff
index 1ae9d45e66c..a6d68cd4e4b 100644
--- a/tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff
+++ b/tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff
@@ -4,16 +4,21 @@
   fn roundtrip(_1: *const u8) -> *const u8 {
       debug x => _1;
       let mut _0: *const u8;
-      let mut _2: *mut u8;
-      let mut _3: *const u8;
+      let mut _2: *const u8;
+      let mut _3: *mut u8;
+      let mut _4: *const u8;
   
       bb0: {
           StorageLive(_2);
           StorageLive(_3);
-          _3 = _1;
-          _2 = move _3 as *mut u8 (PtrToPtr);
-          _0 = move _2 as *const u8 (PointerCoercion(MutToConstPointer));
+          StorageLive(_4);
+          _4 = _1;
+          _3 = move _4 as *mut u8 (PtrToPtr);
+          _2 = move _3 as *const u8 (PointerCoercion(MutToConstPointer));
+          StorageDead(_4);
           StorageDead(_3);
+-         _0 = move _2 as *const u8 (PtrToPtr);
++         _0 = move _2;
           StorageDead(_2);
           return;
       }
diff --git a/tests/mir-opt/instsimplify/casts.rs b/tests/mir-opt/instsimplify/casts.rs
index 18bab524c64..86f9b34ea04 100644
--- a/tests/mir-opt/instsimplify/casts.rs
+++ b/tests/mir-opt/instsimplify/casts.rs
@@ -18,8 +18,8 @@ pub fn redundant<'a, 'b: 'a>(x: *const &'a u8) -> *const &'a u8 {
 // EMIT_MIR casts.roundtrip.InstSimplify.diff
 pub fn roundtrip(x: *const u8) -> *const u8 {
     // CHECK-LABEL: fn roundtrip(
-    // CHECK: _3 = _1;
-    // CHECK: _2 = move _3 as *mut u8 (PtrToPtr);
-    // CHECK: _0 = move _2 as *const u8 (PointerCoercion(MutToConstPointer));
+    // CHECK: _4 = _1;
+    // CHECK: _3 = move _4 as *mut u8 (PtrToPtr);
+    // CHECK: _2 = move _3 as *const u8 (PointerCoercion(MutToConstPointer));
     x as *mut u8 as *const u8
 }
diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs
index 7ee46e1520a..71009d32477 100644
--- a/tests/run-make-fulldeps/issue-19371/foo.rs
+++ b/tests/run-make-fulldeps/issue-19371/foo.rs
@@ -62,6 +62,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         override_queries: None,
         make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
+        using_internal_features: std::sync::Arc::default(),
         expanded_args: Default::default(),
     };
 
diff --git a/tests/run-make/issue-96498/Makefile b/tests/run-make/issue-96498/Makefile
deleted file mode 100644
index efdd328c671..00000000000
--- a/tests/run-make/issue-96498/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# only-windows
-# needs-rust-lld
-
-include ../tools.mk
-
-# Ensure that LLD can link
-all:
-	$(RUSTC) -C linker=rust-lld foo.rs
diff --git a/tests/run-make/windows-safeseh/Makefile b/tests/run-make/windows-safeseh/Makefile
new file mode 100644
index 00000000000..d6a403961d7
--- /dev/null
+++ b/tests/run-make/windows-safeseh/Makefile
@@ -0,0 +1,19 @@
+# only-windows
+# needs-rust-lld
+
+include ../tools.mk
+
+all: foo bar
+
+# Ensure that LLD can link when an .rlib contains a synthetic object
+# file referencing exported or used symbols.
+foo:
+	$(RUSTC) -C linker=rust-lld foo.rs
+
+# Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib.
+# Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware.
+bar: baz
+	$(RUSTC) -C linker=rust-lld -C link-arg=/WHOLEARCHIVE:libbaz.rlib bar.rs
+
+baz:
+	$(RUSTC) baz.rs
diff --git a/tests/run-make/windows-safeseh/bar.rs b/tests/run-make/windows-safeseh/bar.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make/windows-safeseh/bar.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/windows-safeseh/baz.rs b/tests/run-make/windows-safeseh/baz.rs
new file mode 100644
index 00000000000..8d5b9dc5aea
--- /dev/null
+++ b/tests/run-make/windows-safeseh/baz.rs
@@ -0,0 +1,4 @@
+#![crate_type = "rlib"]
+
+#[no_mangle]
+extern "C" fn baz() {}
diff --git a/tests/run-make/issue-96498/foo.rs b/tests/run-make/windows-safeseh/foo.rs
index 93ac3641b09..93ac3641b09 100644
--- a/tests/run-make/issue-96498/foo.rs
+++ b/tests/run-make/windows-safeseh/foo.rs
diff --git a/tests/rustdoc/deprecated-future-staged-api.rs b/tests/rustdoc/deprecated-future-staged-api.rs
index 2670e7f5d04..09120b8d411 100644
--- a/tests/rustdoc/deprecated-future-staged-api.rs
+++ b/tests/rustdoc/deprecated-future-staged-api.rs
@@ -1,12 +1,12 @@
 #![feature(staged_api)]
-#![stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+#![stable(feature = "deprecated_future_staged_api", since = "1.0.0")]
 
 // @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
 //      'Deprecation planned'
 // @has deprecated_future_staged_api/struct.S1.html '//*[@class="stab deprecated"]' \
 //      'Deprecating in 99.99.99: effectively never'
 #[deprecated(since = "99.99.99", note = "effectively never")]
-#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+#[stable(feature = "deprecated_future_staged_api", since = "1.0.0")]
 pub struct S1;
 
 // @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
@@ -14,5 +14,5 @@ pub struct S1;
 // @has deprecated_future_staged_api/struct.S2.html '//*[@class="stab deprecated"]' \
 //      'Deprecating in a future Rust version: literally never'
 #[deprecated(since = "TBD", note = "literally never")]
-#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+#[stable(feature = "deprecated_future_staged_api", since = "1.0.0")]
 pub struct S2;
diff --git a/tests/rustdoc/html-no-source.rs b/tests/rustdoc/html-no-source.rs
index 25615a73c3f..b91aa41207a 100644
--- a/tests/rustdoc/html-no-source.rs
+++ b/tests/rustdoc/html-no-source.rs
@@ -11,20 +11,20 @@
 // @files 'src/foo' '[]'
 
 // @has foo/fn.foo.html
-// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
-// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
 #[stable(feature = "bar", since = "1.0")]
 pub fn foo() {}
 
 // @has foo/struct.Bar.html
-// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
-// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
 #[stable(feature = "bar", since = "1.0")]
 pub struct Bar;
 
 impl Bar {
-    // @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0'
-    // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
+    // @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0.0'
+    // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0.0 ·'
     #[stable(feature = "foobar", since = "2.0")]
     pub fn bar() {}
 }
diff --git a/tests/rustdoc/implementor-stable-version.rs b/tests/rustdoc/implementor-stable-version.rs
index a1f3fd5a8c5..9c5b9b7e303 100644
--- a/tests/rustdoc/implementor-stable-version.rs
+++ b/tests/rustdoc/implementor-stable-version.rs
@@ -1,21 +1,21 @@
-#![stable(feature = "bar", since = "OLD 1.0")]
+#![stable(feature = "bar", since = "3.3.3")]
 #![crate_name = "foo"]
 
 #![feature(staged_api)]
 
-#[stable(feature = "bar", since = "OLD 1.0")]
+#[stable(feature = "bar", since = "3.3.3")]
 pub trait Bar {}
 
-#[stable(feature = "baz", since = "OLD 1.0")]
+#[stable(feature = "baz", since = "3.3.3")]
 pub trait Baz {}
 
-#[stable(feature = "baz", since = "OLD 1.0")]
+#[stable(feature = "baz", since = "3.3.3")]
 pub struct Foo;
 
-// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0'
-#[stable(feature = "foobar", since = "NEW 2.0")]
+// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' '4.4.4'
+#[stable(feature = "foobar", since = "4.4.4")]
 impl Bar for Foo {}
 
-// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0'
-#[stable(feature = "foobaz", since = "OLD 1.0")]
+// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' '3.3.3'
+#[stable(feature = "foobaz", since = "3.3.3")]
 impl Baz for Foo {}
diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-version-separator.rs
index 14580373b3b..7256f731573 100644
--- a/tests/rustdoc/source-version-separator.rs
+++ b/tests/rustdoc/source-version-separator.rs
@@ -3,23 +3,23 @@
 #![feature(staged_api)]
 
 // @has foo/trait.Bar.html
-// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
 #[stable(feature = "bar", since = "1.0")]
 pub trait Bar {
-    // @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source'
+    // @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source'
     #[stable(feature = "foobar", since = "3.0")]
     fn foo();
 }
 
-// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0 · source'
+// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source'
 
 // @has foo/struct.Foo.html
-// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
 #[stable(feature = "baz", since = "1.0")]
 pub struct Foo;
 
 impl Foo {
-    // @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0 · source'
+    // @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · source'
     #[stable(feature = "foobar", since = "3.0")]
     pub fn foofoo() {}
 }
diff --git a/tests/rustdoc/version-separator-without-source.rs b/tests/rustdoc/version-separator-without-source.rs
index 04ea46a7f3a..4a855b7bb29 100644
--- a/tests/rustdoc/version-separator-without-source.rs
+++ b/tests/rustdoc/version-separator-without-source.rs
@@ -4,20 +4,20 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.foo.html
-// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
-// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
 #[stable(feature = "bar", since = "1.0")]
 pub fn foo() {}
 
 // @has foo/struct.Bar.html
-// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
-// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
 #[stable(feature = "bar", since = "1.0")]
 pub struct Bar;
 
 impl Bar {
-    // @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0'
-    // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
+    // @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0.0'
+    // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0.0 ·'
     #[stable(feature = "foobar", since = "2.0")]
     pub fn bar() {}
 }
diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs
index c6a9e08ed02..a340877752d 100644
--- a/tests/ui-fulldeps/stable-mir/check_instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -1,5 +1,5 @@
 // run-pass
-// Test that users are able to use stable mir APIs to retrieve monomorphized instances
+//! Test that users are able to use stable mir APIs to retrieve monomorphized instances
 
 // ignore-stage1
 // ignore-cross-compile
@@ -14,15 +14,15 @@
 extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_smir;
-extern crate stable_mir;
 extern crate rustc_driver;
 extern crate rustc_interface;
+extern crate stable_mir;
 
-use rustc_middle::ty::TyCtxt;
 use mir::{mono::Instance, TerminatorKind::*};
-use stable_mir::ty::{TyKind, RigidTy};
-use stable_mir::*;
+use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
+use stable_mir::ty::{RigidTy, TyKind};
+use stable_mir::*;
 use std::io::Write;
 use std::ops::ControlFlow;
 
@@ -33,16 +33,16 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     let items = stable_mir::all_local_items();
 
     // Get all items and split generic vs monomorphic items.
-    let (generic, mono) : (Vec<_>, Vec<_>) = items.into_iter().partition(|item| {
-        item.requires_monomorphization()
-    });
+    let (generic, mono): (Vec<_>, Vec<_>) =
+        items.into_iter().partition(|item| item.requires_monomorphization());
     assert_eq!(mono.len(), 3, "Expected 2 mono functions and one constant");
     assert_eq!(generic.len(), 2, "Expected 2 generic functions");
 
     // For all monomorphic items, get the correspondent instances.
-    let instances = mono.iter().filter_map(|item| {
-        mir::mono::Instance::try_from(*item).ok()
-    }).collect::<Vec<mir::mono::Instance>>();
+    let instances = mono
+        .iter()
+        .filter_map(|item| mir::mono::Instance::try_from(*item).ok())
+        .collect::<Vec<mir::mono::Instance>>();
     assert_eq!(instances.len(), mono.len());
 
     // For all generic items, try_from should fail.
@@ -58,19 +58,22 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
 fn test_body(body: mir::Body) {
     for term in body.blocks.iter().map(|bb| &bb.terminator) {
         match &term.kind {
-            Call{ func, .. } => {
-                let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
+            Call { func, .. } => {
+                let TyKind::RigidTy(ty) = func.ty(body.locals()).kind() else { unreachable!() };
                 let RigidTy::FnDef(def, args) = ty else { unreachable!() };
                 let result = Instance::resolve(def, &args);
                 assert!(result.is_ok());
             }
-            Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */}
-            _ => { unreachable!("Unexpected terminator {term:?}") }
+            Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => {
+                /* Do nothing */
+            }
+            _ => {
+                unreachable!("Unexpected terminator {term:?}")
+            }
         }
     }
 }
 
-
 /// This test will generate and analyze a dummy crate using the stable mir.
 /// For that, it will first write the dummy crate into a file.
 /// Then it will create a `StableMir` using custom arguments and then
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index 3cb71b5a025..ed6b786f5e1 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -22,8 +22,8 @@ extern crate stable_mir;
 use rustc_hir::def::DefKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
-
-use stable_mir::fold::Foldable;
+use stable_mir::mir::mono::Instance;
+use stable_mir::ty::{RigidTy, TyKind};
 use std::assert_matches::assert_matches;
 use std::io::Write;
 use std::ops::ControlFlow;
@@ -47,7 +47,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
 
     let bar = get_item(&items, (DefKind::Fn, "bar")).unwrap();
     let body = bar.body();
-    assert_eq!(body.locals.len(), 2);
+    assert_eq!(body.locals().len(), 2);
     assert_eq!(body.blocks.len(), 1);
     let block = &body.blocks[0];
     assert_eq!(block.statements.len(), 1);
@@ -62,7 +62,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
 
     let foo_bar = get_item(&items, (DefKind::Fn, "foo_bar")).unwrap();
     let body = foo_bar.body();
-    assert_eq!(body.locals.len(), 5);
+    assert_eq!(body.locals().len(), 5);
     assert_eq!(body.blocks.len(), 4);
     let block = &body.blocks[0];
     match &block.terminator.kind {
@@ -72,29 +72,29 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
 
     let types = get_item(&items, (DefKind::Fn, "types")).unwrap();
     let body = types.body();
-    assert_eq!(body.locals.len(), 6);
+    assert_eq!(body.locals().len(), 6);
     assert_matches!(
-        body.locals[0].ty.kind(),
+        body.locals()[0].ty.kind(),
         stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
     );
     assert_matches!(
-        body.locals[1].ty.kind(),
+        body.locals()[1].ty.kind(),
         stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
     );
     assert_matches!(
-        body.locals[2].ty.kind(),
+        body.locals()[2].ty.kind(),
         stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char)
     );
     assert_matches!(
-        body.locals[3].ty.kind(),
+        body.locals()[3].ty.kind(),
         stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32))
     );
     assert_matches!(
-        body.locals[4].ty.kind(),
+        body.locals()[4].ty.kind(),
         stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64))
     );
     assert_matches!(
-        body.locals[5].ty.kind(),
+        body.locals()[5].ty.kind(),
         stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Float(
             stable_mir::ty::FloatTy::F64
         ))
@@ -119,40 +119,18 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     }
 
     let monomorphic = get_item(&items, (DefKind::Fn, "monomorphic")).unwrap();
-    for block in monomorphic.body().blocks {
+    let instance = Instance::try_from(monomorphic.clone()).unwrap();
+    for block in instance.body().blocks {
         match &block.terminator.kind {
-            stable_mir::mir::TerminatorKind::Call { func, .. } => match func {
-                stable_mir::mir::Operand::Constant(c) => match &c.literal.literal {
-                    stable_mir::ty::ConstantKind::Allocated(alloc) => {
-                        assert!(alloc.bytes.is_empty());
-                        match c.literal.ty.kind() {
-                            stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::FnDef(
-                                def,
-                                mut args,
-                            )) => {
-                                let func = def.body();
-                                match func.locals[1].ty
-                                    .fold(&mut args)
-                                    .continue_value()
-                                    .unwrap()
-                                    .kind()
-                                {
-                                    stable_mir::ty::TyKind::RigidTy(
-                                        stable_mir::ty::RigidTy::Uint(_),
-                                    ) => {}
-                                    stable_mir::ty::TyKind::RigidTy(
-                                        stable_mir::ty::RigidTy::Tuple(_),
-                                    ) => {}
-                                    other => panic!("{other:?}"),
-                                }
-                            }
-                            other => panic!("{other:?}"),
-                        }
-                    }
+            stable_mir::mir::TerminatorKind::Call { func, .. } => {
+                let TyKind::RigidTy(ty) = func.ty(&body.locals()).kind() else { unreachable!() };
+                let RigidTy::FnDef(def, args) = ty else { unreachable!() };
+                let next_func = Instance::resolve(def, &args).unwrap();
+                match next_func.body().locals()[1].ty.kind() {
+                    TyKind::RigidTy(RigidTy::Uint(_)) | TyKind::RigidTy(RigidTy::Tuple(_)) => {}
                     other => panic!("{other:?}"),
-                },
-                other => panic!("{other:?}"),
-            },
+                }
+            }
             stable_mir::mir::TerminatorKind::Return => {}
             other => panic!("{other:?}"),
         }
@@ -162,6 +140,29 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     // Ensure we don't panic trying to get the body of a constant.
     foo_const.body();
 
+    let locals_fn = get_item(&items, (DefKind::Fn, "locals")).unwrap();
+    let body = locals_fn.body();
+    assert_eq!(body.locals().len(), 4);
+    assert_matches!(
+        body.ret_local().ty.kind(),
+        stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char)
+    );
+    assert_eq!(body.arg_locals().len(), 2);
+    assert_matches!(
+        body.arg_locals()[0].ty.kind(),
+        stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32))
+    );
+    assert_matches!(
+        body.arg_locals()[1].ty.kind(),
+        stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64))
+    );
+    assert_eq!(body.inner_locals().len(), 1);
+    // If conditions have an extra inner local to hold their results
+    assert_matches!(
+        body.inner_locals()[0].ty.kind(),
+        stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
+    );
+
     ControlFlow::Continue(())
 }
 
@@ -233,6 +234,14 @@ fn generate_input(path: &str) -> std::io::Result<()> {
 
     pub fn assert(x: i32) -> i32 {{
         x + 1
+    }}
+
+    pub fn locals(a: i32, _: u64) -> char {{
+        if a > 5 {{
+            'a'
+        }} else {{
+            'b'
+        }}
     }}"#
     )?;
     Ok(())
diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs
new file mode 100644
index 00000000000..b0596b18823
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs
@@ -0,0 +1,64 @@
+// run-pass
+//! Test that users are able to use retrieve internal constructs from stable ones to help with
+//! the migration.
+
+// ignore-stage1
+// ignore-cross-compile
+// ignore-remote
+// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+// edition: 2021
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate rustc_middle;
+extern crate stable_mir;
+
+use rustc_middle::ty::TyCtxt;
+use rustc_smir::rustc_internal;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+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;
+    let rustc_ty = rustc_internal::internal(&orig_ty);
+    assert!(rustc_ty.is_unit());
+    ControlFlow::Continue(())
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "internal_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, tcx, test_translation(tcx)).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+    pub fn main() {{
+    }}
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
index 1f049b1785a..0cdf229711a 100644
--- a/tests/ui/abi/compatibility.rs
+++ b/tests/ui/abi/compatibility.rs
@@ -30,6 +30,7 @@
 // revisions: loongarch64
 //[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
 //[loongarch64] needs-llvm-components: loongarch
+//[loongarch64] min-llvm-version: 17
 // revisions: wasm
 //[wasm] compile-flags: --target wasm32-unknown-unknown
 //[wasm] needs-llvm-components: webassembly
diff --git a/tests/ui/associated-consts/issue-105330.rs b/tests/ui/associated-consts/issue-105330.rs
index 285e89cce49..6c6dae864f3 100644
--- a/tests/ui/associated-consts/issue-105330.rs
+++ b/tests/ui/associated-consts/issue-105330.rs
@@ -14,5 +14,6 @@ fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
 
 fn main<A: TraitWAssocConst<A=32>>() {
     //~^ ERROR E0658
+    //~| ERROR E0131
     foo::<Demo>();
 }
diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr
index 55207909f7a..aeedf6b1949 100644
--- a/tests/ui/associated-consts/issue-105330.stderr
+++ b/tests/ui/associated-consts/issue-105330.stderr
@@ -39,7 +39,13 @@ error[E0562]: `impl Trait` only allowed in function and inherent method argument
 LL | impl TraitWAssocConst for impl Demo {
    |                           ^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error[E0131]: `main` function is not allowed to have generic parameters
+  --> $DIR/issue-105330.rs:15:8
+   |
+LL | fn main<A: TraitWAssocConst<A=32>>() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
+
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0404, E0562, E0658.
-For more information about an error, try `rustc --explain E0404`.
+Some errors have detailed explanations: E0131, E0404, E0562, E0658.
+For more information about an error, try `rustc --explain E0131`.
diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr b/tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr
index 464b59c249f..0620725ca33 100644
--- a/tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr
+++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr
@@ -10,6 +10,18 @@ note: required by a bound in `Ty::Pr`
 LL |     type Pr<T: Copy> = T;
    |                ^^^^ required by this bound in `Ty::Pr`
 
-error: aborting due to previous error
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/generic-associated-types-bad.rs:16:27
+   |
+LL | const _: Ty::Pr<String> = String::new();
+   |                           ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+note: required by a bound in `Ty::Pr`
+  --> $DIR/generic-associated-types-bad.rs:10:16
+   |
+LL |     type Pr<T: Copy> = T;
+   |                ^^^^ required by this bound in `Ty::Pr`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr b/tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr
index 4f371b24e80..fcf828c21c7 100644
--- a/tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr
+++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Vec<()>: Copy` is not satisfied
-  --> $DIR/generic-associated-types-bad.rs:20:12
+  --> $DIR/generic-associated-types-bad.rs:21:12
    |
 LL |     let _: Ty::Pr<Vec<()>>;
    |            ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Vec<()>`
diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr b/tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr
index 74ec39424ed..94c20521857 100644
--- a/tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr
+++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/generic-associated-types-bad.rs:25:12
+  --> $DIR/generic-associated-types-bad.rs:26:12
    |
 LL | fn user<'a>() {
    |         -- lifetime `'a` defined here
diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.rs b/tests/ui/associated-inherent-types/generic-associated-types-bad.rs
index e66392a0a94..f5deec422f5 100644
--- a/tests/ui/associated-inherent-types/generic-associated-types-bad.rs
+++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.rs
@@ -14,6 +14,7 @@ impl Ty {
 
 #[cfg(item)]
 const _: Ty::Pr<String> = String::new(); //[item]~ the trait bound `String: Copy` is not satisfied
+//[item]~^ the trait bound `String: Copy` is not satisfied
 
 fn main() {
     #[cfg(local)]
diff --git a/tests/ui/associated-types/associated-types-no-suitable-supertrait.rs b/tests/ui/associated-types/associated-types-no-suitable-supertrait.rs
index c373c5855cd..cc0101d63cf 100644
--- a/tests/ui/associated-types/associated-types-no-suitable-supertrait.rs
+++ b/tests/ui/associated-types/associated-types-no-suitable-supertrait.rs
@@ -21,6 +21,7 @@ trait Other {
 impl<T:Get> Other for T {
     fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
     //~^ ERROR the trait bound `(T, U): Get` is not satisfied
+    //~| ERROR the trait bound `(T, U): Get` is not satisfied
 }
 
 fn main() { }
diff --git a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
index b3f2e16ba0d..9ebc45387e8 100644
--- a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
+++ b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr
@@ -21,6 +21,18 @@ help: consider further restricting `Self`
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
    |                                                              +++++++++++++++
 
-error: aborting due to 2 previous errors
+error[E0277]: the trait bound `(T, U): Get` is not satisfied
+  --> $DIR/associated-types-no-suitable-supertrait.rs:22:5
+   |
+LL |     fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/associated-types-no-suitable-supertrait.rs:12:1
+   |
+LL | trait Get {
+   | ^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-await-let-else.stderr b/tests/ui/async-await/async-await-let-else.stderr
index c3b4e761824..b360aab6b59 100644
--- a/tests/ui/async-await/async-await-let-else.stderr
+++ b/tests/ui/async-await/async-await-let-else.stderr
@@ -30,7 +30,7 @@ LL |     is_send(foo2(Some(true)));
    |     required by a bound introduced by this call
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/async-await-let-else.rs:24:29
    |
 LL |   async fn bar2<T>(_: T) -> ! {
@@ -39,7 +39,7 @@ LL | |     panic!()
 LL | | }
    | |_^
    = note: required because it captures the following types: `impl Future<Output = !>`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/async-await-let-else.rs:18:32
    |
 LL |   async fn foo2(x: Option<bool>) {
diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr b/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr
index 2114fb59ba3..f9e5bf675cb 100644
--- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr
+++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr
@@ -23,7 +23,7 @@ LL |     S::f();
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/async-unsafe-fn-call-in-safe.rs:24:5
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:26:5
    |
 LL |     f();
    |     ^^^ call to unsafe function
diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs b/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs
index c941dc27aa3..14cc0dc614f 100644
--- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs
+++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs
@@ -20,6 +20,10 @@ async fn g() {
 }
 
 fn main() {
-    S::f(); //[mir]~ ERROR call to unsafe function is unsafe
-    f(); //[mir]~ ERROR call to unsafe function is unsafe
+    S::f();
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `S::f` is unsafe
+    f();
+    //[mir]~^ ERROR call to unsafe function is unsafe
+    //[thir]~^^ ERROR call to unsafe function `f` is unsafe
 }
diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr b/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
index 68d97d3fd7d..ba3303fe793 100644
--- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
+++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
@@ -14,6 +14,22 @@ LL |     f();
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error: aborting due to 2 previous errors
+error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:23:5
+   |
+LL |     S::f();
+   |     ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
+  --> $DIR/async-unsafe-fn-call-in-safe.rs:26:5
+   |
+LL |     f();
+   |     ^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
index 3cc11d241f7..c26f6625f00 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 use std::pin::Pin;
 
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
index e6dd83b6b0a..b70b36adb4a 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
@@ -1,11 +1,11 @@
 error[E0053]: method `foo` has an incompatible type for trait
-  --> $DIR/async-example-desugared-boxed-in-trait.rs:13:5
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:11:5
    |
 LL |     async fn foo(&self) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
    |
 note: type in trait
-  --> $DIR/async-example-desugared-boxed-in-trait.rs:9:22
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:7:22
    |
 LL |     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
index 81d25ce27ae..c5a9841029e 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 use std::pin::Pin;
 
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr
index cd18790fdfb..6392ce86e4a 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr
@@ -1,5 +1,5 @@
 error: method `foo` should be async because the method from the trait is async
-  --> $DIR/async-example-desugared-boxed.rs:13:5
+  --> $DIR/async-example-desugared-boxed.rs:11:5
    |
 LL |     async fn foo(&self) -> i32;
    |     --------------------------- required because the trait method is async
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
index f0c59180fb5..ce93bd62608 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs
@@ -2,7 +2,6 @@
 // edition: 2021
 
 #![feature(lint_reasons)]
-#![allow(incomplete_features)]
 
 use std::future::Future;
 use std::pin::Pin;
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
index deca28af853..f7a351efff5 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 
 trait MyTrait {
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
index fdba4d93c77..c287b9a5b84 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 use std::task::Poll;
 
diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr
index 463892f21bf..1eda6fe6532 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr
+++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr
@@ -1,5 +1,5 @@
 error: method `foo` should be async because the method from the trait is async
-  --> $DIR/async-example-desugared-manual.rs:21:5
+  --> $DIR/async-example-desugared-manual.rs:19:5
    |
 LL |     async fn foo(&self) -> i32;
    |     --------------------------- required because the trait method is async
diff --git a/tests/ui/async-await/in-trait/async-example-desugared.rs b/tests/ui/async-await/in-trait/async-example-desugared.rs
index 7fc78f7da6d..78904d87abc 100644
--- a/tests/ui/async-await/in-trait/async-example-desugared.rs
+++ b/tests/ui/async-await/in-trait/async-example-desugared.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::future::Future;
 
 trait MyTrait {
diff --git a/tests/ui/async-await/in-trait/async-example.rs b/tests/ui/async-await/in-trait/async-example.rs
index 62ed490bf05..a32f979df6b 100644
--- a/tests/ui/async-await/in-trait/async-example.rs
+++ b/tests/ui/async-await/in-trait/async-example.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait {
     #[allow(async_fn_in_trait)]
     async fn foo(&self) -> i32;
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
index 4e859fb27a9..8dc0574c757 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs
@@ -2,8 +2,6 @@
 // known-bug: #102682
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::fmt::Debug;
 use std::hash::Hash;
 
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
index d7251a52863..3cc35b21409 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
@@ -1,5 +1,5 @@
 error[E0311]: the parameter type `U` may not live long enough
-  --> $DIR/async-generics-and-bounds.rs:11:5
+  --> $DIR/async-generics-and-bounds.rs:9:5
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Has
    |                 ++++  ++           ++                                       +++++++
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/async-generics-and-bounds.rs:11:5
+  --> $DIR/async-generics-and-bounds.rs:9:5
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-generics.rs b/tests/ui/async-await/in-trait/async-generics.rs
index 2d342592848..6004916a4e5 100644
--- a/tests/ui/async-await/in-trait/async-generics.rs
+++ b/tests/ui/async-await/in-trait/async-generics.rs
@@ -2,8 +2,6 @@
 // known-bug: #102682
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait<T, U> {
     async fn foo(&self) -> &(T, U);
 }
diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr
index aec62d12201..3b27f8fe2f0 100644
--- a/tests/ui/async-await/in-trait/async-generics.stderr
+++ b/tests/ui/async-await/in-trait/async-generics.stderr
@@ -1,5 +1,5 @@
 error[E0311]: the parameter type `U` may not live long enough
-  --> $DIR/async-generics.rs:8:5
+  --> $DIR/async-generics.rs:6:5
    |
 LL |     async fn foo(&self) -> &(T, U);
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a;
    |                 ++++  ++           ++        +++++++++++
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/async-generics.rs:8:5
+  --> $DIR/async-generics.rs:6:5
    |
 LL |     async fn foo(&self) -> &(T, U);
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
index ea8330a4b52..3721b01350d 100644
--- a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
+++ b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 use std::fmt::Debug;
 
 trait MyTrait<'a, 'b, T> {
diff --git a/tests/ui/async-await/in-trait/async-lifetimes.rs b/tests/ui/async-await/in-trait/async-lifetimes.rs
index 6e573b9cc8b..cb4b871cbe1 100644
--- a/tests/ui/async-await/in-trait/async-lifetimes.rs
+++ b/tests/ui/async-await/in-trait/async-lifetimes.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait<'a, 'b, T> {
     #[allow(async_fn_in_trait)]
     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.rs b/tests/ui/async-await/in-trait/async-recursive-generic.rs
index 34f1b09756e..c6031ce28d1 100644
--- a/tests/ui/async-await/in-trait/async-recursive-generic.rs
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait<T> {
     async fn foo_recursive(&self, n: usize) -> T;
 }
diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.stderr b/tests/ui/async-await/in-trait/async-recursive-generic.stderr
index 7c2df6683f0..cf0bcd741fc 100644
--- a/tests/ui/async-await/in-trait/async-recursive-generic.stderr
+++ b/tests/ui/async-await/in-trait/async-recursive-generic.stderr
@@ -1,5 +1,5 @@
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/async-recursive-generic.rs:10:5
+  --> $DIR/async-recursive-generic.rs:8:5
    |
 LL |     async fn foo_recursive(&self, n: usize) -> T {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
diff --git a/tests/ui/async-await/in-trait/async-recursive.rs b/tests/ui/async-await/in-trait/async-recursive.rs
index ddf119b252f..09f1ffe499e 100644
--- a/tests/ui/async-await/in-trait/async-recursive.rs
+++ b/tests/ui/async-await/in-trait/async-recursive.rs
@@ -1,7 +1,5 @@
 // edition: 2021
 
-#![allow(incomplete_features)]
-
 trait MyTrait {
     async fn foo_recursive(&self, n: usize) -> i32;
 }
diff --git a/tests/ui/async-await/in-trait/async-recursive.stderr b/tests/ui/async-await/in-trait/async-recursive.stderr
index 1253252cc40..b959652ea16 100644
--- a/tests/ui/async-await/in-trait/async-recursive.stderr
+++ b/tests/ui/async-await/in-trait/async-recursive.stderr
@@ -1,5 +1,5 @@
 error[E0733]: recursion in an `async fn` requires boxing
-  --> $DIR/async-recursive.rs:10:5
+  --> $DIR/async-recursive.rs:8:5
    |
 LL |     async fn foo_recursive(&self, n: usize) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
diff --git a/tests/ui/async-await/in-trait/coherence-constrained.rs b/tests/ui/async-await/in-trait/coherence-constrained.rs
new file mode 100644
index 00000000000..8e62b3e0e90
--- /dev/null
+++ b/tests/ui/async-await/in-trait/coherence-constrained.rs
@@ -0,0 +1,26 @@
+// edition: 2021
+
+trait Foo {
+    type T;
+
+    async fn foo(&self) -> Self::T;
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    type T = ();
+
+    async fn foo(&self) {}
+    //~^ ERROR type annotations needed: cannot satisfy `<Bar as Foo>::T == ()`
+}
+
+impl Foo for Bar {
+    //~^ ERROR conflicting implementations of trait `Foo` for type `Bar`
+    type T = ();
+
+    async fn foo(&self) {}
+    //~^ ERROR type annotations needed: cannot satisfy `<Bar as Foo>::T == ()`
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/coherence-constrained.stderr b/tests/ui/async-await/in-trait/coherence-constrained.stderr
new file mode 100644
index 00000000000..570a357ca8f
--- /dev/null
+++ b/tests/ui/async-await/in-trait/coherence-constrained.stderr
@@ -0,0 +1,25 @@
+error[E0284]: type annotations needed: cannot satisfy `<Bar as Foo>::T == ()`
+  --> $DIR/coherence-constrained.rs:14:5
+   |
+LL |     async fn foo(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^ cannot satisfy `<Bar as Foo>::T == ()`
+
+error[E0284]: type annotations needed: cannot satisfy `<Bar as Foo>::T == ()`
+  --> $DIR/coherence-constrained.rs:22:5
+   |
+LL |     async fn foo(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^ cannot satisfy `<Bar as Foo>::T == ()`
+
+error[E0119]: conflicting implementations of trait `Foo` for type `Bar`
+  --> $DIR/coherence-constrained.rs:18:1
+   |
+LL | impl Foo for Bar {
+   | ---------------- first implementation here
+...
+LL | impl Foo for Bar {
+   | ^^^^^^^^^^^^^^^^ conflicting implementation for `Bar`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0119, E0284.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/async-await/in-trait/early-bound-1.rs b/tests/ui/async-await/in-trait/early-bound-1.rs
index f79d6f23c93..ddcb477a1dc 100644
--- a/tests/ui/async-await/in-trait/early-bound-1.rs
+++ b/tests/ui/async-await/in-trait/early-bound-1.rs
@@ -1,8 +1,6 @@
 // check-pass
 // edition:2021
 
-#![allow(incomplete_features)]
-
 pub trait Foo {
     #[allow(async_fn_in_trait)]
     async fn foo(&mut self);
diff --git a/tests/ui/async-await/issue-68112.stderr b/tests/ui/async-await/issue-68112.stderr
index 17b619ebee3..1cd8beac260 100644
--- a/tests/ui/async-await/issue-68112.stderr
+++ b/tests/ui/async-await/issue-68112.stderr
@@ -45,7 +45,7 @@ LL |     require_send(send_fut);
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/issue-68112.rs:47:31
    |
 LL |   async fn ready2<T>(t: T) -> T {
diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr
index ab834daa85d..d0605d7e1a6 100644
--- a/tests/ui/async-await/issue-70935-complex-spans.stderr
+++ b/tests/ui/async-await/issue-70935-complex-spans.stderr
@@ -18,7 +18,7 @@ note: required because it's used within this closure
    |
 LL |         baz(|| async {
    |             ^^
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/issue-70935-complex-spans.rs:12:67
    |
 LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr
index 3d6d1fb5c09..2a712aee9c4 100644
--- a/tests/ui/async-await/issues/issue-67893.stderr
+++ b/tests/ui/async-await/issues/issue-67893.stderr
@@ -13,7 +13,7 @@ LL | pub async fn run() {
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
    = note: required because it captures the following types: `Arc<Mutex<()>>`, `MutexGuard<'_, ()>`, `impl Future<Output = ()>`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/auxiliary/issue_67893.rs:9:20
    |
 LL |   pub async fn run() {
diff --git a/tests/ui/async-await/partial-drop-partial-reinit.rs b/tests/ui/async-await/partial-drop-partial-reinit.rs
index 75acb442e7a..815cc916b41 100644
--- a/tests/ui/async-await/partial-drop-partial-reinit.rs
+++ b/tests/ui/async-await/partial-drop-partial-reinit.rs
@@ -26,7 +26,7 @@ impl Drop for NotSend {
 impl !Send for NotSend {}
 
 async fn foo() {
-    //~^ NOTE used within this `async fn` body
+    //~^ NOTE used within this `async` fn body
     //~| NOTE within this `impl Future
     let mut x = (NotSend {},);
     drop(x.0);
diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr
index d115c1b1cc4..310a2923955 100644
--- a/tests/ui/async-await/partial-drop-partial-reinit.stderr
+++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr
@@ -12,7 +12,7 @@ LL | async fn foo() {
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
    = note: required because it appears within the type `(NotSend,)`
    = note: required because it captures the following types: `(NotSend,)`, `impl Future<Output = ()>`
-note: required because it's used within this `async fn` body
+note: required because it's used within this `async` fn body
   --> $DIR/partial-drop-partial-reinit.rs:28:16
    |
 LL |   async fn foo() {
diff --git a/tests/ui/attributes/const-stability-on-macro.rs b/tests/ui/attributes/const-stability-on-macro.rs
index 412af195d7a..af268ccd536 100644
--- a/tests/ui/attributes/const-stability-on-macro.rs
+++ b/tests/ui/attributes/const-stability-on-macro.rs
@@ -1,7 +1,7 @@
 #![feature(staged_api)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[rustc_const_stable(feature = "foo", since = "0")]
+#[rustc_const_stable(feature = "foo", since = "3.3.3")]
 //~^ ERROR macros cannot have const stability attributes
 macro_rules! foo {
     () => {};
diff --git a/tests/ui/attributes/const-stability-on-macro.stderr b/tests/ui/attributes/const-stability-on-macro.stderr
index c3da02c79cb..28f31e3d4f6 100644
--- a/tests/ui/attributes/const-stability-on-macro.stderr
+++ b/tests/ui/attributes/const-stability-on-macro.stderr
@@ -1,8 +1,8 @@
 error: macros cannot have const stability attributes
   --> $DIR/const-stability-on-macro.rs:4:1
    |
-LL | #[rustc_const_stable(feature = "foo", since = "0")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute
+LL | #[rustc_const_stable(feature = "foo", since = "3.3.3")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute
 LL |
 LL | macro_rules! foo {
    | ---------------- const stability attribute affects this macro
diff --git a/tests/ui/attributes/statement-attribute-validation.rs b/tests/ui/attributes/statement-attribute-validation.rs
new file mode 100644
index 00000000000..31407364acf
--- /dev/null
+++ b/tests/ui/attributes/statement-attribute-validation.rs
@@ -0,0 +1,39 @@
+// test for #117058 - check that attributes are validated on various kinds of statements.
+
+struct A;
+
+fn func() {}
+
+fn main() {
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    if true {
+    } else {
+    }
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    (1);
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    match 1 {
+        _ => {}
+    }
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    while false {}
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    {}
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    A {};
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    func();
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    A;
+    #[allow(two-words)]
+    //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
+    loop {}
+}
diff --git a/tests/ui/attributes/statement-attribute-validation.stderr b/tests/ui/attributes/statement-attribute-validation.stderr
new file mode 100644
index 00000000000..06f447be562
--- /dev/null
+++ b/tests/ui/attributes/statement-attribute-validation.stderr
@@ -0,0 +1,56 @@
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:8:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:13:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:16:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:21:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:24:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:27:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:30:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:33:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: expected one of `(`, `,`, `::`, or `=`, found `-`
+  --> $DIR/statement-attribute-validation.rs:36:16
+   |
+LL |     #[allow(two-words)]
+   |                ^ expected one of `(`, `,`, `::`, or `=`
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/cast/ptr-to-ptr-different-regions.rs b/tests/ui/cast/ptr-to-ptr-different-regions.rs
new file mode 100644
index 00000000000..5592e613ac1
--- /dev/null
+++ b/tests/ui/cast/ptr-to-ptr-different-regions.rs
@@ -0,0 +1,24 @@
+// check-pass
+
+// https://github.com/rust-lang/rust/issues/113257
+
+#![deny(trivial_casts)] // The casts here are not trivial.
+
+struct Foo<'a> { a: &'a () }
+
+fn extend_lifetime_very_very_safely<'a>(v: *const Foo<'a>) -> *const Foo<'static> {
+    // This should pass because raw pointer casts can do anything they want.
+    v as *const Foo<'static>
+}
+
+trait Trait {}
+
+fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) {
+    ptr as _
+}
+
+fn main() {
+    let unit = ();
+    let foo = Foo { a: &unit };
+    let _long: *const Foo<'static> = extend_lifetime_very_very_safely(&foo);
+}
diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs
index 20ff875491f..bce3b0fd729 100644
--- a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs
+++ b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs
@@ -6,5 +6,6 @@
 trait NotObjectSafe { fn eq(&self, other: Self); }
 impl NotObjectSafe for dyn NotObjectSafe { }
 //~^ ERROR E0038
+//~| ERROR E0046
 
 fn main() { }
diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr
index e9090c1b6bc..1dcc30ee652 100644
--- a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr
+++ b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr
@@ -13,6 +13,15 @@ LL | trait NotObjectSafe { fn eq(&self, other: Self); }
    |       this trait cannot be made into an object...
    = help: consider moving `eq` to another trait
 
-error: aborting due to previous error
+error[E0046]: not all trait items implemented, missing: `eq`
+  --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:1
+   |
+LL | trait NotObjectSafe { fn eq(&self, other: Self); }
+   |                       -------------------------- `eq` from trait
+LL | impl NotObjectSafe for dyn NotObjectSafe { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `eq` in implementation
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0038`.
+Some errors have detailed explanations: E0038, E0046.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/coherence/coherence-negative-outlives-lifetimes.rs b/tests/ui/coherence/coherence-negative-outlives-lifetimes.rs
index 3acf0d8d39a..0e16d12a181 100644
--- a/tests/ui/coherence/coherence-negative-outlives-lifetimes.rs
+++ b/tests/ui/coherence/coherence-negative-outlives-lifetimes.rs
@@ -1,5 +1,5 @@
 // revisions: stock with_negative_coherence
-//[with_negative_coherence] check-pass
+//[with_negative_coherence] known-bug: unknown
 
 #![feature(negative_impls)]
 #![cfg_attr(with_negative_coherence, feature(with_negative_coherence))]
diff --git a/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr b/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr
new file mode 100644
index 00000000000..097cc4e0fe3
--- /dev/null
+++ b/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `MyTrait<'_>` for type `&_`
+  --> $DIR/coherence-negative-outlives-lifetimes.rs:14:1
+   |
+LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
+   | ---------------------------------------------- first implementation here
+LL | impl<'a, T> MyTrait<'a> for &'a T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/coherence-overlap-trait-alias.rs b/tests/ui/coherence/coherence-overlap-trait-alias.rs
index 9d9c76af91d..d42a666c54f 100644
--- a/tests/ui/coherence/coherence-overlap-trait-alias.rs
+++ b/tests/ui/coherence/coherence-overlap-trait-alias.rs
@@ -13,8 +13,6 @@ impl B for u32 {}
 trait C {}
 impl<T: AB> C for T {}
 impl C for u32 {}
-//~^ ERROR
-// FIXME it's giving an ungreat error but unsure if we care given that it's using an internal rustc
-// attribute and an artificial code path for testing purposes
+//~^ ERROR conflicting implementations of trait `C` for type `u32`
 
 fn main() {}
diff --git a/tests/ui/coherence/coherence-overlap-trait-alias.stderr b/tests/ui/coherence/coherence-overlap-trait-alias.stderr
index 668b8319b38..687f3af0040 100644
--- a/tests/ui/coherence/coherence-overlap-trait-alias.stderr
+++ b/tests/ui/coherence/coherence-overlap-trait-alias.stderr
@@ -1,17 +1,11 @@
-error[E0283]: type annotations needed: cannot satisfy `u32: C`
-  --> $DIR/coherence-overlap-trait-alias.rs:15:12
-   |
-LL | impl C for u32 {}
-   |            ^^^
-   |
-note: multiple `impl`s satisfying `u32: C` found
-  --> $DIR/coherence-overlap-trait-alias.rs:14:1
+error[E0119]: conflicting implementations of trait `C` for type `u32`
+  --> $DIR/coherence-overlap-trait-alias.rs:15:1
    |
 LL | impl<T: AB> C for T {}
-   | ^^^^^^^^^^^^^^^^^^^
+   | ------------------- first implementation here
 LL | impl C for u32 {}
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^ conflicting implementation for `u32`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0283`.
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/coherence-overlap-with-regions.rs b/tests/ui/coherence/coherence-overlap-with-regions.rs
index 32f01f41801..9945c8e6cfd 100644
--- a/tests/ui/coherence/coherence-overlap-with-regions.rs
+++ b/tests/ui/coherence/coherence-overlap-with-regions.rs
@@ -1,4 +1,10 @@
-// check-pass
+// known-bug: unknown
+
+// This fails because we currently perform negative coherence in coherence mode.
+// This means that when looking for a negative predicate, we also assemble a
+// coherence-unknowable predicate. Since confirming the negative impl has region
+// obligations, we don't prefer the impl over the unknowable predicate
+// unconditionally and instead flounder.
 
 #![feature(negative_impls)]
 #![feature(rustc_attrs)]
diff --git a/tests/ui/coherence/coherence-overlap-with-regions.stderr b/tests/ui/coherence/coherence-overlap-with-regions.stderr
new file mode 100644
index 00000000000..fd25f0978ba
--- /dev/null
+++ b/tests/ui/coherence/coherence-overlap-with-regions.stderr
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `Bar` for type `&_`
+  --> $DIR/coherence-overlap-with-regions.rs:20:1
+   |
+LL | impl<T: Foo> Bar for T {}
+   | ---------------------- first implementation here
+LL | impl<T> Bar for &T where T: 'static {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr b/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr
new file mode 100644
index 00000000000..4cf50b4f208
--- /dev/null
+++ b/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `Bar` for type `&_`
+  --> $DIR/negative-coherence-considering-regions.rs:22:1
+   |
+LL | impl<T> Bar for T where T: Foo {}
+   | ------------------------------ first implementation here
+...
+LL | impl<T> Bar for &T {}
+   | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/negative-coherence-considering-regions.rs b/tests/ui/coherence/negative-coherence-considering-regions.rs
new file mode 100644
index 00000000000..597a5972628
--- /dev/null
+++ b/tests/ui/coherence/negative-coherence-considering-regions.rs
@@ -0,0 +1,29 @@
+// revisions: any_lt static_lt
+//[static_lt] known-bug: unknown
+
+// This fails because we currently perform negative coherence in coherence mode.
+// This means that when looking for a negative predicate, we also assemble a
+// coherence-unknowable predicate. Since confirming the negative impl has region
+// obligations, we don't prefer the impl over the unknowable predicate
+// unconditionally and instead flounder.
+
+#![feature(negative_impls)]
+#![feature(with_negative_coherence)]
+
+trait Foo {}
+
+impl<T> !Foo for &'static T {}
+
+trait Bar {}
+
+impl<T> Bar for T where T: Foo {}
+
+#[cfg(any_lt)]
+impl<T> Bar for &T {}
+//[any_lt]~^ ERROR conflicting implementations of trait `Bar` for type `&_`
+
+#[cfg(static_lt)]
+impl<T> Bar for &'static T {}
+
+
+fn main() {}
diff --git a/tests/ui/coherence/negative-coherence-considering-regions.static_lt.stderr b/tests/ui/coherence/negative-coherence-considering-regions.static_lt.stderr
new file mode 100644
index 00000000000..87e7be2aa44
--- /dev/null
+++ b/tests/ui/coherence/negative-coherence-considering-regions.static_lt.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `Bar` for type `&'static _`
+  --> $DIR/negative-coherence-considering-regions.rs:26:1
+   |
+LL | impl<T> Bar for T where T: Foo {}
+   | ------------------------------ first implementation here
+...
+LL | impl<T> Bar for &'static T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&'static _`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/const-generics/const-arg-in-const-arg.rs b/tests/ui/const-generics/const-arg-in-const-arg.rs
index 9eaa54347f1..c1a4c3dc348 100644
--- a/tests/ui/const-generics/const-arg-in-const-arg.rs
+++ b/tests/ui/const-generics/const-arg-in-const-arg.rs
@@ -1,5 +1,5 @@
 // revisions: min
-// we use a single revision because t his shoudl have a `full` revision
+// we use a single revision because this should have a `full` revision
 // but right now that ICEs and I(@BoxyUwU) could not get stderr normalization to work
 
 #![cfg_attr(full, feature(generic_const_exprs))]
diff --git a/tests/ui/const-generics/defaults/default-annotation.rs b/tests/ui/const-generics/defaults/default-annotation.rs
index 7a9f5732f7f..587ad78e298 100644
--- a/tests/ui/const-generics/defaults/default-annotation.rs
+++ b/tests/ui/const-generics/defaults/default-annotation.rs
@@ -4,12 +4,12 @@
 // FIXME(const_generics_defaults): It seems like we aren't testing the right thing here,
 // I would assume that we want the attributes to apply to the const parameter defaults
 // themselves.
-#![stable(feature = "const_default_test", since="none")]
+#![stable(feature = "const_default_test", since = "3.3.3")]
 
-#[unstable(feature = "const_default_stable", issue="none")]
+#[unstable(feature = "const_default_stable", issue = "none")]
 pub struct ConstDefaultUnstable<const N: usize = 3>;
 
-#[stable(feature = "const_default_unstable", since="none")]
+#[stable(feature = "const_default_unstable", since = "3.3.3")]
 pub struct ConstDefaultStable<const N: usize = {
     3
 }>;
diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr
index 4e1d71f1545..7ce2b9ac95a 100644
--- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr
@@ -5,12 +5,15 @@ LL | fn use_dyn(v: &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/object-safety-err-ret.rs:8:23
+  --> $DIR/object-safety-err-ret.rs:8:8
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
 LL |     fn test(&self) -> [u8; bar::<Self>()];
-   |                       ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
+   |        ^^^^           ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
+   |        |
+   |        ...because method `test` references the `Self` type in its `where` clause
+   = help: consider moving `test` to another trait
    = help: consider moving `test` to another trait
 
 error: aborting due to previous error
diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs
new file mode 100644
index 00000000000..5813f098184
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs
@@ -0,0 +1,13 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Q {
+    const ASSOC: usize;
+}
+
+impl<const N: u64> Q for [u8; N] {}
+//~^ ERROR not all trait items implemented
+
+pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
+
+pub fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
new file mode 100644
index 00000000000..0314d7ed23d
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
@@ -0,0 +1,12 @@
+error[E0046]: not all trait items implemented, missing: `ASSOC`
+  --> $DIR/type_mismatch.rs:8:1
+   |
+LL |     const ASSOC: usize;
+   |     ------------------ `ASSOC` from trait
+...
+LL | impl<const N: u64> Q for [u8; N] {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
index afe645ae881..6c4f0a5accf 100644
--- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
+++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
@@ -11,4 +11,5 @@ fn main() {
     //[thir]~^^ call to unsafe function `foo` is unsafe and requires unsafe function or block
     foo();
     //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+    //[thir]~^^ ERROR call to unsafe function `foo` is unsafe and requires unsafe function or block
 }
diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
index b313f06539f..e6b8173eb05 100644
--- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
+++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
@@ -1,4 +1,12 @@
 error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
+  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
+   |
+LL |     foo();
+   |     ^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
   --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
    |
 LL |     let a: [u8; foo()];
@@ -6,6 +14,6 @@ LL |     let a: [u8; foo()];
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/consts/const-unsized.rs b/tests/ui/consts/const-unsized.rs
index 319b8ef97de..e0b06a27109 100644
--- a/tests/ui/consts/const-unsized.rs
+++ b/tests/ui/consts/const-unsized.rs
@@ -2,15 +2,19 @@ use std::fmt::Debug;
 
 const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
 //~^ ERROR the size for values of type
+//~| ERROR the size for values of type
 
 const CONST_FOO: str = *"foo";
 //~^ ERROR the size for values of type
+//~| ERROR the size for values of type
 
 static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
 //~^ ERROR the size for values of type
+//~| ERROR the size for values of type
 
 static STATIC_BAR: str = *"bar";
 //~^ ERROR the size for values of type
+//~| ERROR the size for values of type
 
 fn main() {
     println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
diff --git a/tests/ui/consts/const-unsized.stderr b/tests/ui/consts/const-unsized.stderr
index 27b200648eb..674f0cb99e7 100644
--- a/tests/ui/consts/const-unsized.stderr
+++ b/tests/ui/consts/const-unsized.stderr
@@ -7,7 +7,7 @@ LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
    = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/const-unsized.rs:6:18
+  --> $DIR/const-unsized.rs:7:18
    |
 LL | const CONST_FOO: str = *"foo";
    |                  ^^^ doesn't have a size known at compile-time
@@ -15,7 +15,7 @@ LL | const CONST_FOO: str = *"foo";
    = help: the trait `Sized` is not implemented for `str`
 
 error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time
-  --> $DIR/const-unsized.rs:9:18
+  --> $DIR/const-unsized.rs:11:18
    |
 LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
    |                  ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -23,13 +23,49 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
    = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/const-unsized.rs:12:20
+  --> $DIR/const-unsized.rs:15:20
    |
 LL | static STATIC_BAR: str = *"bar";
    |                    ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `str`
 
-error: aborting due to 4 previous errors
+error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time
+  --> $DIR/const-unsized.rs:3:35
+   |
+LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`
+   = note: constant expressions must have a statically known size
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/const-unsized.rs:7:24
+   |
+LL | const CONST_FOO: str = *"foo";
+   |                        ^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: constant expressions must have a statically known size
+
+error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time
+  --> $DIR/const-unsized.rs:11:37
+   |
+LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)`
+   = note: constant expressions must have a statically known size
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/const-unsized.rs:15:26
+   |
+LL | static STATIC_BAR: str = *"bar";
+   |                          ^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: constant expressions must have a statically known size
+
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/deprecation/staged-deprecation-in-future.rs b/tests/ui/deprecation/staged-deprecation-in-future.rs
index 87b15ec303c..49ee60b9bd0 100644
--- a/tests/ui/deprecation/staged-deprecation-in-future.rs
+++ b/tests/ui/deprecation/staged-deprecation-in-future.rs
@@ -2,14 +2,14 @@
 
 #![feature(staged_api)]
 
-#![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+#![stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")]
 
 #[deprecated(since = "99.99.99", note = "effectively never")]
-#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+#[stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")]
 pub struct S1;
 
 #[deprecated(since = "TBD", note = "literally never")]
-#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+#[stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")]
 pub struct S2;
 
 fn main() {
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
index 00fb59d14d7..346d8373f73 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
@@ -23,9 +23,15 @@ trait Boom {}
 //~^WARN malformed `on_unimplemented` attribute
 trait Doom {}
 
+#[diagnostic::on_unimplemented]
+//~^WARN missing options for `on_unimplemented` attribute
+//~|WARN missing options for `on_unimplemented` attribute
+trait Whatever {}
+
 fn take_foo(_: impl Foo) {}
 fn take_baz(_: impl Baz) {}
 fn take_boom(_: impl Boom) {}
+fn take_whatever(_: impl Whatever) {}
 
 fn main() {
     take_foo(1_i32);
@@ -34,4 +40,6 @@ fn main() {
     //~^ERROR Boom
     take_boom(1_i32);
     //~^ERROR Boom
+    take_whatever(1_i32);
+    //~^ERROR the trait bound `i32: Whatever` is not satisfied
 }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
index bd39c91ffe8..162ddd79fbb 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
@@ -10,36 +10,53 @@ warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
    |
 LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
-   |                                ^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
-   |                                                  ^^^^^^^^^^^^^^^^^^^
+   |                                                  ^^^^^^^^^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32
    |
 LL | #[diagnostic::on_unimplemented = "boom"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
+
+warning: missing options for `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
+   |
+LL | #[diagnostic::on_unimplemented]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: at least one of the `message`, `note` and `label` options are expected
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
    |
 LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
-   |                                ^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `i32: Foo` is not satisfied
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:14
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:14
    |
 LL |     take_foo(1_i32);
    |     -------- ^^^^^ the trait `Foo` is not implemented for `i32`
@@ -52,7 +69,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `take_foo`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:21
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:21
    |
 LL | fn take_foo(_: impl Foo) {}
    |                     ^^^ required by this bound in `take_foo`
@@ -61,12 +78,13 @@ warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
-   |                                                  ^^^^^^^^^^^^^^^^^^^
+   |                                                  ^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Boom
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:14
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:14
    |
 LL |     take_baz(1_i32);
    |     -------- ^^^^^ the trait `Baz` is not implemented for `i32`
@@ -79,7 +97,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Baz {}
    | ^^^^^^^^^
 note: required by a bound in `take_baz`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:21
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:21
    |
 LL | fn take_baz(_: impl Baz) {}
    |                     ^^^ required by this bound in `take_baz`
@@ -88,12 +106,13 @@ warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Boom
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:15
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:15
    |
 LL |     take_boom(1_i32);
    |     --------- ^^^^^ the trait `Boom` is not implemented for `i32`
@@ -106,11 +125,39 @@ help: this trait has no implementations, consider adding one
 LL | trait Boom {}
    | ^^^^^^^^^^
 note: required by a bound in `take_boom`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:28:22
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:22
    |
 LL | fn take_boom(_: impl Boom) {}
    |                      ^^^^ required by this bound in `take_boom`
 
-error: aborting due to 3 previous errors; 8 warnings emitted
+warning: missing options for `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
+   |
+LL | #[diagnostic::on_unimplemented]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: at least one of the `message`, `note` and `label` options are expected
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `i32: Whatever` is not satisfied
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:19
+   |
+LL |     take_whatever(1_i32);
+   |     ------------- ^^^^^ the trait `Whatever` is not implemented for `i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1
+   |
+LL | trait Whatever {}
+   | ^^^^^^^^^^^^^^
+note: required by a bound in `take_whatever`
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:26
+   |
+LL | fn take_whatever(_: impl Whatever) {}
+   |                          ^^^^^^^^ required by this bound in `take_whatever`
+
+error: aborting due to 4 previous errors; 10 warnings emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
index 35307586391..8410b3eb105 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
@@ -1,22 +1,20 @@
 #![feature(diagnostic_namespace)]
 
 #[diagnostic::on_unimplemented(
+    if(Self = "()"),
     //~^WARN malformed `on_unimplemented` attribute
     //~|WARN malformed `on_unimplemented` attribute
-    if(Self = ()),
-    message = "not used yet",
-    label = "not used yet",
-    note = "not used yet"
+    message = "custom message",
+    note = "custom note"
 )]
 #[diagnostic::on_unimplemented(message = "fallback!!")]
 #[diagnostic::on_unimplemented(label = "fallback label")]
 #[diagnostic::on_unimplemented(note = "fallback note")]
-#[diagnostic::on_unimplemented(message = "fallback2!!")]
 trait Foo {}
 
 fn takes_foo(_: impl Foo) {}
 
 fn main() {
     takes_foo(());
-    //~^ERROR fallback!!
+    //~^ERROR custom message
 }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
index 6a83d8e39c6..7860e540589 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
@@ -1,33 +1,23 @@
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5
    |
-LL | / #[diagnostic::on_unimplemented(
-LL | |
-LL | |
-LL | |     if(Self = ()),
-...  |
-LL | |     note = "not used yet"
-LL | | )]
-   | |__^
+LL |     if(Self = "()"),
+   |     ^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5
    |
-LL | / #[diagnostic::on_unimplemented(
-LL | |
-LL | |
-LL | |     if(Self = ()),
-...  |
-LL | |     note = "not used yet"
-LL | | )]
-   | |__^
+LL |     if(Self = "()"),
+   |     ^^^^^^^^^^^^^^^ invalid option found here
    |
+   = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0277]: fallback!!
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15
+error[E0277]: custom message
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15
    |
 LL |     takes_foo(());
    |     --------- ^^ fallback label
@@ -35,14 +25,14 @@ LL |     takes_foo(());
    |     required by a bound introduced by this call
    |
    = help: the trait `Foo` is not implemented for `()`
-   = note: fallback note
+   = note: custom note
 help: this trait has no implementations, consider adding one
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1
    |
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22
    |
 LL | fn takes_foo(_: impl Foo) {}
    |                      ^^^ required by this bound in `takes_foo`
diff --git a/tests/ui/feature-gates/feature-gate-staged_api.rs b/tests/ui/feature-gates/feature-gate-staged_api.rs
index 2571ab5d1b4..ce6b218dd7d 100644
--- a/tests/ui/feature-gates/feature-gate-staged_api.rs
+++ b/tests/ui/feature-gates/feature-gate-staged_api.rs
@@ -1,11 +1,11 @@
-#![stable(feature = "a", since = "b")]
+#![stable(feature = "a", since = "3.3.3")]
 //~^ ERROR stability attributes may not be used outside of the standard library
 mod inner_private_module {
     // UnnameableTypeAlias isn't marked as reachable, so no stability annotation is required here
     pub type UnnameableTypeAlias = u8;
 }
 
-#[stable(feature = "a", since = "b")]
+#[stable(feature = "a", since = "3.3.3")]
 //~^ ERROR stability attributes may not be used outside of the standard library
 pub fn f() -> inner_private_module::UnnameableTypeAlias {
     0
diff --git a/tests/ui/feature-gates/feature-gate-staged_api.stderr b/tests/ui/feature-gates/feature-gate-staged_api.stderr
index 951bb5a1740..1a9fcb02b0d 100644
--- a/tests/ui/feature-gates/feature-gate-staged_api.stderr
+++ b/tests/ui/feature-gates/feature-gate-staged_api.stderr
@@ -1,14 +1,14 @@
 error[E0734]: stability attributes may not be used outside of the standard library
   --> $DIR/feature-gate-staged_api.rs:8:1
    |
-LL | #[stable(feature = "a", since = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[stable(feature = "a", since = "3.3.3")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0734]: stability attributes may not be used outside of the standard library
   --> $DIR/feature-gate-staged_api.rs:1:1
    |
-LL | #![stable(feature = "a", since = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![stable(feature = "a", since = "3.3.3")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/generic-associated-types/issue-84931.rs b/tests/ui/generic-associated-types/issue-84931.rs
index 4123ce9d4d9..2ef990a7a90 100644
--- a/tests/ui/generic-associated-types/issue-84931.rs
+++ b/tests/ui/generic-associated-types/issue-84931.rs
@@ -12,7 +12,8 @@ struct StreamingSliceIter<'a, T> {
 
 impl<'b, T: 'b> StreamingIter for StreamingSliceIter<'b, T> {
     type Item<'a> = &'a mut T;
-    //~^ the parameter type
+    //~^ ERROR: the parameter type
+    //~| ERROR: does not fulfill the required lifetime
     fn next(&mut self) -> Option<&mut T> {
         loop {}
     }
diff --git a/tests/ui/generic-associated-types/issue-84931.stderr b/tests/ui/generic-associated-types/issue-84931.stderr
index fe9932c205a..04e14b9c746 100644
--- a/tests/ui/generic-associated-types/issue-84931.stderr
+++ b/tests/ui/generic-associated-types/issue-84931.stderr
@@ -11,6 +11,26 @@ help: consider adding an explicit lifetime bound
 LL |     type Item<'a> = &'a mut T where T: 'a;
    |                               +++++++++++
 
-error: aborting due to previous error
+error[E0477]: the type `StreamingSliceIter<'b, T>` does not fulfill the required lifetime
+  --> $DIR/issue-84931.rs:14:21
+   |
+LL |     type Item<'a> where Self: 'a;
+   |     ------------- definition of `Item` from trait
+...
+LL |     type Item<'a> = &'a mut T;
+   |                     ^^^^^^^^^
+   |
+note: type must outlive the lifetime `'a` as defined here
+  --> $DIR/issue-84931.rs:14:15
+   |
+LL |     type Item<'a> = &'a mut T;
+   |               ^^
+help: copy the `where` clause predicates from the trait
+   |
+LL |     type Item<'a> = &'a mut T where Self: 'a;
+   |                               ++++++++++++++
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0309`.
+Some errors have detailed explanations: E0309, E0477.
+For more information about an error, try `rustc --explain E0309`.
diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs
index 060ee8821d8..a3f3b1a6d4d 100644
--- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs
+++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs
@@ -7,6 +7,7 @@ pub trait X {
 
 impl X for () {
     type Y<'a> = &'a ();
+    //~^ ERROR lifetime bound not satisfied
 }
 
 struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr
index a69cd0028c1..f73ed5956da 100644
--- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr
+++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr
@@ -12,44 +12,64 @@ LL | #![warn(unused_lifetimes)]
    |         ^^^^^^^^^^^^^^^^
 
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/unsatisfied-item-lifetime-bound.rs:13:8
+  --> $DIR/unsatisfied-item-lifetime-bound.rs:14:8
    |
 LL |     f: <T as X>::Y<'a>,
    |        ^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'a` as defined here
-  --> $DIR/unsatisfied-item-lifetime-bound.rs:12:10
+  --> $DIR/unsatisfied-item-lifetime-bound.rs:13:10
    |
 LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
    |          ^^
    = note: but lifetime parameter must outlive the static lifetime
 
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/unsatisfied-item-lifetime-bound.rs:18:8
+  --> $DIR/unsatisfied-item-lifetime-bound.rs:19:8
    |
 LL |     f: <T as X>::Y<'a>,
    |        ^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'a` as defined here
-  --> $DIR/unsatisfied-item-lifetime-bound.rs:17:10
+  --> $DIR/unsatisfied-item-lifetime-bound.rs:18:10
    |
 LL | struct C<'a, T: X> {
    |          ^^
    = note: but lifetime parameter must outlive the static lifetime
 
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/unsatisfied-item-lifetime-bound.rs:23:8
+  --> $DIR/unsatisfied-item-lifetime-bound.rs:24:8
    |
 LL |     f: <() as X>::Y<'a>,
    |        ^^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'a` as defined here
-  --> $DIR/unsatisfied-item-lifetime-bound.rs:22:10
+  --> $DIR/unsatisfied-item-lifetime-bound.rs:23:10
    |
 LL | struct D<'a> {
    |          ^^
    = note: but lifetime parameter must outlive the static lifetime
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/unsatisfied-item-lifetime-bound.rs:9:18
+   |
+LL |     type Y<'a: 'static>;
+   |     ------------------- definition of `Y` from trait
+...
+LL |     type Y<'a> = &'a ();
+   |                  ^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined here
+  --> $DIR/unsatisfied-item-lifetime-bound.rs:9:12
+   |
+LL |     type Y<'a> = &'a ();
+   |            ^^
+   = note: but lifetime parameter must outlive the static lifetime
+help: copy the `where` clause predicates from the trait
+   |
+LL |     type Y<'a> = &'a () where 'a: 'static;
+   |                         +++++++++++++++++
+
+error: aborting due to 4 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0478`.
diff --git a/tests/ui/impl-trait/in-trait/deep-match.rs b/tests/ui/impl-trait/in-trait/deep-match.rs
index 02889347ba4..82eac7760fc 100644
--- a/tests/ui/impl-trait/in-trait/deep-match.rs
+++ b/tests/ui/impl-trait/in-trait/deep-match.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 struct Wrapper<T>(T);
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/deep-match.stderr b/tests/ui/impl-trait/in-trait/deep-match.stderr
index 9cfc54f5094..a658d8fa078 100644
--- a/tests/ui/impl-trait/in-trait/deep-match.stderr
+++ b/tests/ui/impl-trait/in-trait/deep-match.stderr
@@ -1,5 +1,5 @@
 error[E0053]: method `bar` has an incompatible return type for trait
-  --> $DIR/deep-match.rs:10:17
+  --> $DIR/deep-match.rs:8:17
    |
 LL |     fn bar() -> i32 {
    |                 ^^^
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs
index 977ff8111dd..ac7a50a365e 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err.rs
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 use std::ops::Deref;
 
 pub trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr
index 3d9ca62b0db..596ff101155 100644
--- a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr
+++ b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr
@@ -1,5 +1,5 @@
 error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String`
-  --> $DIR/default-body-type-err.rs:6:22
+  --> $DIR/default-body-type-err.rs:4:22
    |
 LL |     fn lol(&self) -> impl Deref<Target = String> {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String`
diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
index 5a53c9a19b5..0ac60918b67 100644
--- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
+++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 trait Foo {
     fn bar() -> impl std::fmt::Display;
 }
diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr
index cb9ecc7fa48..cd45c6a9c6d 100644
--- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr
+++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr
@@ -1,5 +1,5 @@
 error[E0277]: `()` doesn't implement `std::fmt::Display`
-  --> $DIR/doesnt-satisfy.rs:8:17
+  --> $DIR/doesnt-satisfy.rs:6:17
    |
 LL |     fn bar() -> () {}
    |                 ^^ `()` cannot be formatted with the default formatter
@@ -7,7 +7,7 @@ LL |     fn bar() -> () {}
    = help: the trait `std::fmt::Display` is not implemented for `()`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 note: required by a bound in `Foo::{opaque#0}`
-  --> $DIR/doesnt-satisfy.rs:4:22
+  --> $DIR/doesnt-satisfy.rs:2:22
    |
 LL |     fn bar() -> impl std::fmt::Display;
    |                      ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::{opaque#0}`
diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs
index 2e5373dbd5d..3ea31cc9347 100644
--- a/tests/ui/impl-trait/in-trait/generics-mismatch.rs
+++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 struct U;
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr
index 3dbf2235c5e..043dbc8db5d 100644
--- a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr
@@ -1,5 +1,5 @@
 error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
-  --> $DIR/generics-mismatch.rs:10:12
+  --> $DIR/generics-mismatch.rs:8:12
    |
 LL |     fn bar(&self) -> impl Sized;
    |           - expected 0 type parameters
diff --git a/tests/ui/impl-trait/in-trait/issue-102140.rs b/tests/ui/impl-trait/in-trait/issue-102140.rs
index 1132bd25f81..7960018482f 100644
--- a/tests/ui/impl-trait/in-trait/issue-102140.rs
+++ b/tests/ui/impl-trait/in-trait/issue-102140.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 trait Marker {}
 impl Marker for u32 {}
 
diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr
index 6d50d2f3a24..9cd2cdfd1a5 100644
--- a/tests/ui/impl-trait/in-trait/issue-102140.stderr
+++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:22:22
+  --> $DIR/issue-102140.rs:20:22
    |
 LL |         MyTrait::foo(&self)
    |         ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
@@ -13,7 +13,7 @@ LL +         MyTrait::foo(self)
    |
 
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:22:9
+  --> $DIR/issue-102140.rs:20:9
    |
 LL |         MyTrait::foo(&self)
    |         ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
@@ -21,7 +21,7 @@ LL |         MyTrait::foo(&self)
    = help: the trait `MyTrait` is implemented for `Outer`
 
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
-  --> $DIR/issue-102140.rs:22:9
+  --> $DIR/issue-102140.rs:20:9
    |
 LL |         MyTrait::foo(&self)
    |         ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs
index 4534753f0d2..4fa3fdd31b5 100644
--- a/tests/ui/impl-trait/in-trait/issue-102571.rs
+++ b/tests/ui/impl-trait/in-trait/issue-102571.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 use std::fmt::Display;
 use std::ops::Deref;
 
diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.stderr
index 4d1a0feb22b..872988faf7a 100644
--- a/tests/ui/impl-trait/in-trait/issue-102571.stderr
+++ b/tests/ui/impl-trait/in-trait/issue-102571.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-102571.rs:11:9
+  --> $DIR/issue-102571.rs:9:9
    |
 LL |     let () = t.bar();
    |         ^^   ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>`
diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs
index 15634537dae..5cca4ad839c 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.rs
+++ b/tests/ui/impl-trait/in-trait/object-safety.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 use std::fmt::Debug;
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr
index 8d882391251..3271cb18d9f 100644
--- a/tests/ui/impl-trait/in-trait/object-safety.stderr
+++ b/tests/ui/impl-trait/in-trait/object-safety.stderr
@@ -1,11 +1,11 @@
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:16:33
+  --> $DIR/object-safety.rs:14:33
    |
 LL |     let i = Box::new(42_u32) as Box<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/object-safety.rs:6:22
+  --> $DIR/object-safety.rs:4:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
@@ -14,13 +14,13 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:19:15
+  --> $DIR/object-safety.rs:17:15
    |
 LL |     let s = i.baz();
    |               ^^^ `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/object-safety.rs:6:22
+  --> $DIR/object-safety.rs:4:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
@@ -29,13 +29,13 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:19:13
+  --> $DIR/object-safety.rs:17:13
    |
 LL |     let s = i.baz();
    |             ^^^^^^^ `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/object-safety.rs:6:22
+  --> $DIR/object-safety.rs:4:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
@@ -44,13 +44,13 @@ LL |     fn baz(&self) -> impl Debug;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety.rs:16:13
+  --> $DIR/object-safety.rs:14:13
    |
 LL |     let i = Box::new(42_u32) as Box<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/object-safety.rs:6:22
+  --> $DIR/object-safety.rs:4:22
    |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
index fc708536b0f..1f18bb3b774 100644
--- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
+++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 use std::fmt::Display;
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
index 99b62e80acd..e260762d89f 100644
--- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
+++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/opaque-in-impl-is-opaque.rs:16:19
+  --> $DIR/opaque-in-impl-is-opaque.rs:14:19
    |
 LL |     fn bar(&self) -> impl Display {
    |                      ------------ the found opaque type
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
index c905bfce852..d9fac0238e1 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
@@ -1,5 +1,3 @@
-#![allow(incomplete_features)]
-
 struct S;
 
 trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
index e904548742d..2836e9c7821 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
@@ -1,5 +1,5 @@
 error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter
-  --> $DIR/trait-more-generics-than-impl.rs:10:11
+  --> $DIR/trait-more-generics-than-impl.rs:8:11
    |
 LL |     fn bar<T>() -> impl Sized;
    |            - expected 1 type parameter
diff --git a/tests/ui/impl-trait/negative-reasoning.stderr b/tests/ui/impl-trait/negative-reasoning.stderr
index 6b8cc9e7374..ddce5e7ece2 100644
--- a/tests/ui/impl-trait/negative-reasoning.stderr
+++ b/tests/ui/impl-trait/negative-reasoning.stderr
@@ -7,7 +7,7 @@ LL | impl<T: std::fmt::Debug> AnotherTrait for T {}
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
    |
-   = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
+   = note: upstream crates may add a new impl of trait `std::marker::FnPtr` for type `OpaqueType` in future versions
 
 error: aborting due to previous error
 
diff --git a/tests/ui/impl-unused-tps.rs b/tests/ui/impl-unused-tps.rs
index 7cc1ae613bc..3eb9daedf76 100644
--- a/tests/ui/impl-unused-tps.rs
+++ b/tests/ui/impl-unused-tps.rs
@@ -1,3 +1,5 @@
+//~ ERROR overflow evaluating the requirement `([isize; 0], _): Sized
+
 trait Foo<A> {
     fn get(&self, A: &A) { }
 }
@@ -23,8 +25,7 @@ impl<T:Bar<Out=U>,U> Foo<T> for [isize;3] {
 }
 
 impl<T,U> Foo<T> for U {
-    // OK, T, U are used everywhere. Note that the coherence check
-    // hasn't executed yet, so no errors about overlap.
+    //~^ ERROR conflicting implementations of trait `Foo<_>` for type `[isize; 0]`
 }
 
 impl<T,U> Bar for T {
diff --git a/tests/ui/impl-unused-tps.stderr b/tests/ui/impl-unused-tps.stderr
index 053ab91c893..93215326c2f 100644
--- a/tests/ui/impl-unused-tps.stderr
+++ b/tests/ui/impl-unused-tps.stderr
@@ -1,33 +1,56 @@
 error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/impl-unused-tps.rs:13:8
+  --> $DIR/impl-unused-tps.rs:15:8
    |
 LL | impl<T,U> Foo<T> for [isize;1] {
    |        ^ unconstrained type parameter
 
 error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/impl-unused-tps.rs:30:8
+  --> $DIR/impl-unused-tps.rs:31:8
    |
 LL | impl<T,U> Bar for T {
    |        ^ unconstrained type parameter
 
 error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/impl-unused-tps.rs:38:8
+  --> $DIR/impl-unused-tps.rs:39:8
    |
 LL | impl<T,U> Bar for T
    |        ^ unconstrained type parameter
 
 error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/impl-unused-tps.rs:46:8
+  --> $DIR/impl-unused-tps.rs:47:8
    |
 LL | impl<T,U,V> Foo<T> for T
    |        ^ unconstrained type parameter
 
 error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/impl-unused-tps.rs:46:10
+  --> $DIR/impl-unused-tps.rs:47:10
    |
 LL | impl<T,U,V> Foo<T> for T
    |          ^ unconstrained type parameter
 
-error: aborting due to 5 previous errors
+error[E0119]: conflicting implementations of trait `Foo<_>` for type `[isize; 0]`
+  --> $DIR/impl-unused-tps.rs:27:1
+   |
+LL | impl<T> Foo<T> for [isize;0] {
+   | ---------------------------- first implementation here
+...
+LL | impl<T,U> Foo<T> for U {
+   | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
+
+error[E0275]: overflow evaluating the requirement `([isize; 0], _): Sized`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`impl_unused_tps`)
+note: required for `([isize; 0], _)` to implement `Bar`
+  --> $DIR/impl-unused-tps.rs:31:11
+   |
+LL | impl<T,U> Bar for T {
+   |      -    ^^^     ^
+   |      |
+   |      unsatisfied trait bound introduced here
+   = note: 126 redundant requirements hidden
+   = note: required for `([isize; 0], _)` to implement `Bar`
+
+error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0207`.
+Some errors have detailed explanations: E0119, E0207, E0275.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr
index 15477fb6f10..d2a0f436c42 100644
--- a/tests/ui/imports/issue-56125.stderr
+++ b/tests/ui/imports/issue-56125.stderr
@@ -6,14 +6,14 @@ LL |     use empty::issue_56125;
    |
 help: consider importing one of these items instead
    |
+LL |     use ::issue_56125::issue_56125;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     use ::issue_56125::last_segment::issue_56125;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     use ::issue_56125::non_last_segment::non_last_segment::issue_56125;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     use crate::m3::last_segment::issue_56125;
    |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     use crate::m3::non_last_segment::non_last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     use issue_56125::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     use issue_56125::last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      and 1 other candidate
 
 error[E0659]: `issue_56125` is ambiguous
diff --git a/tests/ui/inline-const/expr-unsafe.thir.stderr b/tests/ui/inline-const/expr-unsafe.thir.stderr
index 4737444fb61..1ab6e42fba0 100644
--- a/tests/ui/inline-const/expr-unsafe.thir.stderr
+++ b/tests/ui/inline-const/expr-unsafe.thir.stderr
@@ -1,9 +1,6 @@
 warning: unnecessary `unsafe` block
   --> $DIR/expr-unsafe.rs:12:13
    |
-LL |     unsafe {
-   |     ------ because it's nested under this `unsafe` block
-...
 LL |             unsafe {}
    |             ^^^^^^ unnecessary `unsafe` block
    |
diff --git a/tests/ui/inline-const/pat-unsafe-err.rs b/tests/ui/inline-const/pat-unsafe-err.rs
index e290b438c51..6df281c6d94 100644
--- a/tests/ui/inline-const/pat-unsafe-err.rs
+++ b/tests/ui/inline-const/pat-unsafe-err.rs
@@ -1,11 +1,13 @@
-// ignore-test This is currently broken
 // revisions: mir thir
+// [mir]ignore-test This is currently broken
 // [thir]compile-flags: -Z thir-unsafeck
 
 #![allow(incomplete_features)]
 #![feature(inline_const_pat)]
 
-const unsafe fn require_unsafe() -> usize { 1 }
+const unsafe fn require_unsafe() -> usize {
+    1
+}
 
 fn main() {
     match () {
@@ -14,4 +16,12 @@ fn main() {
             //~^ ERROR [E0133]
         } => (),
     }
+
+    match 1 {
+        const {
+            require_unsafe()
+            //~^ ERROR [E0133]
+        }..=4 => (),
+        _ => (),
+    }
 }
diff --git a/tests/ui/inline-const/pat-unsafe-err.thir.stderr b/tests/ui/inline-const/pat-unsafe-err.thir.stderr
new file mode 100644
index 00000000000..48a2cb4c704
--- /dev/null
+++ b/tests/ui/inline-const/pat-unsafe-err.thir.stderr
@@ -0,0 +1,19 @@
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+  --> $DIR/pat-unsafe-err.rs:15:13
+   |
+LL |             require_unsafe();
+   |             ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+  --> $DIR/pat-unsafe-err.rs:22:13
+   |
+LL |             require_unsafe()
+   |             ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/inline-const/pat-unsafe.rs b/tests/ui/inline-const/pat-unsafe.rs
index bcf7f6e0180..36f8632af67 100644
--- a/tests/ui/inline-const/pat-unsafe.rs
+++ b/tests/ui/inline-const/pat-unsafe.rs
@@ -1,13 +1,15 @@
-// ignore-test This is currently broken
 // check-pass
 // revisions: mir thir
+// [mir]ignore-test This is currently broken
 // [thir]compile-flags: -Z thir-unsafeck
 
 #![allow(incomplete_features)]
 #![warn(unused_unsafe)]
 #![feature(inline_const_pat)]
 
-const unsafe fn require_unsafe() -> usize { 1 }
+const unsafe fn require_unsafe() -> usize {
+    1
+}
 
 fn main() {
     unsafe {
@@ -18,5 +20,14 @@ fn main() {
                 //~^ WARNING unnecessary `unsafe` block
             } => (),
         }
+
+        match 1 {
+            const {
+                unsafe {}
+                //~^ WARNING unnecessary `unsafe` block
+                require_unsafe()
+            }..=4 => (),
+            _ => (),
+        }
     }
 }
diff --git a/tests/ui/inline-const/pat-unsafe.thir.stderr b/tests/ui/inline-const/pat-unsafe.thir.stderr
new file mode 100644
index 00000000000..0318b3ff2cc
--- /dev/null
+++ b/tests/ui/inline-const/pat-unsafe.thir.stderr
@@ -0,0 +1,20 @@
+warning: unnecessary `unsafe` block
+  --> $DIR/pat-unsafe.rs:19:17
+   |
+LL |                 unsafe {}
+   |                 ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/pat-unsafe.rs:7:9
+   |
+LL | #![warn(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+warning: unnecessary `unsafe` block
+  --> $DIR/pat-unsafe.rs:26:17
+   |
+LL |                 unsafe {}
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/instrument-coverage/bad-value.bad.stderr b/tests/ui/instrument-coverage/bad-value.bad.stderr
index 246c4f31a4b..b867d169dae 100644
--- a/tests/ui/instrument-coverage/bad-value.bad.stderr
+++ b/tests/ui/instrument-coverage/bad-value.bad.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `bad-value` for codegen option `instrument-coverage` - `all` (default), `except-unused-generics`, `except-unused-functions`, or `off` was expected
+error: incorrect value `bad-value` for codegen option `instrument-coverage` - `all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off` was expected
 
diff --git a/tests/ui/instrument-coverage/bad-value.blank.stderr b/tests/ui/instrument-coverage/bad-value.blank.stderr
index b539c558d9b..e7122fb61cd 100644
--- a/tests/ui/instrument-coverage/bad-value.blank.stderr
+++ b/tests/ui/instrument-coverage/bad-value.blank.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `` for codegen option `instrument-coverage` - `all` (default), `except-unused-generics`, `except-unused-functions`, or `off` was expected
+error: incorrect value `` for codegen option `instrument-coverage` - `all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off` was expected
 
diff --git a/tests/ui/instrument-coverage/except-unused-functions.rs b/tests/ui/instrument-coverage/except-unused-functions.rs
deleted file mode 100644
index 5a0b7d4fef9..00000000000
--- a/tests/ui/instrument-coverage/except-unused-functions.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-// compile-flags: -Cinstrument-coverage=except-unused-functions
-
-fn main() {}
diff --git a/tests/ui/instrument-coverage/except-unused-functions.stderr b/tests/ui/instrument-coverage/except-unused-functions.stderr
deleted file mode 100644
index 82c1c630cbf..00000000000
--- a/tests/ui/instrument-coverage/except-unused-functions.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: `-C instrument-coverage=except-*` requires `-Z unstable-options`
-
diff --git a/tests/ui/instrument-coverage/except-unused-generics.rs b/tests/ui/instrument-coverage/except-unused-generics.rs
deleted file mode 100644
index 4b1ddf29026..00000000000
--- a/tests/ui/instrument-coverage/except-unused-generics.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-// compile-flags: -Cinstrument-coverage=except-unused-generics
-
-fn main() {}
diff --git a/tests/ui/instrument-coverage/except-unused-generics.stderr b/tests/ui/instrument-coverage/except-unused-generics.stderr
deleted file mode 100644
index 82c1c630cbf..00000000000
--- a/tests/ui/instrument-coverage/except-unused-generics.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: `-C instrument-coverage=except-*` requires `-Z unstable-options`
-
diff --git a/tests/ui/instrument-coverage/unstable.branch.stderr b/tests/ui/instrument-coverage/unstable.branch.stderr
new file mode 100644
index 00000000000..acc633a2a6d
--- /dev/null
+++ b/tests/ui/instrument-coverage/unstable.branch.stderr
@@ -0,0 +1,2 @@
+error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options`
+
diff --git a/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr b/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr
new file mode 100644
index 00000000000..acc633a2a6d
--- /dev/null
+++ b/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr
@@ -0,0 +1,2 @@
+error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options`
+
diff --git a/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr b/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr
new file mode 100644
index 00000000000..acc633a2a6d
--- /dev/null
+++ b/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr
@@ -0,0 +1,2 @@
+error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options`
+
diff --git a/tests/ui/instrument-coverage/unstable.rs b/tests/ui/instrument-coverage/unstable.rs
new file mode 100644
index 00000000000..c16bcd0bf6d
--- /dev/null
+++ b/tests/ui/instrument-coverage/unstable.rs
@@ -0,0 +1,6 @@
+// revisions: branch except-unused-functions except-unused-generics
+// [branch] compile-flags: -Cinstrument-coverage=branch
+// [except-unused-functions] compile-flags: -Cinstrument-coverage=except-unused-functions
+// [except-unused-generics] compile-flags: -Cinstrument-coverage=except-unused-generics
+
+fn main() {}
diff --git a/tests/ui/issues/issue-19380.rs b/tests/ui/issues/issue-19380.rs
index 5c10e2067e4..fce737cba18 100644
--- a/tests/ui/issues/issue-19380.rs
+++ b/tests/ui/issues/issue-19380.rs
@@ -14,5 +14,6 @@ struct Bar {
 
 const FOO : Foo = Foo;
 const BAR : Bar = Bar { foos: &[&FOO]};
+//~^ ERROR E0038
 
 fn main() { }
diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr
index b2aeb5edf29..37e280fbcc7 100644
--- a/tests/ui/issues/issue-19380.stderr
+++ b/tests/ui/issues/issue-19380.stderr
@@ -20,6 +20,29 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o
 LL |   fn qiz() where Self: Sized;
    |            +++++++++++++++++
 
-error: aborting due to previous error
+error[E0038]: the trait `Qiz` cannot be made into an object
+  --> $DIR/issue-19380.rs:16:33
+   |
+LL | const BAR : Bar = Bar { foos: &[&FOO]};
+   |                                 ^^^^ `Qiz` 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/issue-19380.rs:2:6
+   |
+LL | trait Qiz {
+   |       --- this trait cannot be made into an object...
+LL |   fn qiz();
+   |      ^^^ ...because associated function `qiz` has no `self` parameter
+   = note: required for the cast from `&Foo` to `&'static (dyn Qiz + 'static)`
+help: consider turning `qiz` into a method by giving it a `&self` argument
+   |
+LL |   fn qiz(&self);
+   |          +++++
+help: alternatively, consider constraining `qiz` so it does not apply to trait objects
+   |
+LL |   fn qiz() where Self: Sized;
+   |            +++++++++++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/issues/issue-24446.rs b/tests/ui/issues/issue-24446.rs
index 9ab952ade9c..6cf8846506d 100644
--- a/tests/ui/issues/issue-24446.rs
+++ b/tests/ui/issues/issue-24446.rs
@@ -2,6 +2,8 @@ fn main() {
     static foo: dyn Fn() -> u32 = || -> u32 {
         //~^ ERROR the size for values of type
         //~| ERROR cannot be shared between threads safely
+        //~| ERROR the size for values of type
+        //~| ERROR mismatched types
         0
     };
 }
diff --git a/tests/ui/issues/issue-24446.stderr b/tests/ui/issues/issue-24446.stderr
index 72d528f1619..9c206e5ef3c 100644
--- a/tests/ui/issues/issue-24446.stderr
+++ b/tests/ui/issues/issue-24446.stderr
@@ -15,6 +15,39 @@ LL |     static foo: dyn Fn() -> u32 = || -> u32 {
    |
    = help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)`
 
-error: aborting due to 2 previous errors
+error[E0277]: the size for values of type `(dyn Fn() -> u32 + 'static)` cannot be known at compilation time
+  --> $DIR/issue-24446.rs:2:35
+   |
+LL |       static foo: dyn Fn() -> u32 = || -> u32 {
+   |  ___________________________________^
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         0
+LL | |     };
+   | |_____^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)`
+   = note: constant expressions must have a statically known size
+
+error[E0308]: mismatched types
+  --> $DIR/issue-24446.rs:2:35
+   |
+LL |       static foo: dyn Fn() -> u32 = || -> u32 {
+   |  ___________________________________^
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         0
+LL | |     };
+   | |_____^ expected `dyn Fn`, found closure
+   |
+   = note: expected trait object `(dyn Fn() -> u32 + 'static)`
+                   found closure `{closure@$DIR/issue-24446.rs:2:35: 2:44}`
+
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/issues/issue-77919.rs b/tests/ui/issues/issue-77919.rs
index 3cbf493afb8..bf603314977 100644
--- a/tests/ui/issues/issue-77919.rs
+++ b/tests/ui/issues/issue-77919.rs
@@ -10,3 +10,4 @@ struct Multiply<N, M> {
 }
 impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
 //~^ ERROR cannot find type `VAL` in this scope
+//~| ERROR not all trait items implemented
diff --git a/tests/ui/issues/issue-77919.stderr b/tests/ui/issues/issue-77919.stderr
index 9d2f859e05a..dbbe70ff069 100644
--- a/tests/ui/issues/issue-77919.stderr
+++ b/tests/ui/issues/issue-77919.stderr
@@ -20,6 +20,16 @@ help: you might be missing a type parameter
 LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          +++++
 
-error: aborting due to 2 previous errors
+error[E0046]: not all trait items implemented, missing: `VAL`
+  --> $DIR/issue-77919.rs:11:1
+   |
+LL |     const VAL: T;
+   |     ------------ `VAL` from trait
+...
+LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0412`.
+Some errors have detailed explanations: E0046, E0412.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/layout/issue-84108.rs b/tests/ui/layout/issue-84108.rs
index dd025c9b443..af21d1d6210 100644
--- a/tests/ui/layout/issue-84108.rs
+++ b/tests/ui/layout/issue-84108.rs
@@ -9,6 +9,8 @@ static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
 const BAR: (&Path, [u8], usize) = ("hello", [], 42);
 //~^ ERROR cannot find type `Path` in this scope
 //~| ERROR the size for values of type `[u8]` cannot be known at compilation time
+//~| ERROR mismatched types
 
 static BAZ: ([u8], usize) = ([], 0);
 //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+//~| ERROR mismatched types
diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr
index 5ad450bed07..3a02e73f96b 100644
--- a/tests/ui/layout/issue-84108.stderr
+++ b/tests/ui/layout/issue-84108.stderr
@@ -30,7 +30,7 @@ LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/issue-84108.rs:13:13
+  --> $DIR/issue-84108.rs:14:13
    |
 LL | static BAZ: ([u8], usize) = ([], 0);
    |             ^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -38,7 +38,25 @@ LL | static BAZ: ([u8], usize) = ([], 0);
    = help: the trait `Sized` is not implemented for `[u8]`
    = note: only the last element of a tuple may have a dynamically sized type
 
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+  --> $DIR/issue-84108.rs:9:45
+   |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+   |                                             ^^ expected `[u8]`, found `[_; 0]`
+   |
+   = note: expected slice `[u8]`
+              found array `[_; 0]`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-84108.rs:14:30
+   |
+LL | static BAZ: ([u8], usize) = ([], 0);
+   |                              ^^ expected `[u8]`, found `[_; 0]`
+   |
+   = note: expected slice `[u8]`
+              found array `[_; 0]`
+
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0277, E0412.
+Some errors have detailed explanations: E0277, E0308, E0412.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr
index 30afcecf827..e61158a5d4d 100644
--- a/tests/ui/lifetimes/issue-26638.stderr
+++ b/tests/ui/lifetimes/issue-26638.stderr
@@ -44,6 +44,10 @@ LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.ne
    |
    = note: expected reference `&str`
                    found enum `Option<&str>`
+help: consider using `Option::expect` to unwrap the `Option<&str>` value, panicking if the value is an `Option::None`
+   |
+LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next().expect("REASON") }
+   |                                                                                +++++++++++++++++
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/issue-26638.rs:5:47
diff --git a/tests/ui/mismatched_types/async-unwrap-suggestion.rs b/tests/ui/mismatched_types/async-unwrap-suggestion.rs
new file mode 100644
index 00000000000..9698cc29ffd
--- /dev/null
+++ b/tests/ui/mismatched_types/async-unwrap-suggestion.rs
@@ -0,0 +1,22 @@
+// edition: 2021
+
+async fn dont_suggest() -> i32 {
+    if false {
+        return Ok(6);
+        //~^ ERROR mismatched types
+    }
+
+    5
+}
+
+async fn do_suggest() -> i32 {
+    if false {
+        let s = Ok(6);
+        return s;
+        //~^ ERROR mismatched types
+    }
+
+    5
+}
+
+fn main() {}
diff --git a/tests/ui/mismatched_types/async-unwrap-suggestion.stderr b/tests/ui/mismatched_types/async-unwrap-suggestion.stderr
new file mode 100644
index 00000000000..80ca76a4b86
--- /dev/null
+++ b/tests/ui/mismatched_types/async-unwrap-suggestion.stderr
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+  --> $DIR/async-unwrap-suggestion.rs:5:16
+   |
+LL |         return Ok(6);
+   |                ^^^^^ expected `i32`, found `Result<{integer}, _>`
+   |
+   = note: expected type `i32`
+              found enum `Result<{integer}, _>`
+
+error[E0308]: mismatched types
+  --> $DIR/async-unwrap-suggestion.rs:15:16
+   |
+LL |         return s;
+   |                ^ expected `i32`, found `Result<{integer}, _>`
+   |
+   = note: expected type `i32`
+              found enum `Result<{integer}, _>`
+help: consider using `Result::expect` to unwrap the `Result<{integer}, _>` value, panicking if the value is a `Result::Err`
+   |
+LL |         return s.expect("REASON");
+   |                 +++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs
new file mode 100644
index 00000000000..b288a9b05ef
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs
@@ -0,0 +1,23 @@
+#![allow(unused, dead_code)]
+
+fn test_unwrap() -> Option<i32> {
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b; // return type is not `Result`, we don't suggest ? here
+    //~^ ERROR mismatched types
+    Some(v)
+}
+
+fn test_unwrap_option() -> Result<i32, ()> {
+    let b = Some(1);
+    let v: i32 = b; // return type is not `Option`, we don't suggest ? here
+    //~^ ERROR mismatched types
+    Ok(v)
+}
+
+fn main() {
+    let v: i32 = Some(0); //~ ERROR mismatched types
+
+    let c = Ok(false);
+    let v: i32 = c; //~ ERROR mismatched types
+
+}
diff --git a/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr
new file mode 100644
index 00000000000..4f8f9b1a8a5
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-dont-suggest.rs:5:18
+   |
+LL |     let v: i32 = b; // return type is not `Result`, we don't suggest ? here
+   |            ---   ^ expected `i32`, found `Result<i32, ()>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Result<i32, ()>`
+help: consider using `Result::expect` to unwrap the `Result<i32, ()>` value, panicking if the value is a `Result::Err`
+   |
+LL |     let v: i32 = b.expect("REASON"); // return type is not `Result`, we don't suggest ? here
+   |                   +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-dont-suggest.rs:12:18
+   |
+LL |     let v: i32 = b; // return type is not `Option`, we don't suggest ? here
+   |            ---   ^ expected `i32`, found `Option<{integer}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<{integer}>`
+help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None`
+   |
+LL |     let v: i32 = b.expect("REASON"); // return type is not `Option`, we don't suggest ? here
+   |                   +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-dont-suggest.rs:18:18
+   |
+LL |     let v: i32 = Some(0);
+   |            ---   ^^^^^^^ expected `i32`, found `Option<{integer}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-dont-suggest.rs:21:18
+   |
+LL |     let v: i32 = c;
+   |            ---   ^ expected `i32`, found `Result<bool, _>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Result<bool, _>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed
new file mode 100644
index 00000000000..f3f560fe530
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+#![allow(unused, dead_code)]
+
+fn func() -> Option<i32> {
+    Some(1)
+}
+
+fn test_unwrap() -> Result<i32, ()> {
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b?; //~ ERROR mismatched types
+    Ok(v)
+}
+
+fn test_unwrap_option() -> Option<i32> {
+    let b = Some(1);
+    let v: i32 = b?; //~ ERROR mismatched types
+    Some(v)
+}
+
+fn main() {
+    let a = Some(1);
+    let v: i32 = a.expect("REASON"); //~ ERROR mismatched types
+
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b.expect("REASON"); //~ ERROR mismatched types
+
+    let v: i32 = func().expect("REASON"); //~ ERROR mismatched types
+
+    let a = None;
+    let v: i32 = a.expect("REASON"); //~ ERROR mismatched types
+}
diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs
new file mode 100644
index 00000000000..14020e872ff
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+#![allow(unused, dead_code)]
+
+fn func() -> Option<i32> {
+    Some(1)
+}
+
+fn test_unwrap() -> Result<i32, ()> {
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b; //~ ERROR mismatched types
+    Ok(v)
+}
+
+fn test_unwrap_option() -> Option<i32> {
+    let b = Some(1);
+    let v: i32 = b; //~ ERROR mismatched types
+    Some(v)
+}
+
+fn main() {
+    let a = Some(1);
+    let v: i32 = a; //~ ERROR mismatched types
+
+    let b: Result<i32, ()> = Ok(1);
+    let v: i32 = b; //~ ERROR mismatched types
+
+    let v: i32 = func(); //~ ERROR mismatched types
+
+    let a = None;
+    let v: i32 = a; //~ ERROR mismatched types
+}
diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr
new file mode 100644
index 00000000000..9de23447fed
--- /dev/null
+++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr
@@ -0,0 +1,93 @@
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:10:18
+   |
+LL |     let v: i32 = b;
+   |            ---   ^ expected `i32`, found `Result<i32, ()>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Result<i32, ()>`
+help: use the `?` operator to extract the `Result<i32, ()>` value, propagating a `Result::Err` value to the caller
+   |
+LL |     let v: i32 = b?;
+   |                   +
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:16:18
+   |
+LL |     let v: i32 = b;
+   |            ---   ^ expected `i32`, found `Option<{integer}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<{integer}>`
+help: use the `?` operator to extract the `Option<{integer}>` value, propagating an `Option::None` value to the caller
+   |
+LL |     let v: i32 = b?;
+   |                   +
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:22:18
+   |
+LL |     let v: i32 = a;
+   |            ---   ^ expected `i32`, found `Option<{integer}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<{integer}>`
+help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None`
+   |
+LL |     let v: i32 = a.expect("REASON");
+   |                   +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:25:18
+   |
+LL |     let v: i32 = b;
+   |            ---   ^ expected `i32`, found `Result<i32, ()>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Result<i32, ()>`
+help: consider using `Result::expect` to unwrap the `Result<i32, ()>` value, panicking if the value is a `Result::Err`
+   |
+LL |     let v: i32 = b.expect("REASON");
+   |                   +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:27:18
+   |
+LL |     let v: i32 = func();
+   |            ---   ^^^^^^ expected `i32`, found `Option<i32>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<i32>`
+help: consider using `Option::expect` to unwrap the `Option<i32>` value, panicking if the value is an `Option::None`
+   |
+LL |     let v: i32 = func().expect("REASON");
+   |                        +++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/mismatch-ty-unwrap-expect.rs:30:18
+   |
+LL |     let v: i32 = a;
+   |            ---   ^ expected `i32`, found `Option<_>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+              found enum `Option<_>`
+help: consider using `Option::expect` to unwrap the `Option<_>` value, panicking if the value is an `Option::None`
+   |
+LL |     let v: i32 = a.expect("REASON");
+   |                   +++++++++++++++++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/noexporttypeexe.stderr b/tests/ui/noexporttypeexe.stderr
index 26bafd31d01..bf88ceaa5d2 100644
--- a/tests/ui/noexporttypeexe.stderr
+++ b/tests/ui/noexporttypeexe.stderr
@@ -8,6 +8,10 @@ LL |   let x: isize = noexporttypelib::foo();
    |
    = note: expected type `isize`
               found enum `Option<isize>`
+help: consider using `Option::expect` to unwrap the `Option<isize>` value, panicking if the value is an `Option::None`
+   |
+LL |   let x: isize = noexporttypelib::foo().expect("REASON");
+   |                                        +++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/pattern/non-structural-match-types.mir.stderr b/tests/ui/pattern/non-structural-match-types.mir.stderr
new file mode 100644
index 00000000000..7a9e5b7e02e
--- /dev/null
+++ b/tests/ui/pattern/non-structural-match-types.mir.stderr
@@ -0,0 +1,14 @@
+error: `{closure@$DIR/non-structural-match-types.rs:12:17: 12:19}` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:12:9
+   |
+LL |         const { || {} } => {}
+   |         ^^^^^^^^^^^^^^^
+
+error: `{async block@$DIR/non-structural-match-types.rs:15:17: 15:25}` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:15:9
+   |
+LL |         const { async {} } => {}
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs
index fc52ee3d013..fb7779fa808 100644
--- a/tests/ui/pattern/non-structural-match-types.rs
+++ b/tests/ui/pattern/non-structural-match-types.rs
@@ -1,4 +1,7 @@
 // edition:2021
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![allow(incomplete_features)]
 #![allow(unreachable_code)]
 #![feature(const_async_blocks)]
diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr
deleted file mode 100644
index f3e0665fef5..00000000000
--- a/tests/ui/pattern/non-structural-match-types.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns
-  --> $DIR/non-structural-match-types.rs:9:9
-   |
-LL |         const { || {} } => {}
-   |         ^^^^^^^^^^^^^^^
-
-error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns
-  --> $DIR/non-structural-match-types.rs:12:9
-   |
-LL |         const { async {} } => {}
-   |         ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/pattern/non-structural-match-types.thir.stderr b/tests/ui/pattern/non-structural-match-types.thir.stderr
new file mode 100644
index 00000000000..7a9e5b7e02e
--- /dev/null
+++ b/tests/ui/pattern/non-structural-match-types.thir.stderr
@@ -0,0 +1,14 @@
+error: `{closure@$DIR/non-structural-match-types.rs:12:17: 12:19}` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:12:9
+   |
+LL |         const { || {} } => {}
+   |         ^^^^^^^^^^^^^^^
+
+error: `{async block@$DIR/non-structural-match-types.rs:15:17: 15:25}` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:15:9
+   |
+LL |         const { async {} } => {}
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/privacy/associated-item-privacy-trait.rs b/tests/ui/privacy/associated-item-privacy-trait.rs
index db77a6a7258..f038ae9e261 100644
--- a/tests/ui/privacy/associated-item-privacy-trait.rs
+++ b/tests/ui/privacy/associated-item-privacy-trait.rs
@@ -23,7 +23,7 @@ mod priv_trait {
         let _: <Pub as PrivTr>::AssocTy;
         //~^ ERROR associated type `PrivTr::AssocTy` is private
         pub type InSignatureTy = <Pub as PrivTr>::AssocTy;
-        //~^ ERROR trait `PrivTr` is private
+        //~^ ERROR associated type `PrivTr::AssocTy` is private
         pub trait InSignatureTr: PrivTr {}
         //~^ ERROR trait `PrivTr` is private
         impl PrivTr for u8 {}
diff --git a/tests/ui/privacy/associated-item-privacy-trait.stderr b/tests/ui/privacy/associated-item-privacy-trait.stderr
index eb905bf7ef8..4e9dfa4a835 100644
--- a/tests/ui/privacy/associated-item-privacy-trait.stderr
+++ b/tests/ui/privacy/associated-item-privacy-trait.stderr
@@ -53,11 +53,11 @@ LL |     priv_trait::mac!();
    |
    = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: trait `PrivTr` is private
+error: associated type `PrivTr::AssocTy` is private
   --> $DIR/associated-item-privacy-trait.rs:25:34
    |
 LL |         pub type InSignatureTy = <Pub as PrivTr>::AssocTy;
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^ private trait
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^ private associated type
 ...
 LL |     priv_trait::mac!();
    |     ------------------ in this macro invocation
diff --git a/tests/ui/privacy/private-in-public.rs b/tests/ui/privacy/private-in-public.rs
index f54f9e38faa..3fff2d51710 100644
--- a/tests/ui/privacy/private-in-public.rs
+++ b/tests/ui/privacy/private-in-public.rs
@@ -104,8 +104,8 @@ mod aliases_pub {
 
     // This should be OK, but associated type aliases are not substituted yet
     pub fn f3(arg: <Priv as PrivTr>::Assoc) {}
-    //~^ WARNING trait `aliases_pub::PrivTr` is more private than the item `aliases_pub::f3`
-    //~| WARNING type `aliases_pub::Priv` is more private than the item `aliases_pub::f3`
+    //~^ WARNING type `aliases_pub::Priv` is more private than the item `aliases_pub::f3`
+    //~| WARNING associated type `aliases_pub::PrivTr::Assoc` is more private than the item `aliases_pub::f3`
 
     impl PrivUseAlias {
         pub fn f(arg: Priv) {}
@@ -133,8 +133,8 @@ mod aliases_priv {
     pub fn f1(arg: PrivUseAlias) {} //~ WARNING type `Priv1` is more private than the item `aliases_priv::f1`
     pub fn f2(arg: PrivAlias) {} //~ WARNING type `Priv2` is more private than the item `aliases_priv::f2`
     pub fn f3(arg: <Priv as PrivTr>::Assoc) {}
-    //~^ WARNING trait `aliases_priv::PrivTr` is more private than the item `aliases_priv::f3`
-    //~| WARNING type `aliases_priv::Priv` is more private than the item `aliases_priv::f3`
+    //~^ WARNING type `aliases_priv::Priv` is more private than the item `aliases_priv::f3`
+    //~| WARNING associated type `aliases_priv::PrivTr::Assoc` is more private than the item `aliases_priv::f3`
 }
 
 mod aliases_params {
diff --git a/tests/ui/privacy/private-in-public.stderr b/tests/ui/privacy/private-in-public.stderr
index d3f7f0f637f..49cc2e19bf0 100644
--- a/tests/ui/privacy/private-in-public.stderr
+++ b/tests/ui/privacy/private-in-public.stderr
@@ -276,17 +276,17 @@ note: but type `impls::Priv` is only usable at visibility `pub(self)`
 LL |     struct Priv;
    |     ^^^^^^^^^^^
 
-warning: trait `aliases_pub::PrivTr` is more private than the item `aliases_pub::f3`
+warning: associated type `aliases_pub::PrivTr::Assoc` is more private than the item `aliases_pub::f3`
   --> $DIR/private-in-public.rs:106:5
    |
 LL |     pub fn f3(arg: <Priv as PrivTr>::Assoc) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function `aliases_pub::f3` is reachable at visibility `pub(crate)`
    |
-note: but trait `aliases_pub::PrivTr` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public.rs:100:5
+note: but associated type `aliases_pub::PrivTr::Assoc` is only usable at visibility `pub(self)`
+  --> $DIR/private-in-public.rs:101:9
    |
-LL |     trait PrivTr {
-   |     ^^^^^^^^^^^^
+LL |         type Assoc = m::Pub3;
+   |         ^^^^^^^^^^
 
 warning: type `aliases_pub::Priv` is more private than the item `aliases_pub::f3`
   --> $DIR/private-in-public.rs:106:5
@@ -324,17 +324,17 @@ note: but type `Priv2` is only usable at visibility `pub(self)`
 LL |     struct Priv2;
    |     ^^^^^^^^^^^^
 
-warning: trait `aliases_priv::PrivTr` is more private than the item `aliases_priv::f3`
+warning: associated type `aliases_priv::PrivTr::Assoc` is more private than the item `aliases_priv::f3`
   --> $DIR/private-in-public.rs:135:5
    |
 LL |     pub fn f3(arg: <Priv as PrivTr>::Assoc) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function `aliases_priv::f3` is reachable at visibility `pub(crate)`
    |
-note: but trait `aliases_priv::PrivTr` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public.rs:128:5
+note: but associated type `aliases_priv::PrivTr::Assoc` is only usable at visibility `pub(self)`
+  --> $DIR/private-in-public.rs:129:9
    |
-LL |     trait PrivTr {
-   |     ^^^^^^^^^^^^
+LL |         type Assoc = Priv3;
+   |         ^^^^^^^^^^
 
 warning: type `aliases_priv::Priv` is more private than the item `aliases_priv::f3`
   --> $DIR/private-in-public.rs:135:5
diff --git a/tests/ui/proc-macro/bad-projection.rs b/tests/ui/proc-macro/bad-projection.rs
index d214c7ac8b2..c7cffdc9b47 100644
--- a/tests/ui/proc-macro/bad-projection.rs
+++ b/tests/ui/proc-macro/bad-projection.rs
@@ -13,3 +13,5 @@ trait Project {
 #[proc_macro]
 pub fn uwu() -> <() as Project>::Assoc {}
 //~^ ERROR the trait bound `(): Project` is not satisfied
+//~| ERROR the trait bound `(): Project` is not satisfied
+//~| ERROR function is expected to take 1 argument, but it takes 0 arguments
diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr
index 8716defa17a..aea5d6d7c84 100644
--- a/tests/ui/proc-macro/bad-projection.stderr
+++ b/tests/ui/proc-macro/bad-projection.stderr
@@ -10,6 +10,32 @@ help: this trait has no implementations, consider adding one
 LL | trait Project {
    | ^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
+  --> $DIR/bad-projection.rs:14:1
+   |
+LL | pub fn uwu() -> <() as Project>::Assoc {}
+   | --------------------------------------^^^
+   | |
+   | expected function that takes 1 argument
+   | takes 0 arguments
+   | required by a bound introduced by this call
+   |
+note: required by a bound in `ProcMacro::bang`
+  --> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL
+
+error[E0277]: the trait bound `(): Project` is not satisfied
+  --> $DIR/bad-projection.rs:14:1
+   |
+LL | pub fn uwu() -> <() as Project>::Assoc {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/bad-projection.rs:9:1
+   |
+LL | trait Project {
+   | ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0593.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/reachable/reachable-unnameable-type-alias.rs b/tests/ui/reachable/reachable-unnameable-type-alias.rs
index 461355f87cf..ce830d2d4b4 100644
--- a/tests/ui/reachable/reachable-unnameable-type-alias.rs
+++ b/tests/ui/reachable/reachable-unnameable-type-alias.rs
@@ -1,14 +1,14 @@
 // run-pass
 
 #![feature(staged_api)]
-#![stable(feature = "a", since = "b")]
+#![stable(feature = "a", since = "3.3.3")]
 
 mod inner_private_module {
     // UnnameableTypeAlias isn't marked as reachable, so no stability annotation is required here
     pub type UnnameableTypeAlias = u8;
 }
 
-#[stable(feature = "a", since = "b")]
+#[stable(feature = "a", since = "3.3.3")]
 pub fn f() -> inner_private_module::UnnameableTypeAlias {
     0
 }
diff --git a/tests/ui/repr/16-bit-repr-c-enum.rs b/tests/ui/repr/16-bit-repr-c-enum.rs
index d4fea2b192b..987fd455fcc 100644
--- a/tests/ui/repr/16-bit-repr-c-enum.rs
+++ b/tests/ui/repr/16-bit-repr-c-enum.rs
@@ -8,7 +8,7 @@
 #![feature(no_core, lang_items, intrinsics, staged_api, rustc_attrs)]
 #![no_core]
 #![crate_type = "lib"]
-#![stable(feature = "", since = "")]
+#![stable(feature = "intrinsics_for_test", since = "3.3.3")]
 #![allow(dead_code)]
 
 // Test that the repr(C) attribute doesn't break compilation
@@ -22,8 +22,8 @@ enum Foo {
 }
 
 extern "rust-intrinsic" {
-    #[stable(feature = "", since = "")]
-    #[rustc_const_stable(feature = "", since = "")]
+    #[stable(feature = "intrinsics_for_test", since = "3.3.3")]
+    #[rustc_const_stable(feature = "intrinsics_for_test", since = "3.3.3")]
     #[rustc_safe_intrinsic]
     fn size_of<T>() -> usize;
 }
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
index 1b45cd9aab9..13881e042a3 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
@@ -7,7 +7,7 @@
 
 #![feature(staged_api)]
 #![feature(const_trait_impl)]
-#![stable(since = "1", feature = "foo")]
+#![stable(feature = "foo", since = "3.3.3")]
 
 #[const_trait]
 trait Tr {
diff --git a/tests/ui/simd/array-trait.rs b/tests/ui/simd/array-trait.rs
index 45c10b37816..883d718c49b 100644
--- a/tests/ui/simd/array-trait.rs
+++ b/tests/ui/simd/array-trait.rs
@@ -22,6 +22,7 @@ impl Simd for i32x4 {
 #[derive(Copy, Clone)]
 pub struct T<S: Simd>([S::Lane; S::SIZE]);
 //~^ ERROR unconstrained generic constant
+//~| ERROR SIMD vector element type should be a primitive scalar
 
 extern "platform-intrinsic" {
     fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
diff --git a/tests/ui/simd/array-trait.stderr b/tests/ui/simd/array-trait.stderr
index 765215c3939..cf6026912aa 100644
--- a/tests/ui/simd/array-trait.stderr
+++ b/tests/ui/simd/array-trait.stderr
@@ -6,5 +6,12 @@ LL | pub struct T<S: Simd>([S::Lane; S::SIZE]);
    |
    = help: try adding a `where` bound using this expression: `where [(); S::SIZE]:`
 
-error: aborting due to previous error
+error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type
+  --> $DIR/array-trait.rs:23:1
+   |
+LL | pub struct T<S: Simd>([S::Lane; S::SIZE]);
+   | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0077`.
diff --git a/tests/ui/span/lint-unused-unsafe-thir.rs b/tests/ui/span/lint-unused-unsafe-thir.rs
deleted file mode 100644
index adb72c26bba..00000000000
--- a/tests/ui/span/lint-unused-unsafe-thir.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// FIXME: This file is tracking old lint behavior that's still unchanged in the
-// unstable -Zthir-unsafeck implementation. See lint-unused-unsafe.rs for more details.
-//
-// Exercise the unused_unsafe attribute in some positive and negative cases
-
-// compile-flags: -Zthir-unsafeck
-
-#![allow(dead_code)]
-#![deny(unused_unsafe)]
-
-
-mod foo {
-    extern "C" {
-        pub fn bar();
-    }
-}
-
-fn callback<T, F>(_f: F) -> T where F: FnOnce() -> T { panic!() }
-unsafe fn unsf() {}
-
-fn bad1() { unsafe {} }                  //~ ERROR: unnecessary `unsafe` block
-fn bad2() { unsafe { bad1() } }          //~ ERROR: unnecessary `unsafe` block
-unsafe fn bad3() { unsafe {} }           //~ ERROR: unnecessary `unsafe` block
-fn bad4() { unsafe { callback(||{}) } }  //~ ERROR: unnecessary `unsafe` block
-unsafe fn bad5() { unsafe { unsf() } }
-fn bad6() {
-    unsafe {                             // don't put the warning here
-        unsafe {                         //~ ERROR: unnecessary `unsafe` block
-            unsf()
-        }
-    }
-}
-unsafe fn bad7() {
-    unsafe {
-        unsafe {                         //~ ERROR: unnecessary `unsafe` block
-            unsf()
-        }
-    }
-}
-
-unsafe fn good0() { unsf() }
-fn good1() { unsafe { unsf() } }
-fn good2() {
-    /* bug uncovered when implementing warning about unused unsafe blocks. Be
-       sure that when purity is inherited that the source of the unsafe-ness
-       is tracked correctly */
-    unsafe {
-        unsafe fn what() -> Vec<String> { panic!() }
-
-        callback(|| {
-            what();
-        });
-    }
-}
-
-unsafe fn good3() { foo::bar() }
-fn good4() { unsafe { foo::bar() } }
-
-#[allow(unused_unsafe)] fn allowed() { unsafe {} }
-
-fn main() {}
diff --git a/tests/ui/span/lint-unused-unsafe-thir.stderr b/tests/ui/span/lint-unused-unsafe-thir.stderr
deleted file mode 100644
index 3bcbb759775..00000000000
--- a/tests/ui/span/lint-unused-unsafe-thir.stderr
+++ /dev/null
@@ -1,50 +0,0 @@
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe-thir.rs:21:13
-   |
-LL | fn bad1() { unsafe {} }
-   |             ^^^^^^ unnecessary `unsafe` block
-   |
-note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe-thir.rs:9:9
-   |
-LL | #![deny(unused_unsafe)]
-   |         ^^^^^^^^^^^^^
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe-thir.rs:22:13
-   |
-LL | fn bad2() { unsafe { bad1() } }
-   |             ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe-thir.rs:23:20
-   |
-LL | unsafe fn bad3() { unsafe {} }
-   | ----------------   ^^^^^^ unnecessary `unsafe` block
-   | |
-   | because it's nested under this `unsafe` fn
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe-thir.rs:24:13
-   |
-LL | fn bad4() { unsafe { callback(||{}) } }
-   |             ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe-thir.rs:28:9
-   |
-LL |     unsafe {                             // don't put the warning here
-   |     ------ because it's nested under this `unsafe` block
-LL |         unsafe {
-   |         ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe-thir.rs:35:9
-   |
-LL |     unsafe {
-   |     ------ because it's nested under this `unsafe` block
-LL |         unsafe {
-   |         ^^^^^^ unnecessary `unsafe` block
-
-error: aborting due to 6 previous errors
-
diff --git a/tests/ui/span/lint-unused-unsafe.mir.stderr b/tests/ui/span/lint-unused-unsafe.mir.stderr
index d8412908c73..9e8d3359242 100644
--- a/tests/ui/span/lint-unused-unsafe.mir.stderr
+++ b/tests/ui/span/lint-unused-unsafe.mir.stderr
@@ -1,77 +1,77 @@
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:26:13
+  --> $DIR/lint-unused-unsafe.rs:22:13
    |
 LL | fn bad1() { unsafe {} }
    |             ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:14:9
+  --> $DIR/lint-unused-unsafe.rs:10:9
    |
 LL | #![deny(unused_unsafe)]
    |         ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:27:13
+  --> $DIR/lint-unused-unsafe.rs:23:13
    |
 LL | fn bad2() { unsafe { bad1() } }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:28:20
+  --> $DIR/lint-unused-unsafe.rs:24:20
    |
 LL | unsafe fn bad3() { unsafe {} }
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:29:13
+  --> $DIR/lint-unused-unsafe.rs:25:13
    |
 LL | fn bad4() { unsafe { callback(||{}) } }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:32:5
+  --> $DIR/lint-unused-unsafe.rs:28:5
    |
 LL |     unsafe {
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:39:5
+  --> $DIR/lint-unused-unsafe.rs:35:5
    |
 LL |     unsafe {
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:74:9
+  --> $DIR/lint-unused-unsafe.rs:70:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:83:9
+  --> $DIR/lint-unused-unsafe.rs:79:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:84:13
+  --> $DIR/lint-unused-unsafe.rs:80:13
    |
 LL |             unsafe {}
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:85:13
+  --> $DIR/lint-unused-unsafe.rs:81:13
    |
 LL |             unsafe {}
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:90:9
+  --> $DIR/lint-unused-unsafe.rs:86:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:100:13
+  --> $DIR/lint-unused-unsafe.rs:96:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -80,7 +80,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:101:13
+  --> $DIR/lint-unused-unsafe.rs:97:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -89,7 +89,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:102:13
+  --> $DIR/lint-unused-unsafe.rs:98:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -98,7 +98,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:112:17
+  --> $DIR/lint-unused-unsafe.rs:108:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -107,13 +107,13 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:110:20
+  --> $DIR/lint-unused-unsafe.rs:106:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:113:17
+  --> $DIR/lint-unused-unsafe.rs:109:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -122,7 +122,7 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:114:17
+  --> $DIR/lint-unused-unsafe.rs:110:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -131,37 +131,37 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:124:9
+  --> $DIR/lint-unused-unsafe.rs:120:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:134:9
+  --> $DIR/lint-unused-unsafe.rs:130:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:135:13
+  --> $DIR/lint-unused-unsafe.rs:131:13
    |
 LL |             unsafe {}
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:136:13
+  --> $DIR/lint-unused-unsafe.rs:132:13
    |
 LL |             unsafe {}
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:142:9
+  --> $DIR/lint-unused-unsafe.rs:138:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:153:13
+  --> $DIR/lint-unused-unsafe.rs:149:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -170,7 +170,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:154:13
+  --> $DIR/lint-unused-unsafe.rs:150:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -179,7 +179,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:155:13
+  --> $DIR/lint-unused-unsafe.rs:151:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -188,7 +188,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:166:17
+  --> $DIR/lint-unused-unsafe.rs:162:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -197,13 +197,13 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:164:20
+  --> $DIR/lint-unused-unsafe.rs:160:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:167:17
+  --> $DIR/lint-unused-unsafe.rs:163:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -212,7 +212,7 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:168:17
+  --> $DIR/lint-unused-unsafe.rs:164:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -221,37 +221,37 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:178:9
+  --> $DIR/lint-unused-unsafe.rs:174:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:188:9
+  --> $DIR/lint-unused-unsafe.rs:184:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:189:13
+  --> $DIR/lint-unused-unsafe.rs:185:13
    |
 LL |             unsafe {}
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:190:13
+  --> $DIR/lint-unused-unsafe.rs:186:13
    |
 LL |             unsafe {}
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:196:9
+  --> $DIR/lint-unused-unsafe.rs:192:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:207:13
+  --> $DIR/lint-unused-unsafe.rs:203:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -260,7 +260,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:208:13
+  --> $DIR/lint-unused-unsafe.rs:204:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -269,7 +269,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:209:13
+  --> $DIR/lint-unused-unsafe.rs:205:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -278,7 +278,7 @@ LL |             unsafe { unsf() }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:220:17
+  --> $DIR/lint-unused-unsafe.rs:216:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -287,13 +287,13 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:218:20
+  --> $DIR/lint-unused-unsafe.rs:214:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:221:17
+  --> $DIR/lint-unused-unsafe.rs:217:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -302,7 +302,7 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:222:17
+  --> $DIR/lint-unused-unsafe.rs:218:17
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -311,13 +311,13 @@ LL |                 unsafe { unsf() }
    |                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:242:9
+  --> $DIR/lint-unused-unsafe.rs:238:9
    |
 LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:255:13
+  --> $DIR/lint-unused-unsafe.rs:251:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -325,7 +325,7 @@ LL |             unsafe {
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:268:13
+  --> $DIR/lint-unused-unsafe.rs:264:13
    |
 LL |         unsafe {
    |         ------ because it's nested under this `unsafe` block
@@ -333,37 +333,37 @@ LL |             unsafe {
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:286:20
+  --> $DIR/lint-unused-unsafe.rs:282:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:295:20
+  --> $DIR/lint-unused-unsafe.rs:291:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:296:24
+  --> $DIR/lint-unused-unsafe.rs:292:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:297:24
+  --> $DIR/lint-unused-unsafe.rs:293:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:302:20
+  --> $DIR/lint-unused-unsafe.rs:298:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:312:24
+  --> $DIR/lint-unused-unsafe.rs:308:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -372,7 +372,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:313:24
+  --> $DIR/lint-unused-unsafe.rs:309:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -381,7 +381,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:314:24
+  --> $DIR/lint-unused-unsafe.rs:310:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -390,7 +390,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:324:28
+  --> $DIR/lint-unused-unsafe.rs:320:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -399,13 +399,13 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:322:20
+  --> $DIR/lint-unused-unsafe.rs:318:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:325:28
+  --> $DIR/lint-unused-unsafe.rs:321:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -414,7 +414,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:326:28
+  --> $DIR/lint-unused-unsafe.rs:322:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -423,37 +423,37 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:336:20
+  --> $DIR/lint-unused-unsafe.rs:332:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:346:20
+  --> $DIR/lint-unused-unsafe.rs:342:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:347:24
+  --> $DIR/lint-unused-unsafe.rs:343:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:348:24
+  --> $DIR/lint-unused-unsafe.rs:344:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:354:20
+  --> $DIR/lint-unused-unsafe.rs:350:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:365:24
+  --> $DIR/lint-unused-unsafe.rs:361:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -462,7 +462,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:366:24
+  --> $DIR/lint-unused-unsafe.rs:362:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -471,7 +471,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:367:24
+  --> $DIR/lint-unused-unsafe.rs:363:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -480,7 +480,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:378:28
+  --> $DIR/lint-unused-unsafe.rs:374:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -489,13 +489,13 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:376:20
+  --> $DIR/lint-unused-unsafe.rs:372:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:379:28
+  --> $DIR/lint-unused-unsafe.rs:375:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -504,7 +504,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:380:28
+  --> $DIR/lint-unused-unsafe.rs:376:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -513,37 +513,37 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:390:20
+  --> $DIR/lint-unused-unsafe.rs:386:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:400:20
+  --> $DIR/lint-unused-unsafe.rs:396:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:401:24
+  --> $DIR/lint-unused-unsafe.rs:397:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:402:24
+  --> $DIR/lint-unused-unsafe.rs:398:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:408:20
+  --> $DIR/lint-unused-unsafe.rs:404:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:419:24
+  --> $DIR/lint-unused-unsafe.rs:415:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -552,7 +552,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:420:24
+  --> $DIR/lint-unused-unsafe.rs:416:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -561,7 +561,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:421:24
+  --> $DIR/lint-unused-unsafe.rs:417:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -570,7 +570,7 @@ LL |             let _ = || unsafe { unsf() };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:432:28
+  --> $DIR/lint-unused-unsafe.rs:428:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -579,13 +579,13 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:430:20
+  --> $DIR/lint-unused-unsafe.rs:426:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:433:28
+  --> $DIR/lint-unused-unsafe.rs:429:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -594,7 +594,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:434:28
+  --> $DIR/lint-unused-unsafe.rs:430:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -603,13 +603,13 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:454:20
+  --> $DIR/lint-unused-unsafe.rs:450:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:467:24
+  --> $DIR/lint-unused-unsafe.rs:463:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -617,7 +617,7 @@ LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:480:24
+  --> $DIR/lint-unused-unsafe.rs:476:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -625,37 +625,37 @@ LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:499:20
+  --> $DIR/lint-unused-unsafe.rs:495:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:508:20
+  --> $DIR/lint-unused-unsafe.rs:504:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:509:24
+  --> $DIR/lint-unused-unsafe.rs:505:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:510:24
+  --> $DIR/lint-unused-unsafe.rs:506:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:515:20
+  --> $DIR/lint-unused-unsafe.rs:511:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:525:24
+  --> $DIR/lint-unused-unsafe.rs:521:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -664,7 +664,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:526:24
+  --> $DIR/lint-unused-unsafe.rs:522:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -673,7 +673,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:527:24
+  --> $DIR/lint-unused-unsafe.rs:523:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -682,7 +682,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:537:28
+  --> $DIR/lint-unused-unsafe.rs:533:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -691,13 +691,13 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:535:20
+  --> $DIR/lint-unused-unsafe.rs:531:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:538:28
+  --> $DIR/lint-unused-unsafe.rs:534:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -706,7 +706,7 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:539:28
+  --> $DIR/lint-unused-unsafe.rs:535:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -715,37 +715,37 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:549:20
+  --> $DIR/lint-unused-unsafe.rs:545:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:559:20
+  --> $DIR/lint-unused-unsafe.rs:555:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:560:24
+  --> $DIR/lint-unused-unsafe.rs:556:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:561:24
+  --> $DIR/lint-unused-unsafe.rs:557:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:567:20
+  --> $DIR/lint-unused-unsafe.rs:563:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:578:24
+  --> $DIR/lint-unused-unsafe.rs:574:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -754,7 +754,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:579:24
+  --> $DIR/lint-unused-unsafe.rs:575:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -763,7 +763,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:580:24
+  --> $DIR/lint-unused-unsafe.rs:576:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -772,7 +772,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:591:28
+  --> $DIR/lint-unused-unsafe.rs:587:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -781,13 +781,13 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:589:20
+  --> $DIR/lint-unused-unsafe.rs:585:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:592:28
+  --> $DIR/lint-unused-unsafe.rs:588:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -796,7 +796,7 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:593:28
+  --> $DIR/lint-unused-unsafe.rs:589:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -805,37 +805,37 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:603:20
+  --> $DIR/lint-unused-unsafe.rs:599:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:613:20
+  --> $DIR/lint-unused-unsafe.rs:609:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:614:24
+  --> $DIR/lint-unused-unsafe.rs:610:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:615:24
+  --> $DIR/lint-unused-unsafe.rs:611:24
    |
 LL |             let _ = || unsafe {};
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:621:20
+  --> $DIR/lint-unused-unsafe.rs:617:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:632:24
+  --> $DIR/lint-unused-unsafe.rs:628:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -844,7 +844,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:633:24
+  --> $DIR/lint-unused-unsafe.rs:629:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -853,7 +853,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:634:24
+  --> $DIR/lint-unused-unsafe.rs:630:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -862,7 +862,7 @@ LL |             let _ = || unsafe { let _ = || unsf(); };
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:645:28
+  --> $DIR/lint-unused-unsafe.rs:641:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -871,13 +871,13 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:643:20
+  --> $DIR/lint-unused-unsafe.rs:639:20
    |
 LL |             #[deny(unused_unsafe)]
    |                    ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:646:28
+  --> $DIR/lint-unused-unsafe.rs:642:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -886,7 +886,7 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:647:28
+  --> $DIR/lint-unused-unsafe.rs:643:28
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -895,13 +895,13 @@ LL |                 let _ = || unsafe { let _ = || unsf(); };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:667:20
+  --> $DIR/lint-unused-unsafe.rs:663:20
    |
 LL |         let _ = || unsafe {
    |                    ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:680:24
+  --> $DIR/lint-unused-unsafe.rs:676:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -909,7 +909,7 @@ LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:693:24
+  --> $DIR/lint-unused-unsafe.rs:689:24
    |
 LL |         let _ = || unsafe {
    |                    ------ because it's nested under this `unsafe` block
@@ -917,37 +917,37 @@ LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:711:24
+  --> $DIR/lint-unused-unsafe.rs:707:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:721:24
+  --> $DIR/lint-unused-unsafe.rs:717:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:722:28
+  --> $DIR/lint-unused-unsafe.rs:718:28
    |
 LL |                 let _ = || unsafe {};
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:723:28
+  --> $DIR/lint-unused-unsafe.rs:719:28
    |
 LL |                 let _ = || unsafe {};
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:729:24
+  --> $DIR/lint-unused-unsafe.rs:725:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:740:28
+  --> $DIR/lint-unused-unsafe.rs:736:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -956,7 +956,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:741:28
+  --> $DIR/lint-unused-unsafe.rs:737:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -965,7 +965,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:742:28
+  --> $DIR/lint-unused-unsafe.rs:738:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -974,7 +974,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:753:32
+  --> $DIR/lint-unused-unsafe.rs:749:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -983,13 +983,13 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:751:24
+  --> $DIR/lint-unused-unsafe.rs:747:24
    |
 LL |                 #[deny(unused_unsafe)]
    |                        ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:754:32
+  --> $DIR/lint-unused-unsafe.rs:750:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -998,7 +998,7 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:755:32
+  --> $DIR/lint-unused-unsafe.rs:751:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1007,37 +1007,37 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:765:24
+  --> $DIR/lint-unused-unsafe.rs:761:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:775:24
+  --> $DIR/lint-unused-unsafe.rs:771:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:776:28
+  --> $DIR/lint-unused-unsafe.rs:772:28
    |
 LL |                 let _ = || unsafe {};
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:777:28
+  --> $DIR/lint-unused-unsafe.rs:773:28
    |
 LL |                 let _ = || unsafe {};
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:783:24
+  --> $DIR/lint-unused-unsafe.rs:779:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:794:28
+  --> $DIR/lint-unused-unsafe.rs:790:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1046,7 +1046,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:795:28
+  --> $DIR/lint-unused-unsafe.rs:791:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1055,7 +1055,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:796:28
+  --> $DIR/lint-unused-unsafe.rs:792:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1064,7 +1064,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:807:32
+  --> $DIR/lint-unused-unsafe.rs:803:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1073,13 +1073,13 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:805:24
+  --> $DIR/lint-unused-unsafe.rs:801:24
    |
 LL |                 #[deny(unused_unsafe)]
    |                        ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:808:32
+  --> $DIR/lint-unused-unsafe.rs:804:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1088,7 +1088,7 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:809:32
+  --> $DIR/lint-unused-unsafe.rs:805:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1097,13 +1097,13 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:829:24
+  --> $DIR/lint-unused-unsafe.rs:825:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:842:28
+  --> $DIR/lint-unused-unsafe.rs:838:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1111,7 +1111,7 @@ LL |                 let _ = || unsafe {
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:855:28
+  --> $DIR/lint-unused-unsafe.rs:851:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1119,37 +1119,37 @@ LL |                 let _ = || unsafe {
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:869:24
+  --> $DIR/lint-unused-unsafe.rs:865:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:879:24
+  --> $DIR/lint-unused-unsafe.rs:875:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:880:28
+  --> $DIR/lint-unused-unsafe.rs:876:28
    |
 LL |                 let _ = || unsafe {};
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:881:28
+  --> $DIR/lint-unused-unsafe.rs:877:28
    |
 LL |                 let _ = || unsafe {};
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:887:24
+  --> $DIR/lint-unused-unsafe.rs:883:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:898:28
+  --> $DIR/lint-unused-unsafe.rs:894:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1158,7 +1158,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:899:28
+  --> $DIR/lint-unused-unsafe.rs:895:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1167,7 +1167,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:900:28
+  --> $DIR/lint-unused-unsafe.rs:896:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1176,7 +1176,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:911:32
+  --> $DIR/lint-unused-unsafe.rs:907:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1185,13 +1185,13 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:909:24
+  --> $DIR/lint-unused-unsafe.rs:905:24
    |
 LL |                 #[deny(unused_unsafe)]
    |                        ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:912:32
+  --> $DIR/lint-unused-unsafe.rs:908:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1200,7 +1200,7 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:913:32
+  --> $DIR/lint-unused-unsafe.rs:909:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1209,37 +1209,37 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:923:24
+  --> $DIR/lint-unused-unsafe.rs:919:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:933:24
+  --> $DIR/lint-unused-unsafe.rs:929:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:934:28
+  --> $DIR/lint-unused-unsafe.rs:930:28
    |
 LL |                 let _ = || unsafe {};
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:935:28
+  --> $DIR/lint-unused-unsafe.rs:931:28
    |
 LL |                 let _ = || unsafe {};
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:941:24
+  --> $DIR/lint-unused-unsafe.rs:937:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:952:28
+  --> $DIR/lint-unused-unsafe.rs:948:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1248,7 +1248,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:953:28
+  --> $DIR/lint-unused-unsafe.rs:949:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1257,7 +1257,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:954:28
+  --> $DIR/lint-unused-unsafe.rs:950:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1266,7 +1266,7 @@ LL |                 let _ = || unsafe { unsf() };
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:965:32
+  --> $DIR/lint-unused-unsafe.rs:961:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1275,13 +1275,13 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:963:24
+  --> $DIR/lint-unused-unsafe.rs:959:24
    |
 LL |                 #[deny(unused_unsafe)]
    |                        ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:966:32
+  --> $DIR/lint-unused-unsafe.rs:962:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1290,7 +1290,7 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:967:32
+  --> $DIR/lint-unused-unsafe.rs:963:32
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1299,13 +1299,13 @@ LL |                     let _ = || unsafe { unsf() };
    |                                ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:987:24
+  --> $DIR/lint-unused-unsafe.rs:983:24
    |
 LL |             let _ = || unsafe {
    |                        ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1000:28
+  --> $DIR/lint-unused-unsafe.rs:996:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1313,7 +1313,7 @@ LL |                 let _ = || unsafe {
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1013:28
+  --> $DIR/lint-unused-unsafe.rs:1009:28
    |
 LL |             let _ = || unsafe {
    |                        ------ because it's nested under this `unsafe` block
@@ -1321,13 +1321,13 @@ LL |                 let _ = || unsafe {
    |                            ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1059:29
+  --> $DIR/lint-unused-unsafe.rs:1055:29
    |
 LL |             let _ = async { unsafe {
    |                             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1066:33
+  --> $DIR/lint-unused-unsafe.rs:1062:33
    |
 LL |             let _ = async { unsafe {
    |                             ------ because it's nested under this `unsafe` block
@@ -1336,7 +1336,7 @@ LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
    |                                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1067:33
+  --> $DIR/lint-unused-unsafe.rs:1063:33
    |
 LL |             let _ = async { unsafe {
    |                             ------ because it's nested under this `unsafe` block
@@ -1345,7 +1345,7 @@ LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
    |                                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1068:33
+  --> $DIR/lint-unused-unsafe.rs:1064:33
    |
 LL |             let _ = async { unsafe {
    |                             ------ because it's nested under this `unsafe` block
@@ -1354,13 +1354,13 @@ LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
    |                                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1073:29
+  --> $DIR/lint-unused-unsafe.rs:1069:29
    |
 LL |             let _ = async { unsafe {
    |                             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1080:33
+  --> $DIR/lint-unused-unsafe.rs:1076:33
    |
 LL |             let _ = async { unsafe {
    |                             ------ because it's nested under this `unsafe` block
@@ -1369,7 +1369,7 @@ LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
    |                                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1081:33
+  --> $DIR/lint-unused-unsafe.rs:1077:33
    |
 LL |             let _ = async { unsafe {
    |                             ------ because it's nested under this `unsafe` block
@@ -1378,7 +1378,7 @@ LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
    |                                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1082:33
+  --> $DIR/lint-unused-unsafe.rs:1078:33
    |
 LL |             let _ = async { unsafe {
    |                             ------ because it's nested under this `unsafe` block
@@ -1387,13 +1387,13 @@ LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
    |                                 ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1092:22
+  --> $DIR/lint-unused-unsafe.rs:1088:22
    |
 LL |         let _x: [(); unsafe { 0 }] = [];
    |                      ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:1096:22
+  --> $DIR/lint-unused-unsafe.rs:1092:22
    |
 LL |         let _x: [(); unsafe { unsafe { size() } }] = [];
    |                      ^^^^^^ unnecessary `unsafe` block
diff --git a/tests/ui/span/lint-unused-unsafe.rs b/tests/ui/span/lint-unused-unsafe.rs
index 5d042768be0..ca615f64f22 100644
--- a/tests/ui/span/lint-unused-unsafe.rs
+++ b/tests/ui/span/lint-unused-unsafe.rs
@@ -3,12 +3,8 @@
 
 // edition:2018
 
-// revisions: mir
-
-// FIXME: Adapt -Zthir-unsafeck to behave the same as the mir version after #93678,
-// then delete lint-unused-unsafe-thir.rs, and go back to using the settings below
-// // revisions: mir thir
-// // [thir]compile-flags: -Zthir-unsafeck
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![allow(dead_code)]
 #![deny(unused_unsafe)]
diff --git a/tests/ui/span/lint-unused-unsafe.thir.stderr b/tests/ui/span/lint-unused-unsafe.thir.stderr
new file mode 100644
index 00000000000..9e8d3359242
--- /dev/null
+++ b/tests/ui/span/lint-unused-unsafe.thir.stderr
@@ -0,0 +1,1402 @@
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:22:13
+   |
+LL | fn bad1() { unsafe {} }
+   |             ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:10:9
+   |
+LL | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:23:13
+   |
+LL | fn bad2() { unsafe { bad1() } }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:24:20
+   |
+LL | unsafe fn bad3() { unsafe {} }
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:25:13
+   |
+LL | fn bad4() { unsafe { callback(||{}) } }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:28:5
+   |
+LL |     unsafe {
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:35:5
+   |
+LL |     unsafe {
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:70:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:79:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:80:13
+   |
+LL |             unsafe {}
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:81:13
+   |
+LL |             unsafe {}
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:86:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:96:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+LL |             unsf();
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:97:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:98:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:108:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:106:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:109:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:110:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:120:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:130:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:131:13
+   |
+LL |             unsafe {}
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:132:13
+   |
+LL |             unsafe {}
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:138:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:149:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+LL |             unsf();
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:150:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:151:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:162:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:160:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:163:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:164:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:174:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:184:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:185:13
+   |
+LL |             unsafe {}
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:186:13
+   |
+LL |             unsafe {}
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:192:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:203:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+LL |             unsf();
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:204:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:205:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |             unsafe { unsf() }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:216:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:214:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:217:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:218:17
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+...
+LL |                 unsafe { unsf() }
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:238:9
+   |
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:251:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+LL |             unsafe {
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:264:13
+   |
+LL |         unsafe {
+   |         ------ because it's nested under this `unsafe` block
+LL |             unsafe {
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:282:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:291:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:292:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:293:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:298:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:308:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             unsf();
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:309:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:310:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:320:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:318:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:321:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:322:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:332:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:342:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:343:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:344:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:350:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:361:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             unsf();
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:362:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:363:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:374:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:372:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:375:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:376:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:386:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:396:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:397:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:398:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:404:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:415:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             unsf();
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:416:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:417:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { unsf() };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:428:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:426:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:429:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:430:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:450:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:463:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:476:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:495:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:504:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:505:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:506:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:511:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:521:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             let _ = || unsf();
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:522:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:523:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:533:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:531:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:534:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:535:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:545:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:555:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:556:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:557:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:563:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:574:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             let _ = || unsf();
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:575:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:576:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:587:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:585:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:588:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:589:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:599:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:609:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:610:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:611:24
+   |
+LL |             let _ = || unsafe {};
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:617:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:628:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             let _ = || unsf();
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:629:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:630:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |             let _ = || unsafe { let _ = || unsf(); };
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:641:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:639:20
+   |
+LL |             #[deny(unused_unsafe)]
+   |                    ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:642:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:643:28
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { let _ = || unsf(); };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:663:20
+   |
+LL |         let _ = || unsafe {
+   |                    ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:676:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:689:24
+   |
+LL |         let _ = || unsafe {
+   |                    ------ because it's nested under this `unsafe` block
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:707:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:717:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:718:28
+   |
+LL |                 let _ = || unsafe {};
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:719:28
+   |
+LL |                 let _ = || unsafe {};
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:725:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:736:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+LL |                 unsf();
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:737:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:738:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:749:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:747:24
+   |
+LL |                 #[deny(unused_unsafe)]
+   |                        ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:750:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:751:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:761:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:771:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:772:28
+   |
+LL |                 let _ = || unsafe {};
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:773:28
+   |
+LL |                 let _ = || unsafe {};
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:779:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:790:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+LL |                 unsf();
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:791:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:792:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:803:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:801:24
+   |
+LL |                 #[deny(unused_unsafe)]
+   |                        ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:804:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:805:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:825:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:838:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+LL |                 let _ = || unsafe {
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:851:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+LL |                 let _ = || unsafe {
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:865:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:875:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:876:28
+   |
+LL |                 let _ = || unsafe {};
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:877:28
+   |
+LL |                 let _ = || unsafe {};
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:883:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:894:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+LL |                 unsf();
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:895:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:896:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:907:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:905:24
+   |
+LL |                 #[deny(unused_unsafe)]
+   |                        ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:908:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:909:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:919:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:929:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:930:28
+   |
+LL |                 let _ = || unsafe {};
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:931:28
+   |
+LL |                 let _ = || unsafe {};
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:937:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:948:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+LL |                 unsf();
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:949:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:950:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = || unsafe { unsf() };
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:961:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:959:24
+   |
+LL |                 #[deny(unused_unsafe)]
+   |                        ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:962:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:963:32
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+...
+LL |                     let _ = || unsafe { unsf() };
+   |                                ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:983:24
+   |
+LL |             let _ = || unsafe {
+   |                        ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:996:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+LL |                 let _ = || unsafe {
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1009:28
+   |
+LL |             let _ = || unsafe {
+   |                        ------ because it's nested under this `unsafe` block
+LL |                 let _ = || unsafe {
+   |                            ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1055:29
+   |
+LL |             let _ = async { unsafe {
+   |                             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1062:33
+   |
+LL |             let _ = async { unsafe {
+   |                             ------ because it's nested under this `unsafe` block
+LL |                 let _ = async { unsf() };
+LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
+   |                                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1063:33
+   |
+LL |             let _ = async { unsafe {
+   |                             ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
+   |                                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1064:33
+   |
+LL |             let _ = async { unsafe {
+   |                             ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
+   |                                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1069:29
+   |
+LL |             let _ = async { unsafe {
+   |                             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1076:33
+   |
+LL |             let _ = async { unsafe {
+   |                             ------ because it's nested under this `unsafe` block
+LL |                 let _ = async { unsf() };
+LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
+   |                                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1077:33
+   |
+LL |             let _ = async { unsafe {
+   |                             ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
+   |                                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1078:33
+   |
+LL |             let _ = async { unsafe {
+   |                             ------ because it's nested under this `unsafe` block
+...
+LL |                 let _ = async { unsafe { let _ = async { unsf() }; }};
+   |                                 ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1088:22
+   |
+LL |         let _x: [(); unsafe { 0 }] = [];
+   |                      ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:1092:22
+   |
+LL |         let _x: [(); unsafe { unsafe { size() } }] = [];
+   |                      ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 174 previous errors
+
diff --git a/tests/ui/specialization/min_specialization/issue-79224.rs b/tests/ui/specialization/min_specialization/issue-79224.rs
index 104bddd076e..a118cb28b38 100644
--- a/tests/ui/specialization/min_specialization/issue-79224.rs
+++ b/tests/ui/specialization/min_specialization/issue-79224.rs
@@ -19,6 +19,7 @@ impl<B: ?Sized> Display for Cow<'_, B> {
     //~^ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         //~^ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
+        //~| ERROR: the trait bound `B: Clone` is not satisfied [E0277]
         write!(f, "foo")
     }
 }
diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr
index 9a4d557a152..7541579498e 100644
--- a/tests/ui/specialization/min_specialization/issue-79224.stderr
+++ b/tests/ui/specialization/min_specialization/issue-79224.stderr
@@ -22,6 +22,18 @@ help: consider further restricting this bound
 LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> {
    |                +++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error[E0277]: the trait bound `B: Clone` is not satisfied
+  --> $DIR/issue-79224.rs:20:5
+   |
+LL |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B`
+   |
+   = note: required for `B` to implement `ToOwned`
+help: consider further restricting this bound
+   |
+LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> {
+   |                +++++++++++++++++++
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/stability-attribute/stability-attribute-issue-43027.rs b/tests/ui/stability-attribute/stability-attribute-issue-43027.rs
index 3f4fdfd0180..810fbef7b38 100644
--- a/tests/ui/stability-attribute/stability-attribute-issue-43027.rs
+++ b/tests/ui/stability-attribute/stability-attribute-issue-43027.rs
@@ -1,12 +1,12 @@
 // check-pass
 #![feature(staged_api)]
-#![stable(feature = "test", since = "0")]
+#![stable(feature = "test", since = "3.3.3")]
 
-#[stable(feature = "test", since = "0")]
+#[stable(feature = "test", since = "3.3.3")]
 pub struct A<T>(pub T);
 
-#[stable(feature = "test", since = "0")]
-pub struct B<T>(#[stable(feature = "test", since = "0")] pub T);
+#[stable(feature = "test", since = "3.3.3")]
+pub struct B<T>(#[stable(feature = "test", since = "3.3.3")] pub T);
 
 fn main() {
     // Make sure the field is used to fill the stability cache
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-4.rs b/tests/ui/stability-attribute/stability-attribute-sanity-4.rs
index 64f99635219..4fe8e45fd04 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity-4.rs
+++ b/tests/ui/stability-attribute/stability-attribute-sanity-4.rs
@@ -17,11 +17,11 @@ mod bogus_attribute_types_2 {
     #[stable = "a"] //~ ERROR malformed `stable` attribute
     fn f4() { }
 
-    #[stable(feature = "a", since = "b")]
+    #[stable(feature = "a", since = "3.3.3")]
     #[deprecated] //~ ERROR missing 'since'
     fn f5() { }
 
-    #[stable(feature = "a", since = "b")]
+    #[stable(feature = "a", since = "3.3.3")]
     #[deprecated = "a"] //~ ERROR missing 'since'
     fn f6() { }
 }
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs
index cc30e6ab9a9..8258b6f5ae0 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity.rs
+++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs
@@ -5,19 +5,19 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 mod bogus_attribute_types_1 {
-    #[stable(feature = "a", since = "b", reason)] //~ ERROR unknown meta item 'reason' [E0541]
+    #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR unknown meta item 'reason' [E0541]
     fn f1() { }
 
     #[stable(feature = "a", since)] //~ ERROR incorrect meta item [E0539]
     fn f2() { }
 
-    #[stable(feature, since = "a")] //~ ERROR incorrect meta item [E0539]
+    #[stable(feature, since = "3.3.3")] //~ ERROR incorrect meta item [E0539]
     fn f3() { }
 
     #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item [E0539]
     fn f5() { }
 
-    #[stable(feature(b), since = "a")] //~ ERROR incorrect meta item [E0539]
+    #[stable(feature(b), since = "3.3.3")] //~ ERROR incorrect meta item [E0539]
     fn f6() { }
 }
 
@@ -28,7 +28,7 @@ mod missing_feature_names {
     #[unstable(feature = "b")] //~ ERROR missing 'issue' [E0547]
     fn f2() { }
 
-    #[stable(since = "a")] //~ ERROR missing 'feature' [E0546]
+    #[stable(since = "3.3.3")] //~ ERROR missing 'feature' [E0546]
     fn f3() { }
 }
 
@@ -36,28 +36,28 @@ mod missing_version {
     #[stable(feature = "a")] //~ ERROR missing 'since' [E0542]
     fn f1() { }
 
-    #[stable(feature = "a", since = "b")]
+    #[stable(feature = "a", since = "4.4.4")]
     #[deprecated(note = "a")] //~ ERROR missing 'since' [E0542]
     fn f2() { }
 
-    #[stable(feature = "a", since = "b")]
+    #[stable(feature = "a", since = "4.4.4")]
     #[deprecated(since = "a")] //~ ERROR missing 'note' [E0543]
     fn f3() { }
 }
 
 #[unstable(feature = "b", issue = "none")]
-#[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544]
+#[stable(feature = "a", since = "4.4.4")] //~ ERROR multiple stability levels [E0544]
 fn multiple1() { }
 
 #[unstable(feature = "b", issue = "none")]
 #[unstable(feature = "b", issue = "none")] //~ ERROR multiple stability levels [E0544]
 fn multiple2() { }
 
-#[stable(feature = "a", since = "b")]
-#[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544]
+#[stable(feature = "a", since = "4.4.4")]
+#[stable(feature = "a", since = "4.4.4")] //~ ERROR multiple stability levels [E0544]
 fn multiple3() { }
 
-#[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found
+#[stable(feature = "e", since = "b")] //~ ERROR 'since' must be a Rust version number, such as "1.31.0"
 #[deprecated(since = "b", note = "text")]
 #[deprecated(since = "b", note = "text")] //~ ERROR multiple `deprecated` attributes
 #[rustc_const_unstable(feature = "c", issue = "none")]
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr
index 89a8425f5e7..955230742bd 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -11,10 +11,10 @@ LL | #[deprecated(since = "b", note = "text")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0541]: unknown meta item 'reason'
-  --> $DIR/stability-attribute-sanity.rs:8:42
+  --> $DIR/stability-attribute-sanity.rs:8:46
    |
-LL |     #[stable(feature = "a", since = "b", reason)]
-   |                                          ^^^^^^ expected one of `feature`, `since`
+LL |     #[stable(feature = "a", since = "4.4.4", reason)]
+   |                                              ^^^^^^ expected one of `feature`, `since`
 
 error[E0539]: incorrect meta item
   --> $DIR/stability-attribute-sanity.rs:11:29
@@ -25,7 +25,7 @@ LL |     #[stable(feature = "a", since)]
 error[E0539]: incorrect meta item
   --> $DIR/stability-attribute-sanity.rs:14:14
    |
-LL |     #[stable(feature, since = "a")]
+LL |     #[stable(feature, since = "3.3.3")]
    |              ^^^^^^^
 
 error[E0539]: incorrect meta item
@@ -37,7 +37,7 @@ LL |     #[stable(feature = "a", since(b))]
 error[E0539]: incorrect meta item
   --> $DIR/stability-attribute-sanity.rs:20:14
    |
-LL |     #[stable(feature(b), since = "a")]
+LL |     #[stable(feature(b), since = "3.3.3")]
    |              ^^^^^^^^^^
 
 error[E0546]: missing 'feature'
@@ -55,8 +55,8 @@ LL |     #[unstable(feature = "b")]
 error[E0546]: missing 'feature'
   --> $DIR/stability-attribute-sanity.rs:31:5
    |
-LL |     #[stable(since = "a")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[stable(since = "3.3.3")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0542]: missing 'since'
   --> $DIR/stability-attribute-sanity.rs:36:5
@@ -79,8 +79,8 @@ LL |     #[deprecated(since = "a")]
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:49:1
    |
-LL | #[stable(feature = "a", since = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[stable(feature = "a", since = "4.4.4")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:53:1
@@ -91,7 +91,13 @@ LL | #[unstable(feature = "b", issue = "none")]
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:57:1
    |
-LL | #[stable(feature = "a", since = "b")]
+LL | #[stable(feature = "a", since = "4.4.4")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: 'since' must be a Rust version number, such as "1.31.0"
+  --> $DIR/stability-attribute-sanity.rs:60:1
+   |
+LL | #[stable(feature = "e", since = "b")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0544]: multiple stability levels
@@ -100,15 +106,6 @@ error[E0544]: multiple stability levels
 LL | #[rustc_const_unstable(feature = "d", issue = "none")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: invalid stability version found
-  --> $DIR/stability-attribute-sanity.rs:60:1
-   |
-LL | #[stable(feature = "a", since = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid stability version
-...
-LL | pub const fn multiple4() { }
-   | ---------------------------- the stability attribute annotates this item
-
 error: invalid deprecation version found
   --> $DIR/stability-attribute-sanity.rs:67:1
    |
@@ -124,7 +121,7 @@ error[E0549]: deprecated attribute must be paired with either stable or unstable
 LL | #[deprecated(since = "a", note = "text")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since b
+error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since 4.4.4
   --> $DIR/stability-attribute-sanity.rs:67:1
    |
 LL | #[stable(feature = "a", since = "1.0.0")]
diff --git a/tests/ui/stability-attribute/stability-attribute-trait-impl.rs b/tests/ui/stability-attribute/stability-attribute-trait-impl.rs
index 1d138e26408..880000ee7a4 100644
--- a/tests/ui/stability-attribute/stability-attribute-trait-impl.rs
+++ b/tests/ui/stability-attribute/stability-attribute-trait-impl.rs
@@ -1,13 +1,13 @@
 #![feature(staged_api, never_type, rust_cold_cc)]
 //~^ ERROR module has missing stability attribute
 
-#[stable(feature = "a", since = "1")]
+#[stable(feature = "a", since = "3.3.3")]
 struct StableType;
 
 #[unstable(feature = "b", issue = "none")]
 struct UnstableType;
 
-#[stable(feature = "c", since = "1")]
+#[stable(feature = "c", since = "3.3.3")]
 trait StableTrait {}
 
 #[unstable(feature = "d", issue = "none")]
diff --git a/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr b/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr
index 96322c2c945..018786dd26d 100644
--- a/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr
@@ -21,7 +21,7 @@ error: module has missing stability attribute
 LL | / #![feature(staged_api, never_type, rust_cold_cc)]
 LL | |
 LL | |
-LL | | #[stable(feature = "a", since = "1")]
+LL | | #[stable(feature = "a", since = "3.3.3")]
 ...  |
 LL | |
 LL | | fn main() {}
diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs
index 782444417a8..971a4654b4c 100644
--- a/tests/ui/target-feature/gate.rs
+++ b/tests/ui/target-feature/gate.rs
@@ -18,6 +18,7 @@
 // gate-test-bpf_target_feature
 // gate-test-aarch64_ver_target_feature
 // gate-test-csky_target_feature
+// gate-test-loongarch_target_feature
 
 #[target_feature(enable = "avx512bw")]
 //~^ ERROR: currently unstable
diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr
index f56efb3bb83..0ec7427c3c4 100644
--- a/tests/ui/target-feature/gate.stderr
+++ b/tests/ui/target-feature/gate.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the target feature `avx512bw` is currently unstable
-  --> $DIR/gate.rs:22:18
+  --> $DIR/gate.rs:23:18
    |
 LL | #[target_feature(enable = "avx512bw")]
    |                  ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
new file mode 100644
index 00000000000..e0edd522431
--- /dev/null
+++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
@@ -0,0 +1,43 @@
+// Regression test for #116464
+// Checks that we do not suggest Trait<..., Assoc=arg> when the trait
+// is referred to from one of its impls but do so at all other places
+
+pub trait Trait<T> {
+    type Assoc;
+}
+
+impl<T, S> Trait<T> for i32 {
+    type Assoc = String;
+}
+
+// Should not not trigger suggestion here...
+impl<T, S> Trait<T, S> for () {}
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+
+//... but should do so in all of the below cases except the last one
+fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+//~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+    3
+}
+
+struct Struct<T: Trait<u32, String>> {
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+    a: T
+}
+
+trait AnotherTrait<T: Trait<T, i32>> {}
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+
+impl<T: Trait<u32, String>> Struct<T> {}
+//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+
+// Test for self type. Should not trigger suggestion as it doesn't have an
+// associated type
+trait YetAnotherTrait {}
+impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
+//~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied
+
+
+fn main() {
+}
diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
new file mode 100644
index 00000000000..711ccf1b668
--- /dev/null
+++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
@@ -0,0 +1,109 @@
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:14:12
+   |
+LL | impl<T, S> Trait<T, S> for () {}
+   |            ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:12
+   |
+LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
+   |            ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | fn func<T: Trait<u32, Assoc = String>>(t: T) -> impl Trait<(), i32> {
+   |                       +++++++
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:46
+   |
+LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
+   |                                              ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> {
+   |                                                        +++++++
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:18
+   |
+LL | struct Struct<T: Trait<u32, String>> {
+   |                  ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | struct Struct<T: Trait<u32, Assoc = String>> {
+   |                             +++++++
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:29:23
+   |
+LL | trait AnotherTrait<T: Trait<T, i32>> {}
+   |                       ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | trait AnotherTrait<T: Trait<T, Assoc = i32>> {}
+   |                                +++++++
+
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:32:9
+   |
+LL | impl<T: Trait<u32, String>> Struct<T> {}
+   |         ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+help: replace the generic bound with the associated type
+   |
+LL | impl<T: Trait<u32, Assoc = String>> Struct<T> {}
+   |                    +++++++
+
+error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:38:58
+   |
+LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
+   |                                                          ^^^^^^    - help: remove this generic argument
+   |                                                          |
+   |                                                          expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:8
+   |
+LL | struct Struct<T: Trait<u32, String>> {
+   |        ^^^^^^ -
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.rs b/tests/ui/traits/bound/on-structs-and-enums-static.rs
index df3f8b8a599..066416cb362 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-static.rs
+++ b/tests/ui/traits/bound/on-structs-and-enums-static.rs
@@ -8,7 +8,7 @@ struct Foo<T:Trait> {
 
 static X: Foo<usize> = Foo {
 //~^ ERROR E0277
-    x: 1,
+    x: 1, //~ ERROR: E0277
 };
 
 fn main() {
diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.stderr b/tests/ui/traits/bound/on-structs-and-enums-static.stderr
index fa14aff684d..28bbe00c582 100644
--- a/tests/ui/traits/bound/on-structs-and-enums-static.stderr
+++ b/tests/ui/traits/bound/on-structs-and-enums-static.stderr
@@ -15,6 +15,23 @@ note: required by a bound in `Foo`
 LL | struct Foo<T:Trait> {
    |              ^^^^^ required by this bound in `Foo`
 
-error: aborting due to previous error
+error[E0277]: the trait bound `usize: Trait` is not satisfied
+  --> $DIR/on-structs-and-enums-static.rs:11:8
+   |
+LL |     x: 1,
+   |        ^ the trait `Trait` is not implemented for `usize`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/on-structs-and-enums-static.rs:1:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
+note: required by a bound in `Foo`
+  --> $DIR/on-structs-and-enums-static.rs:5:14
+   |
+LL | struct Foo<T:Trait> {
+   |              ^^^^^ required by this bound in `Foo`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/specialization-transmute.rs b/tests/ui/traits/new-solver/specialization-transmute.rs
index f6b19e7adf5..7523b828321 100644
--- a/tests/ui/traits/new-solver/specialization-transmute.rs
+++ b/tests/ui/traits/new-solver/specialization-transmute.rs
@@ -10,7 +10,7 @@ trait Default {
 }
 
 impl<T> Default for T {
-    default type Id = T;
+    default type Id = T; //~ ERROR: type annotations needed
     // This will be fixed by #111994
     fn intu(&self) -> &Self::Id { //~ ERROR type annotations needed
         self
diff --git a/tests/ui/traits/new-solver/specialization-transmute.stderr b/tests/ui/traits/new-solver/specialization-transmute.stderr
index 09b1405fefb..18965a465b3 100644
--- a/tests/ui/traits/new-solver/specialization-transmute.stderr
+++ b/tests/ui/traits/new-solver/specialization-transmute.stderr
@@ -16,6 +16,13 @@ LL |     fn intu(&self) -> &Self::Id {
    |
    = note: cannot satisfy `<T as Default>::Id == _`
 
-error: aborting due to previous error; 1 warning emitted
+error[E0282]: type annotations needed
+  --> $DIR/specialization-transmute.rs:13:23
+   |
+LL |     default type Id = T;
+   |                       ^ cannot infer type for associated type `<T as Default>::Id`
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0282, E0284.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.rs b/tests/ui/type-alias-impl-trait/generic_underconstrained.rs
index d87a25aad58..1acacc778de 100644
--- a/tests/ui/type-alias-impl-trait/generic_underconstrained.rs
+++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.rs
@@ -8,5 +8,6 @@ type Underconstrained<T: Trait> = impl Send;
 // no `Trait` bound
 fn underconstrain<T>(_: T) -> Underconstrained<T> {
     //~^ ERROR the trait bound `T: Trait`
+    //~| ERROR the trait bound `T: Trait`
     unimplemented!()
 }
diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
index bc9280127ac..88529b370f1 100644
--- a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
@@ -14,6 +14,27 @@ help: consider restricting type parameter `T`
 LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> {
    |                    +++++++
 
-error: aborting due to previous error
+error[E0277]: the trait bound `T: Trait` is not satisfied
+  --> $DIR/generic_underconstrained.rs:9:51
+   |
+LL |   fn underconstrain<T>(_: T) -> Underconstrained<T> {
+   |  ___________________________________________________^
+LL | |
+LL | |
+LL | |     unimplemented!()
+LL | | }
+   | |_^ the trait `Trait` is not implemented for `T`
+   |
+note: required by a bound on the type alias `Underconstrained`
+  --> $DIR/generic_underconstrained.rs:6:26
+   |
+LL | type Underconstrained<T: Trait> = impl Send;
+   |                          ^^^^^ required by this bound
+help: consider restricting type parameter `T`
+   |
+LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> {
+   |                    +++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.rs b/tests/ui/type-alias-impl-trait/generic_underconstrained2.rs
index 8adc0bf32a6..1e1bece9a1c 100644
--- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.rs
+++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.rs
@@ -7,6 +7,7 @@ type Underconstrained<T: std::fmt::Debug> = impl Send;
 // not a defining use, because it doesn't define *all* possible generics
 fn underconstrained<U>(_: U) -> Underconstrained<U> {
     //~^ ERROR `U` doesn't implement `Debug`
+    //~| ERROR `U` doesn't implement `Debug`
     5u32
 }
 
@@ -15,5 +16,6 @@ type Underconstrained2<T: std::fmt::Debug> = impl Send;
 // not a defining use, because it doesn't define *all* possible generics
 fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
     //~^ ERROR `V` doesn't implement `Debug`
+    //~| ERROR `V` doesn't implement `Debug`
     5u32
 }
diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index fdc9ec090db..b3b9cbca968 100644
--- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -15,13 +15,13 @@ LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> {
    |                      +++++++++++++++++
 
 error[E0277]: `V` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:16:43
+  --> $DIR/generic_underconstrained2.rs:17:43
    |
 LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
    |                                           ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
 note: required by a bound on the type alias `Underconstrained2`
-  --> $DIR/generic_underconstrained2.rs:13:27
+  --> $DIR/generic_underconstrained2.rs:14:27
    |
 LL | type Underconstrained2<T: std::fmt::Debug> = impl Send;
    |                           ^^^^^^^^^^^^^^^ required by this bound
@@ -30,6 +30,48 @@ help: consider restricting type parameter `V`
 LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained2<V> {
    |                          +++++++++++++++++
 
-error: aborting due to 2 previous errors
+error[E0277]: `U` doesn't implement `Debug`
+  --> $DIR/generic_underconstrained2.rs:8:53
+   |
+LL |   fn underconstrained<U>(_: U) -> Underconstrained<U> {
+   |  _____________________________________________________^
+LL | |
+LL | |
+LL | |     5u32
+LL | | }
+   | |_^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+note: required by a bound on the type alias `Underconstrained`
+  --> $DIR/generic_underconstrained2.rs:5:26
+   |
+LL | type Underconstrained<T: std::fmt::Debug> = impl Send;
+   |                          ^^^^^^^^^^^^^^^ required by this bound
+help: consider restricting type parameter `U`
+   |
+LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> {
+   |                      +++++++++++++++++
+
+error[E0277]: `V` doesn't implement `Debug`
+  --> $DIR/generic_underconstrained2.rs:17:64
+   |
+LL |   fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
+   |  ________________________________________________________________^
+LL | |
+LL | |
+LL | |     5u32
+LL | | }
+   | |_^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+note: required by a bound on the type alias `Underconstrained2`
+  --> $DIR/generic_underconstrained2.rs:14:27
+   |
+LL | type Underconstrained2<T: std::fmt::Debug> = impl Send;
+   |                           ^^^^^^^^^^^^^^^ required by this bound
+help: consider restricting type parameter `V`
+   |
+LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained2<V> {
+   |                          +++++++++++++++++
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr b/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr
index aaf75cc3db9..e35913be899 100644
--- a/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr
+++ b/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr
@@ -15,6 +15,8 @@ LL | impl Bop for Bar<()> {}
 ...
 LL | impl Bop for Barr {}
    | ^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>`
+   |
+   = note: upstream crates may add a new impl of trait `std::marker::FnPtr` for type `Barr` in future versions
 
 error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>`
   --> $DIR/impl_trait_for_same_tait.rs:30:1
diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs
new file mode 100644
index 00000000000..3d1759097d6
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs
@@ -0,0 +1,17 @@
+// test for #113326
+#![feature(type_alias_impl_trait)]
+
+pub type Diff = impl Fn(usize) -> usize;
+
+pub fn lift() -> Diff {
+    |_: usize |loop {}
+}
+
+pub fn add(
+    n: Diff,
+    m: Diff,
+) -> Diff {
+    move |x: usize| m(n(x)) //~ ERROR: concrete type differs
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr
new file mode 100644
index 00000000000..b2898a21190
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr
@@ -0,0 +1,14 @@
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/recursive-fn-tait.rs:14:5
+   |
+LL |     move |x: usize| m(n(x))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `{closure@$DIR/recursive-fn-tait.rs:7:5: 7:16}`, got `{closure@$DIR/recursive-fn-tait.rs:14:5: 14:20}`
+   |
+note: previous use here
+  --> $DIR/recursive-fn-tait.rs:7:5
+   |
+LL |     |_: usize |loop {}
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr b/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr
index f53abe53bf1..c4f16429563 100644
--- a/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr
+++ b/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr
@@ -8,6 +8,10 @@ LL |     let x : char = last(y);
    |
    = note: expected type `char`
               found enum `Option<_>`
+help: consider using `Option::expect` to unwrap the `Option<_>` value, panicking if the value is an `Option::None`
+   |
+LL |     let x : char = last(y).expect("REASON");
+   |                           +++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/ufcs/ufcs-explicit-self-bad.rs b/tests/ui/ufcs/ufcs-explicit-self-bad.rs
index cb1fac0bae6..9b0f99a189a 100644
--- a/tests/ui/ufcs/ufcs-explicit-self-bad.rs
+++ b/tests/ui/ufcs/ufcs-explicit-self-bad.rs
@@ -36,6 +36,7 @@ impl<'a, T> SomeTrait for &'a Bar<T> {
     fn dummy1(self: &&'a Bar<T>) { }
     fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched `self` parameter type
     //~^ ERROR mismatched `self` parameter type
+    //~| ERROR has an incompatible type for trait
     fn dummy3(self: &&Bar<T>) {}
     //~^ ERROR mismatched `self` parameter type
     //~| expected reference `&'a Bar<T>`
diff --git a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
index f325d1d8182..0efaa41d48a 100644
--- a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
+++ b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
@@ -64,7 +64,7 @@ LL |     fn dummy2(self: &Bar<T>) {}
    |                     ^^^^^^^
 
 error[E0308]: mismatched `self` parameter type
-  --> $DIR/ufcs-explicit-self-bad.rs:39:21
+  --> $DIR/ufcs-explicit-self-bad.rs:40:21
    |
 LL |     fn dummy3(self: &&Bar<T>) {}
    |                     ^^^^^^^^ lifetime mismatch
@@ -72,7 +72,7 @@ LL |     fn dummy3(self: &&Bar<T>) {}
    = note: expected reference `&'a Bar<T>`
               found reference `&Bar<T>`
 note: the anonymous lifetime defined here...
-  --> $DIR/ufcs-explicit-self-bad.rs:39:22
+  --> $DIR/ufcs-explicit-self-bad.rs:40:22
    |
 LL |     fn dummy3(self: &&Bar<T>) {}
    |                      ^^^^^^^
@@ -83,7 +83,7 @@ LL | impl<'a, T> SomeTrait for &'a Bar<T> {
    |      ^^
 
 error[E0308]: mismatched `self` parameter type
-  --> $DIR/ufcs-explicit-self-bad.rs:39:21
+  --> $DIR/ufcs-explicit-self-bad.rs:40:21
    |
 LL |     fn dummy3(self: &&Bar<T>) {}
    |                     ^^^^^^^^ lifetime mismatch
@@ -96,12 +96,29 @@ note: the lifetime `'a` as defined here...
 LL | impl<'a, T> SomeTrait for &'a Bar<T> {
    |      ^^
 note: ...does not necessarily outlive the anonymous lifetime defined here
-  --> $DIR/ufcs-explicit-self-bad.rs:39:22
+  --> $DIR/ufcs-explicit-self-bad.rs:40:22
    |
 LL |     fn dummy3(self: &&Bar<T>) {}
    |                      ^^^^^^^
 
-error: aborting due to 7 previous errors
+error[E0053]: method `dummy2` has an incompatible type for trait
+  --> $DIR/ufcs-explicit-self-bad.rs:37:21
+   |
+LL |     fn dummy2(self: &Bar<T>) {}
+   |               ------^^^^^^^
+   |               |     |
+   |               |     expected `&'a Bar<T>`, found `Bar<T>`
+   |               help: change the self-receiver type to match the trait: `&self`
+   |
+note: type in trait
+  --> $DIR/ufcs-explicit-self-bad.rs:31:15
+   |
+LL |     fn dummy2(&self);
+   |               ^^^^^
+   = note: expected signature `fn(&&'a Bar<T>)`
+              found signature `fn(&Bar<T>)`
+
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0307, E0308.
-For more information about an error, try `rustc --explain E0307`.
+Some errors have detailed explanations: E0053, E0307, E0308.
+For more information about an error, try `rustc --explain E0053`.
diff --git a/tests/ui/union/issue-81199.rs b/tests/ui/union/issue-81199.rs
index 628e7c6ed5d..b8b0d9d33e7 100644
--- a/tests/ui/union/issue-81199.rs
+++ b/tests/ui/union/issue-81199.rs
@@ -4,6 +4,7 @@ union PtrRepr<T: ?Sized> {
     mut_ptr: *mut T,
     components: PtrComponents<T>,
     //~^ ERROR the trait bound
+    //~| ERROR field must implement `Copy`
 }
 
 #[repr(C)]
diff --git a/tests/ui/union/issue-81199.stderr b/tests/ui/union/issue-81199.stderr
index 5bb98675361..0dd894beb2a 100644
--- a/tests/ui/union/issue-81199.stderr
+++ b/tests/ui/union/issue-81199.stderr
@@ -5,7 +5,7 @@ LL |     components: PtrComponents<T>,
    |                 ^^^^^^^^^^^^^^^^ the trait `Pointee` is not implemented for `T`
    |
 note: required by a bound in `PtrComponents`
-  --> $DIR/issue-81199.rs:10:25
+  --> $DIR/issue-81199.rs:11:25
    |
 LL | struct PtrComponents<T: Pointee + ?Sized> {
    |                         ^^^^^^^ required by this bound in `PtrComponents`
@@ -14,6 +14,19 @@ help: consider further restricting this bound
 LL | union PtrRepr<T: ?Sized + Pointee> {
    |                         +++++++++
 
-error: aborting due to previous error
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/issue-81199.rs:5:5
+   |
+LL |     components: PtrComponents<T>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     components: std::mem::ManuallyDrop<PtrComponents<T>>,
+   |                 +++++++++++++++++++++++                +
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0740.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/union/union-unsized.mirunsafeck.stderr b/tests/ui/union/union-unsized.mirunsafeck.stderr
index 59ab835fba2..f8da20413b2 100644
--- a/tests/ui/union/union-unsized.mirunsafeck.stderr
+++ b/tests/ui/union/union-unsized.mirunsafeck.stderr
@@ -17,7 +17,7 @@ LL |     a: Box<str>,
    |        ++++   +
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:13:8
+  --> $DIR/union-unsized.rs:14:8
    |
 LL |     b: str,
    |        ^^^ doesn't have a size known at compile-time
@@ -34,6 +34,31 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL |     b: Box<str>,
    |        ++++   +
 
-error: aborting due to 2 previous errors
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/union-unsized.rs:5:5
+   |
+LL |     a: str,
+   |     ^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     a: std::mem::ManuallyDrop<str>,
+   |        +++++++++++++++++++++++   +
+
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/union-unsized.rs:14:5
+   |
+LL |     b: str,
+   |     ^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     b: std::mem::ManuallyDrop<str>,
+   |        +++++++++++++++++++++++   +
+
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0740.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/union/union-unsized.rs b/tests/ui/union/union-unsized.rs
index 8e897d7d3c6..b95b2e414f3 100644
--- a/tests/ui/union/union-unsized.rs
+++ b/tests/ui/union/union-unsized.rs
@@ -4,6 +4,7 @@
 union U {
     a: str,
     //~^ ERROR the size for values of type
+    //~| ERROR field must implement `Copy`
 
     b: u8,
 }
@@ -12,6 +13,7 @@ union W {
     a: u8,
     b: str,
     //~^ ERROR the size for values of type
+    //~| ERROR field must implement `Copy`
 }
 
 fn main() {}
diff --git a/tests/ui/union/union-unsized.thirunsafeck.stderr b/tests/ui/union/union-unsized.thirunsafeck.stderr
index 59ab835fba2..f8da20413b2 100644
--- a/tests/ui/union/union-unsized.thirunsafeck.stderr
+++ b/tests/ui/union/union-unsized.thirunsafeck.stderr
@@ -17,7 +17,7 @@ LL |     a: Box<str>,
    |        ++++   +
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:13:8
+  --> $DIR/union-unsized.rs:14:8
    |
 LL |     b: str,
    |        ^^^ doesn't have a size known at compile-time
@@ -34,6 +34,31 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL |     b: Box<str>,
    |        ++++   +
 
-error: aborting due to 2 previous errors
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/union-unsized.rs:5:5
+   |
+LL |     a: str,
+   |     ^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     a: std::mem::ManuallyDrop<str>,
+   |        +++++++++++++++++++++++   +
+
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/union-unsized.rs:14:5
+   |
+LL |     b: str,
+   |     ^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     b: std::mem::ManuallyDrop<str>,
+   |        +++++++++++++++++++++++   +
+
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0740.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/unresolved/auxiliary/library.rs b/tests/ui/unresolved/auxiliary/library.rs
new file mode 100644
index 00000000000..1169ed96225
--- /dev/null
+++ b/tests/ui/unresolved/auxiliary/library.rs
@@ -0,0 +1 @@
+pub struct SomeUsefulType;
diff --git a/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs
new file mode 100644
index 00000000000..af8207aaadd
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs
@@ -0,0 +1,31 @@
+// Test that we don't prepend `::` to paths referencing crates from the extern prelude
+// when it can be avoided[^1] since it's more idiomatic to do so.
+//
+// [^1]: Counterexample: `unresolved-import-suggest-disambiguated-crate-name.rs`
+#![feature(decl_macro)] // allows us to create items with hygienic names
+
+// aux-crate:library=library.rs
+// edition: 2021
+
+mod hygiene {
+    make!();
+    macro make() {
+        // This won't conflict with the suggested *non-global* path as the syntax context differs.
+        mod library {}
+    }
+
+    mod module {}
+    use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
+}
+
+mod glob {
+    use inner::*;
+    mod inner {
+        mod library {}
+    }
+
+    mod module {}
+    use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
+}
+
+fn main() {}
diff --git a/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr
new file mode 100644
index 00000000000..b0352ab6754
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr
@@ -0,0 +1,25 @@
+error[E0432]: unresolved import `module::SomeUsefulType`
+  --> $DIR/unresolved-import-avoid-suggesting-global-path.rs:18:9
+   |
+LL |     use module::SomeUsefulType;
+   |         ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `hygiene::module`
+   |
+help: consider importing this struct instead
+   |
+LL |     use library::SomeUsefulType;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0432]: unresolved import `module::SomeUsefulType`
+  --> $DIR/unresolved-import-avoid-suggesting-global-path.rs:28:9
+   |
+LL |     use module::SomeUsefulType;
+   |         ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `glob::module`
+   |
+help: consider importing this struct instead
+   |
+LL |     use library::SomeUsefulType;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed
new file mode 100644
index 00000000000..2b20d3f106b
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed
@@ -0,0 +1,19 @@
+// Regression test for issue #116970.
+//
+// When we suggest importing an item from a crate found in the extern prelude and there
+// happens to exist a module or type in the current scope with the same name as the crate,
+// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`).
+//
+// For context, when it can be avoided we don't prepend `::` to paths referencing crates
+// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`.
+
+// run-rustfix
+
+// compile-flags: --crate-type=lib
+// aux-crate:library=library.rs
+// edition: 2021
+
+mod library {} // this module shares the same name as the external crate!
+
+mod module {}
+pub use ::library::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs
new file mode 100644
index 00000000000..b810a7f5296
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs
@@ -0,0 +1,19 @@
+// Regression test for issue #116970.
+//
+// When we suggest importing an item from a crate found in the extern prelude and there
+// happens to exist a module or type in the current scope with the same name as the crate,
+// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`).
+//
+// For context, when it can be avoided we don't prepend `::` to paths referencing crates
+// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`.
+
+// run-rustfix
+
+// compile-flags: --crate-type=lib
+// aux-crate:library=library.rs
+// edition: 2021
+
+mod library {} // this module shares the same name as the external crate!
+
+mod module {}
+pub use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr
new file mode 100644
index 00000000000..f139c0f3cf1
--- /dev/null
+++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr
@@ -0,0 +1,14 @@
+error[E0432]: unresolved import `module::SomeUsefulType`
+  --> $DIR/unresolved-import-suggest-disambiguated-crate-name.rs:19:9
+   |
+LL | pub use module::SomeUsefulType;
+   |         ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `module`
+   |
+help: consider importing this struct instead
+   |
+LL | pub use ::library::SomeUsefulType;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr b/tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr
index 9e9cbcf33ae..2267da31512 100644
--- a/tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr
+++ b/tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr
@@ -16,9 +16,9 @@ LL | #[deny(unused_unsafe)]
 error: unnecessary `unsafe` block
   --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
    |
-LL |     unsafe {
-   |     ------ because it's nested under this `unsafe` block
-...
+LL |             unsafe {
+   |             ------ because it's nested under this `unsafe` block
+LL |                 v.set_len(24);
 LL |                 |w: &mut Vec<u32>| { unsafe {
    |                                      ^^^^^^ unnecessary `unsafe` block
 
diff --git a/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr b/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr
index 13c080e5b6a..4cdd97e5e06 100644
--- a/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr
+++ b/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr
@@ -76,12 +76,10 @@ LL |     unsafe {}
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:49:14
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:49:5
    |
 LL |     unsafe { unsafe { unsf() } }
-   |     ------   ^^^^^^ unnecessary `unsafe` block
-   |     |
-   |     because it's nested under this `unsafe` block
+   |     ^^^^^^ unnecessary `unsafe` block
 
 error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block
   --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
diff --git a/tests/ui/unsized/unsized-trait-impl-self-type.rs b/tests/ui/unsized/unsized-trait-impl-self-type.rs
index df571a83382..603c0a221ec 100644
--- a/tests/ui/unsized/unsized-trait-impl-self-type.rs
+++ b/tests/ui/unsized/unsized-trait-impl-self-type.rs
@@ -9,6 +9,7 @@ struct S5<Y>(Y);
 
 impl<X: ?Sized> T3<X> for S5<X> {
     //~^ ERROR the size for values of type
+    //~| ERROR not all trait items implemented
 }
 
 fn main() { }
diff --git a/tests/ui/unsized/unsized-trait-impl-self-type.stderr b/tests/ui/unsized/unsized-trait-impl-self-type.stderr
index 4955d463fc2..5bc8dc590ca 100644
--- a/tests/ui/unsized/unsized-trait-impl-self-type.stderr
+++ b/tests/ui/unsized/unsized-trait-impl-self-type.stderr
@@ -24,6 +24,16 @@ LL - impl<X: ?Sized> T3<X> for S5<X> {
 LL + impl<X> T3<X> for S5<X> {
    |
 
-error: aborting due to previous error
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/unsized-trait-impl-self-type.rs:10:1
+   |
+LL |     fn foo(&self, z: &Z);
+   |     --------------------- `foo` from trait
+...
+LL | impl<X: ?Sized> T3<X> for S5<X> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0046, E0277.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/unsized/unsized-trait-impl-trait-arg.rs b/tests/ui/unsized/unsized-trait-impl-trait-arg.rs
index 96e7e371f2a..e7602b175c8 100644
--- a/tests/ui/unsized/unsized-trait-impl-trait-arg.rs
+++ b/tests/ui/unsized/unsized-trait-impl-trait-arg.rs
@@ -7,6 +7,7 @@ trait T2<Z> {
 struct S4<Y: ?Sized>(Box<Y>);
 impl<X: ?Sized> T2<X> for S4<X> {
     //~^ ERROR the size for values of type
+    //~| ERROR not all trait items implemented
 }
 
 fn main() { }
diff --git a/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr b/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr
index 8761c293af4..e9353d2bbd9 100644
--- a/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr
+++ b/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr
@@ -21,6 +21,16 @@ help: consider relaxing the implicit `Sized` restriction
 LL | trait T2<Z: ?Sized> {
    |           ++++++++
 
-error: aborting due to previous error
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/unsized-trait-impl-trait-arg.rs:8:1
+   |
+LL |     fn foo(&self, z: Z);
+   |     -------------------- `foo` from trait
+...
+LL | impl<X: ?Sized> T2<X> for S4<X> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0046, E0277.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/unsized/unsized7.rs b/tests/ui/unsized/unsized7.rs
index 422a784814e..63e015c28d3 100644
--- a/tests/ui/unsized/unsized7.rs
+++ b/tests/ui/unsized/unsized7.rs
@@ -11,6 +11,7 @@ trait T1<Z: T> {
 struct S3<Y: ?Sized>(Box<Y>);
 impl<X: ?Sized + T> T1<X> for S3<X> {
     //~^ ERROR the size for values of type
+    //~| ERROR not all trait items implemented
 }
 
 fn main() { }
diff --git a/tests/ui/unsized/unsized7.stderr b/tests/ui/unsized/unsized7.stderr
index c313a2724c0..2edde159653 100644
--- a/tests/ui/unsized/unsized7.stderr
+++ b/tests/ui/unsized/unsized7.stderr
@@ -21,6 +21,16 @@ help: consider relaxing the implicit `Sized` restriction
 LL | trait T1<Z: T + ?Sized> {
    |               ++++++++
 
-error: aborting due to previous error
+error[E0046]: not all trait items implemented, missing: `dummy`
+  --> $DIR/unsized7.rs:12:1
+   |
+LL |     fn dummy(&self) -> Z;
+   |     --------------------- `dummy` from trait
+...
+LL | impl<X: ?Sized + T> T1<X> for S3<X> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `dummy` in implementation
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0046, E0277.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/wf/hir-wf-check-erase-regions.rs b/tests/ui/wf/hir-wf-check-erase-regions.rs
index 3855f2c35c1..2820d5f6d07 100644
--- a/tests/ui/wf/hir-wf-check-erase-regions.rs
+++ b/tests/ui/wf/hir-wf-check-erase-regions.rs
@@ -5,6 +5,7 @@ pub struct Table<T, const N: usize>([Option<T>; N]);
 
 impl<'a, T, const N: usize> IntoIterator for &'a Table<T, N> {
     type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>; //~ ERROR `&'a T` is not an iterator
+    //~^ ERROR `&'a T` is not an iterator
     type Item = &'a T;
 
     fn into_iter(self) -> Self::IntoIter { //~ ERROR `&'a T` is not an iterator
diff --git a/tests/ui/wf/hir-wf-check-erase-regions.stderr b/tests/ui/wf/hir-wf-check-erase-regions.stderr
index 2843983c716..eb0a8f8f69a 100644
--- a/tests/ui/wf/hir-wf-check-erase-regions.stderr
+++ b/tests/ui/wf/hir-wf-check-erase-regions.stderr
@@ -11,7 +11,7 @@ note: required by a bound in `Flatten`
   --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
 
 error[E0277]: `&'a T` is not an iterator
-  --> $DIR/hir-wf-check-erase-regions.rs:10:27
+  --> $DIR/hir-wf-check-erase-regions.rs:11:27
    |
 LL |     fn into_iter(self) -> Self::IntoIter {
    |                           ^^^^^^^^^^^^^^ `&'a T` is not an iterator
@@ -22,6 +22,18 @@ LL |     fn into_iter(self) -> Self::IntoIter {
 note: required by a bound in `Flatten`
   --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
 
-error: aborting due to 2 previous errors
+error[E0277]: `&'a T` is not an iterator
+  --> $DIR/hir-wf-check-erase-regions.rs:7:21
+   |
+LL |     type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `&'a T`
+   = help: the trait `Iterator` is implemented for `&mut I`
+   = note: required for `Flatten<std::slice::Iter<'a, T>>` to implement `Iterator`
+note: required by a bound in `std::iter::IntoIterator::IntoIter`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/issue-110157.rs b/tests/ui/wf/issue-110157.rs
index 43a8ce72ff1..07e2c5d58c3 100644
--- a/tests/ui/wf/issue-110157.rs
+++ b/tests/ui/wf/issue-110157.rs
@@ -2,6 +2,7 @@ struct NeedsDropTypes<'tcx, F>(std::marker::PhantomData<&'tcx F>);
 
 impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
 //~^ ERROR type annotations needed
+//~| ERROR not all trait items implemented
 where
     F: Fn(&Missing) -> Result<I, ()>,
     //~^ ERROR cannot find type `Missing` in this scope
diff --git a/tests/ui/wf/issue-110157.stderr b/tests/ui/wf/issue-110157.stderr
index 91d801e9470..16bd34a6d8e 100644
--- a/tests/ui/wf/issue-110157.stderr
+++ b/tests/ui/wf/issue-110157.stderr
@@ -1,11 +1,11 @@
 error[E0412]: cannot find type `Missing` in this scope
-  --> $DIR/issue-110157.rs:6:12
+  --> $DIR/issue-110157.rs:7:12
    |
 LL |     F: Fn(&Missing) -> Result<I, ()>,
    |            ^^^^^^^ not found in this scope
 
 error[E0412]: cannot find type `Missing` in this scope
-  --> $DIR/issue-110157.rs:8:24
+  --> $DIR/issue-110157.rs:9:24
    |
 LL |     I: Iterator<Item = Missing>,
    |                        ^^^^^^^ not found in this scope
@@ -26,7 +26,22 @@ LL | impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
 LL |     I: Iterator<Item = Missing>,
    |        ------------------------ unsatisfied trait bound introduced here
 
-error: aborting due to 3 previous errors
+error[E0046]: not all trait items implemented, missing: `Item`, `next`
+  --> $DIR/issue-110157.rs:3:1
+   |
+LL | / impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
+LL | |
+LL | |
+LL | | where
+LL | |     F: Fn(&Missing) -> Result<I, ()>,
+LL | |
+LL | |     I: Iterator<Item = Missing>,
+   | |________________________________^ missing `Item`, `next` in implementation
+   |
+   = help: implement the missing item: `type Item = /* Type */;`
+   = help: implement the missing item: `fn next(&mut self) -> Option<<Self as Iterator>::Item> { todo!() }`
+
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0283, E0412.
-For more information about an error, try `rustc --explain E0283`.
+Some errors have detailed explanations: E0046, E0283, E0412.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/wf/wf-const-type.rs b/tests/ui/wf/wf-const-type.rs
index df79aa26712..64b0d9c8de7 100644
--- a/tests/ui/wf/wf-const-type.rs
+++ b/tests/ui/wf/wf-const-type.rs
@@ -9,6 +9,7 @@ struct NotCopy;
 
 const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
 //~^ ERROR E0277
+//~| ERROR E0277
 
 
 fn main() { }
diff --git a/tests/ui/wf/wf-const-type.stderr b/tests/ui/wf/wf-const-type.stderr
index 617969720a6..039e907705e 100644
--- a/tests/ui/wf/wf-const-type.stderr
+++ b/tests/ui/wf/wf-const-type.stderr
@@ -16,6 +16,24 @@ LL + #[derive(Copy)]
 LL | struct NotCopy;
    |
 
-error: aborting due to previous error
+error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
+  --> $DIR/wf-const-type.rs:10:50
+   |
+LL | const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
+   |                                                  ^^^^ the trait `Copy` is not implemented for `NotCopy`
+   |
+   = note: required for `Option<NotCopy>` to implement `Copy`
+note: required by a bound in `IsCopy`
+  --> $DIR/wf-const-type.rs:7:17
+   |
+LL | struct IsCopy<T:Copy> { t: T }
+   |                 ^^^^ required by this bound in `IsCopy`
+help: consider annotating `NotCopy` with `#[derive(Copy)]`
+   |
+LL + #[derive(Copy)]
+LL | struct NotCopy;
+   |
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/wf-static-type.rs b/tests/ui/wf/wf-static-type.rs
index 1c35e1daf44..f454fe30e77 100644
--- a/tests/ui/wf/wf-static-type.rs
+++ b/tests/ui/wf/wf-static-type.rs
@@ -9,6 +9,7 @@ struct NotCopy;
 
 static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
 //~^ ERROR E0277
+//~| ERROR E0277
 
 
 fn main() { }
diff --git a/tests/ui/wf/wf-static-type.stderr b/tests/ui/wf/wf-static-type.stderr
index bb5a57834eb..65dae260143 100644
--- a/tests/ui/wf/wf-static-type.stderr
+++ b/tests/ui/wf/wf-static-type.stderr
@@ -16,6 +16,24 @@ LL + #[derive(Copy)]
 LL | struct NotCopy;
    |
 
-error: aborting due to previous error
+error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
+  --> $DIR/wf-static-type.rs:10:51
+   |
+LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
+   |                                                   ^^^^ the trait `Copy` is not implemented for `NotCopy`
+   |
+   = note: required for `Option<NotCopy>` to implement `Copy`
+note: required by a bound in `IsCopy`
+  --> $DIR/wf-static-type.rs:7:17
+   |
+LL | struct IsCopy<T:Copy> { t: T }
+   |                 ^^^^ required by this bound in `IsCopy`
+help: consider annotating `NotCopy` with `#[derive(Copy)]`
+   |
+LL + #[derive(Copy)]
+LL | struct NotCopy;
+   |
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.